c++ - 将原始 PCM 转换为 FLAC?

标签 c++ c audio pcm flac

编辑:我已经更新了下面的代码以类似于我取得的进展。我正在尝试自己编写 .wav header 。截至目前,代码无法正常工作,音频未正确写入文件。该代码不包含任何将其转换为 .flac 文件的尝试。


我正在使用 Raspberry Pi ( Debian Linux ) 通过 ALSA library 录制音频.录音工作正常,但我需要将输入音频编码为 FLAC 编解码器。

这是我迷路的地方。我花了相当多的时间试图弄清楚如何将这些原始数据转换成 FLAC ,但我一直在想出如何将 .wav 文件转换为 .flac 文件的示例。

这是我使用 ALSA 录制音频的当前(更新)代码(它可能有点粗糙,我仍在使用 C++):

// Use the newer ALSA API
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Riff
{
  char chunkId[4]; // "RIFF" (assuming char is 8 bits)
  int chunkSize; // (assuming int is 32 bits)
  char format[4]; // "WAVE"
};

struct Format
{
  char chunkId[4]; // "fmt "
  int chunkSize;
  short format; // assuming short is 16 bits
  short numChannels;
  int sampleRate;
  int byteRate;
  short align;
  short bitsPerSample;
};

struct Data
{
  char chunkId[4]; // "data"
  int chunkSize; // length of data
  char* data;
};

struct Wave // Actual structure of a PCM WAVE file
{
  Riff riffHeader;
  Format formatHeader;
  Data dataHeader;
};

int main(int argc, char *argv[])
{
        void saveWaveFile(struct Wave *waveFile);

        long loops;
        int rc;
        int size;
        snd_pcm_t *handle;
        snd_pcm_hw_params_t *params;
        unsigned int sampleRate = 44100;
        int dir;
        snd_pcm_uframes_t frames;
        char *buffer;
        char *device = (char*) "plughw:1,0";
        //char *device = (char*) "default";

        printf("Capture device is %s\n", device);
        /* Open PCM device for recording (capture). */
        rc = snd_pcm_open(&handle, device, SND_PCM_STREAM_CAPTURE, 0);
        if (rc < 0)
        {
                fprintf(stderr, "Unable to open PCM device: %s\n", snd_strerror(rc));
                exit(1);
        }

        /* Allocate a hardware parameters object. */
        snd_pcm_hw_params_alloca(&params);

        /* Fill it in with default values. */
        snd_pcm_hw_params_any(handle, params);

        /* Set the desired hardware parameters. */

        /* Interleaved mode */
        snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

        /* Signed 16-bit little-endian format */
        snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);

        /* Two channels (stereo) */
        snd_pcm_hw_params_set_channels(handle, params, 2);

        /* 44100 bits/second sampling rate (CD quality) */
        snd_pcm_hw_params_set_rate_near(handle, params, &sampleRate, &dir);

        /* Set period size to 32 frames. */
        frames = 32;
        snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

        /* Write the parameters to the driver */
        rc = snd_pcm_hw_params(handle, params);
        if (rc < 0)
        {
                fprintf(stderr, "Unable to set HW parameters: %s\n", snd_strerror(rc));
                exit(1);
        }

        /* Use a buffer large enough to hold one period */
        snd_pcm_hw_params_get_period_size(params, &frames, &dir);
        size = frames * 4; /* 2 bytes/sample, 2 channels */
        buffer = (char *) malloc(size);

        /* We want to loop for 5 seconds */
        snd_pcm_hw_params_get_period_time(params, &sampleRate, &dir);
        loops = 5000000 / sampleRate;

        while (loops > 0)
        {
                loops--;
                rc = snd_pcm_readi(handle, buffer, frames);
                if (rc == -EPIPE)
                {
                        /* EPIPE means overrun */
                        fprintf(stderr, "Overrun occurred.\n");
                        snd_pcm_prepare(handle);
                } else if (rc < 0)
                {
                        fprintf(stderr, "Error from read: %s\n", snd_strerror(rc));
                } else if (rc != (int)frames)
                {
                        fprintf(stderr, "Short read, read %d frames.\n", rc);
                }
                if (rc != size) fprintf(stderr, "Short write: wrote %d bytes.\n", rc);
        }

        Wave wave;

        strcpy(wave.riffHeader.chunkId, "RIFF");
        wave.riffHeader.chunkSize = 36 + size;
        strcpy(wave.riffHeader.format, "WAVE");

        strcpy(wave.formatHeader.chunkId, "fmt");
        wave.formatHeader.chunkSize = 16;
        wave.formatHeader.format = 1; // PCM, other value indicates compression
        wave.formatHeader.numChannels = 2; // Stereo
        wave.formatHeader.sampleRate = sampleRate;
        wave.formatHeader.byteRate = sampleRate * 2 * 2;
        wave.formatHeader.align = 2 * 2;
        wave.formatHeader.bitsPerSample = 16;

        strcpy(wave.dataHeader.chunkId, "data");
        wave.dataHeader.chunkSize = size;
        wave.dataHeader.data = buffer;

        saveWaveFile(&wave);

        snd_pcm_drain(handle);
        snd_pcm_close(handle);
        free(buffer);

        return 0;
}

void saveWaveFile(struct Wave *waveFile)
{
        FILE *file = fopen("test.wav", "wb");
        size_t written;

        if (file == NULL)
        {
                fprintf(stderr, "Cannot open file for writing.\n");
                exit(1);
        }

        written = fwrite(waveFile, sizeof waveFile[0], 1, file);
        fclose(file);

        if (written < 1);
        {
                fprintf(stderr, "Writing to file failed, error %d.\n", written);
                exit(1);
        }
}

我如何将 PCM 数据转换为 FLAC 并将其保存到磁盘以备后用?我已经下载了 libflac-dev,只需要一个示例即可。


我现在的做法是:

./capture > test.raw     // or   ./capture > test.flac

它应该是这样的(程序为我做了一切):

./capture

最佳答案

如果我理解FLAC::Encoder::File文档,你可以做类似的事情

#include <FLAC++/encoder.h>

FLAC::Encoder::File encoder;
encoder.init("outfile.flac");
encoder.process(buffer, samples);
encoder.finish();

其中 buffer 是 32 位整数指针的数组(大小为 samples)。

不幸的是,我对音频编码几乎一无所知,所以我不能说任何其他选择。祝你好运!

关于c++ - 将原始 PCM 转换为 FLAC?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17139974/

相关文章:

c - 如何搜索、查找和打印用户给出的单词的索引?

c - 用 C 语言制作问答游戏

c - 如何使用 htonl 将小端转换为大端

javascript - 分析器条动画 HTML 音频 API 不起作用

html - 在HTML背景中具有MP3\WAV

c++ - SQLITE 内存不足无法执行语句

c++ - 在 Qt QML 中为许多文本元素指定字体

c++ - 为什么在引用计数器上需要存储顺序限制?

C++ #include 和 operator<< 重载错误

android - MediaPlayer滞后于手机锁