#include #include #include #include #include #include #include #include #include #include #include #define SYNTH_STATUS_CLEAR 0 #define SYNTH_STATUS_ON (1 << 0) typedef struct _synth_sine { int flags; float phase; size_t frequency; } synth_sine; static void usage(int argc, char **argv, const char *message, ...) { va_list args; va_start(args, message); if (message) { vfprintf(stderr, message, args); fputc('\n', stderr); } va_end(args); fprintf(stderr, "usage: %s output.wav\n", argv[0]); exit(EX_USAGE); } static int16_t sine_sample(xas_synth *synth, synth_sine *sine) { int16_t ret; static float tau = 2.0f * M_PI; if (sine->flags & SYNTH_STATUS_ON) { ret = (int16_t)roundf((INT16_MAX >> 2) * sinf(sine->phase)); sine->phase += tau / (synth->sample_rate / sine->frequency); if (sine->phase > tau) { sine->phase -= tau; } } else { ret = 0; } return ret; } static void sine_cleanup(xas_synth *synth, synth_sine *sine) { return; } int main(int argc, char **argv) { xas_mixer *mixer; xas_audio_stream *synth_l, *synth_r, *wave; synth_sine sine_channels[2] = { { SYNTH_STATUS_ON, 0.0f, 220 }, { SYNTH_STATUS_ON, 0.0f, 420 }, }; size_t sample_rate = 44100, duration_s = 60, i; if (argc != 2) { usage(argc, argv, "No output file provided"); } if ((wave = xas_riff_file_new(argv[1], XAS_AUDIO_STREAM_PCM_16_BIT, sample_rate, XAS_AUDIO_STREAM_STEREO, O_WRONLY | O_CREAT | O_TRUNC)) == NULL) { goto error_riff_file_new; } if ((synth_l = xas_synth_new(XAS_AUDIO_STREAM_PCM_16_BIT, sample_rate, sample_rate, (xas_synth_callback_sample)sine_sample, (xas_synth_callback_cleanup)sine_cleanup, &sine_channels[0])) == NULL) { goto error_synth_new_l; } if ((synth_r = xas_synth_new(XAS_AUDIO_STREAM_PCM_16_BIT, sample_rate, sample_rate, (xas_synth_callback_sample)sine_sample, (xas_synth_callback_cleanup)sine_cleanup, &sine_channels[1])) == NULL) { goto error_synth_new_r; } if ((mixer = xas_mixer_new(XAS_AUDIO_STREAM_PCM_16_BIT, sample_rate, XAS_AUDIO_STREAM_STEREO, sample_rate)) == NULL) { goto error_mixer_new; } if (xas_mixer_input_add(mixer, synth_l, 0.3, -1.0) == NULL) { goto error_mixer_input_add; } if (xas_mixer_input_add(mixer, synth_r, 0.3, 1.0) == NULL) { goto error_mixer_input_add; } for (i=0; ioutput, &buf, sample_rate)) < 0) { goto error_audio_stream_read; } if (xas_audio_stream_write(wave, buf, readlen) < 0) { goto error_audio_stream_write; } } xas_audio_stream_flush(wave); xas_mixer_destroy(mixer); xas_audio_stream_destroy(synth_r); xas_audio_stream_destroy(synth_l); xas_audio_stream_destroy(wave); return EX_OK; error_audio_stream_write: error_audio_stream_read: error_mixer_input_add: xas_mixer_destroy(mixer); error_mixer_new: xas_audio_stream_destroy(synth_r); error_synth_new_r: xas_audio_stream_destroy(synth_l); error_synth_new_l: xas_audio_stream_destroy(wave); error_riff_file_new: return EX_OSERR; }