EDIT: I updated the code below to resemble the progress I made. I am trying to write a .wav header. At the moment, the code is not working properly, the sound is not written to the file properly. The code does not contain any attempts to convert it to a .flac file.
I use Raspberry Pi ( Debian Linux ) to record sound using ALSA Library . Recording works fine, but I need to encode the input sound in the FLAC codec.
This is where I got lost. I spent a lot of time trying to figure out how to convert this raw data to FLAC , but I keep coming up with examples of how to convert .wav files to .flac files.
Here is the current ( updated ) code that I have for recording sound using ALSA (this can be a little rude, I'm still typing 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(¶ms); /* 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); } }
How do I go about converting PCM data to FLAC and save it to disk for later use? I already downloaded libflac-dev and just need an example to get away.
How am I doing this right now:
./capture > test.raw // or ./capture > test.flac
How it should be (the program does everything for me):
./capture