As an ongoing little side project of mine, I've been working on recording audio in c. You can the code's progression by looking at past versions (V1.0, V2.0).
I've found that my past versions were too limited. They required a certain time frame for which they would record, and then stop. This isn't very practical for many real-world applications, so I rewrote everything so the computer would always be listening, and only record necessary data.
Here is what I would like reviewed:
Memory consumption: Obviously a huge potential problem is lots of space being consumed in recording and saving the audio to file. Am I wasting space at all? Every little bit counts. Note: file storage container must be FLAC.
Speed: I have to be processing the data in real time. I can't hang for anything or I might lose precious audio data. Is there anywhere I could speed up processing?
Syntax/Styling: How does my code look? What about it could make it look better? Anything I'm doing wrong syntax-wise?
Feel free to review other stuff as well, I would just like reviews to be focused on the above. Keep in mind I've been away from the C language for a bit now, so I may have forgotten some of the more simple things ;)
main.c:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <portaudio.h>
#include <sndfile.h>
#define FRAMES_PER_BUFFER 1024
typedef struct
{
uint16_t formatType;
uint8_t numberOfChannels;
uint32_t sampleRate;
size_t size;
float *recordedSamples;
} AudioData;
typedef struct
{
float *snippet;
size_t size;
} AudioSnippet;
AudioData initAudioData(uint32_t sampleRate, uint16_t channels, int type)
{
AudioData data;
data.formatType = type;
data.numberOfChannels = channels;
data.sampleRate = sampleRate;
data.size = 0;
data.recordedSamples = NULL;
return data;
}
float avg(float *data, size_t length)
{
float sum = 0;
for (size_t i = 0; i < length; i++)
{
sum += fabs(*(data + i));
}
return (float) sum / length;
}
long storeFLAC(AudioData *data, const char *fileName)
{
uint8_t err = SF_ERR_NO_ERROR;
SF_INFO sfinfo =
{
.channels = data->numberOfChannels,
.samplerate = data->sampleRate,
.format = SF_FORMAT_FLAC | SF_FORMAT_PCM_16
};
SNDFILE *outfile = sf_open(fileName, SFM_WRITE, &sfinfo);
if (!outfile) return -1;
// Write the entire buffer to the file
long wr = sf_writef_float(outfile, data->recordedSamples, data->size / sizeof(float));
err = data->size - wr;
// Force write to disk and close file
sf_write_sync(outfile);
sf_close(outfile);
puts("Wrote to file!!!!");
return err;
}
int main(void)
{
PaError err = paNoError;
if((err = Pa_Initialize())) goto done;
const PaDeviceInfo *info = Pa_GetDeviceInfo(Pa_GetDefaultInputDevice());
AudioData data = initAudioData(44100, info->maxInputChannels, paFloat32);
AudioSnippet sampleBlock =
{
.snippet = NULL,
.size = FRAMES_PER_BUFFER * sizeof(float) * data.numberOfChannels
};
PaStream *stream = NULL;
sampleBlock.snippet = malloc(sampleBlock.size);
time_t talking = 0;
time_t silence = 0;
PaStreamParameters inputParameters =
{
.device = Pa_GetDefaultInputDevice(),
.channelCount = data.numberOfChannels,
.sampleFormat = data.formatType,
.suggestedLatency = info->defaultHighInputLatency,
.hostApiSpecificStreamInfo = NULL
};
if((err = Pa_OpenStream(&stream, &inputParameters, NULL, data.sampleRate, FRAMES_PER_BUFFER, paClipOff, NULL, NULL))) goto done;
if((err = Pa_StartStream(stream))) goto done;
for(int i = 0;;)
{
err = Pa_ReadStream(stream, sampleBlock.snippet, FRAMES_PER_BUFFER);
if (err) goto done;
else if(avg(sampleBlock.snippet, FRAMES_PER_BUFFER) > 0.000550) // talking
{
printf("You're talking! %d\n", i);
i++;
time(&talking);
data.recordedSamples = realloc(data.recordedSamples, sampleBlock.size * i);
data.size = sampleBlock.size * i;
if (data.recordedSamples) memcpy((char*)data.recordedSamples + ((i - 1) * sampleBlock.size), sampleBlock.snippet, sampleBlock.size);
else
{
free(data.recordedSamples);
data.recordedSamples = NULL;
data.size = 0;
}
}
else //silence
{
double test = difftime(time(&silence), talking);
if (test >= 1.5 && test <= 10)
{
char buffer[100];
snprintf(buffer, 100, "file:%d.flac", i);
storeFLAC(&data, buffer);
talking = 0;
free(data.recordedSamples);
data.recordedSamples = NULL;
data.size = 0;
}
}
}
done:
free(sampleBlock.snippet);
Pa_Terminate();
return err;
}
Compile with: gcc main.c -lsndfile -lportaudio
(assuming you have those libraries installed)