Skip to content

Instantly share code, notes, and snippets.

@yne
Created June 9, 2016 21:04
Show Gist options
  • Save yne/e4adf578a14953c4547d078406d575d4 to your computer and use it in GitHub Desktop.
Save yne/e4adf578a14953c4547d078406d575d4 to your computer and use it in GitHub Desktop.
Play argv wavs using ALSA
#include <alloca.h> /*needed (yet not included) by asoundlib in c99*/
#include <alsa/asoundlib.h>/* build with -lasound */
#include <stdint.h>
#define $(x) if ((x) < 0) { fprintf(stderr, "Error:%s", # x); return -1; }
#define MIN(A, B) ((A) < (B) ? (A) : (B))
typedef struct {
char RIFF[4];
uint32_t ChunkSize;
char WAVE[4];
char fmt[4];
uint32_t Subchunk1Size;
int16_t AudioFormat;
int16_t NumOfChannels;
uint32_t SamplesPerSec;
uint32_t bytesPerSec;
int16_t blockAlign;
int16_t bitsPerSample;
char Subchunk2ID[4];
uint32_t Subchunk2Size;
char data[1];
} wavHeader;
typedef struct {
void* data;
wavHeader*wav_hdr;
size_t wav_size;
char* wav_data;
}sound_file_t;
sound_file_t wavs[256];
size_t wavs_loaded = 0;
void load_wavs(char** paths, size_t total)
{
for (int i = 0; i < total; i++) {
sound_file_t*wav = &wavs[wavs_loaded];
FILE *file = fopen(paths[i], "rb");
if (file == NULL)
continue;
fseek(file, 0, SEEK_END);
wav->wav_size = ftell(file);
fseek(file, 0, SEEK_SET);
wav->data = malloc(wav->wav_size);
if (wav->data != NULL) {
fread(wav->data, 1, wav->wav_size, file);
wav->wav_hdr = wav->data;
wav->wav_data = ((char*)wav->data) + sizeof(wavHeader) + wav->wav_hdr->Subchunk2Size;
wav->wav_size = wav->wav_size + sizeof(wavHeader) + wav->wav_hdr->Subchunk2Size;
wavs_loaded++;
}
fclose(file);
}
}
void unload_wavs()
{
for (int i = 0; i < wavs_loaded; i++)
free(wavs[i].data);
}
int main(int argc, char**argv)
{
int i;
load_wavs(argv + 1, argc - 1);
snd_pcm_t *handle;
$(snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0));
snd_pcm_hw_params_t *params;
snd_pcm_hw_params_alloca(&params);
snd_pcm_hw_params_any(handle, params);
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
snd_pcm_hw_params_set_channels(handle, params, wavs[0].wav_hdr->NumOfChannels);
snd_pcm_hw_params_set_rate_near(handle, params, &wavs[0].wav_hdr->SamplesPerSec, &i);
$(snd_pcm_hw_params(handle, params));
// snd_pcm_prepare(handle);
for (int wav = 0; wav < wavs_loaded; wav) {
char*wav_data = wavs[wav].wav_data;
snd_pcm_uframes_t frames_size = wavs[wav].wav_hdr->NumOfChannels * sizeof(uint16_t);
int frames_remain = wavs[wav].wav_size / frames_size;
unsigned frames_step = 1024;
while (frames_remain > 0) {
snd_pcm_writei(handle, wav_data, MIN(frames_remain, frames_step));
frames_remain -= frames_step;
wav_data += frames_step * frames_size;
}
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
unload_wavs();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment