diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/synth.c | 154 |
1 files changed, 128 insertions, 26 deletions
diff --git a/src/synth.c b/src/synth.c index d96c1b5..082a383 100644 --- a/src/synth.c +++ b/src/synth.c @@ -1,7 +1,89 @@ #include <stdlib.h> +#include <math.h> +#include <errno.h> #include <xas/synth.h> +static int16_t sample_sine(xas_synth *synth) { + int16_t ret; + static float tau = 2.0f * M_PI; + + if (synth->state == XAS_SYNTH_ACTIVE) { + ret = (int16_t)roundf((INT16_MAX >> 2) * sinf(synth->phase)); + + synth->phase += tau / (synth->format.sample_rate / synth->frequency); + + if (synth->phase > tau) { + synth->phase -= tau; + } + } else { + ret = 0; + } + + return ret; +} + +static int16_t sample_square(xas_synth *synth) { + int16_t ret; + static float tau = 2.0f * M_PI; + + if (synth->state == XAS_SYNTH_ACTIVE) { + ret = synth->phase > 0.0? INT16_MAX / 4: INT16_MIN / 4; + + synth->phase += tau / (synth->format.sample_rate / synth->frequency); + + if (synth->phase > tau) { + synth->phase -= tau; + } + } else { + ret = 0; + } + + return ret; +} + +static int16_t sample_triangle(xas_synth *synth) { + int16_t ret; + static float tau = 2.0f * M_PI; + + if (synth->state == XAS_SYNTH_ACTIVE) { + float v = 2.0f * fabs(2.0f * fabs(synth->phase - floorf(synth->phase + 0.5))) - 1.0f; + + ret = (int16_t)roundf((INT16_MAX >> 2) * v); + + synth->phase += tau / (synth->format.sample_rate / synth->frequency); + + if (synth->phase > tau) { + synth->phase -= tau; + } + } else { + ret = 0; + } + + return ret; +} + +static int16_t sample_sawtooth(xas_synth *synth) { + int16_t ret; + static float tau = 2.0f * M_PI; + + if (synth->state == XAS_SYNTH_ACTIVE) { + float v = 2.0f * (synth->phase / tau - 0.5f); + + ret = (int16_t)roundf((INT16_MAX >> 2) * v); + + synth->phase += tau / (synth->format.sample_rate / synth->frequency); + + if (synth->phase > tau) { + synth->phase -= tau; + } + } else { + ret = 0; + } + + return ret; +} + static ssize_t synth_fill(xas_synth *synth, int16_t *samples, size_t count, @@ -9,53 +91,73 @@ static ssize_t synth_fill(xas_synth *synth, size_t i; for (i=0; i<count; i++) { - samples[i] = synth->sample(synth, synth->ctx); + samples[i] = synth->sample(synth); } return count; } -static void synth_cleanup(xas_synth *synth, xas_audio_stream *stream) { - if (synth->cleanup) { - synth->cleanup(synth, synth->ctx); - } - - free(synth); -} - -xas_audio_stream *xas_synth_new(xas_synth_callback_sample sample, - xas_synth_callback_cleanup cleanup, - xas_audio_format format, - size_t buffer_size, - void *ctx) { - xas_audio_stream *stream; +xas_synth *xas_synth_new(xas_audio_format format, + size_t buffer_size, + enum xas_synth_type type) { xas_synth *synth; if ((synth = malloc(sizeof(*synth))) == NULL) { goto error_malloc_synth; } + synth->type = type; + synth->state = XAS_SYNTH_IDLE; + synth->phase = 0.0f; + synth->frequency = XAS_SYNTH_DEFAULT_FREQUENCY; + synth->format.channels = XAS_AUDIO_MONO; synth->format.sample_size = format.sample_size; synth->format.sample_rate = format.sample_rate; + synth->buffer_size = buffer_size; - synth->sample = sample; - synth->cleanup = cleanup; - synth->ctx = ctx; + switch (type) { + case XAS_SYNTH_SINE: synth->sample = sample_sine; break; + case XAS_SYNTH_SQUARE: synth->sample = sample_square; break; + case XAS_SYNTH_TRIANGLE: synth->sample = sample_triangle; break; + case XAS_SYNTH_SAWTOOTH: synth->sample = sample_sawtooth; break; - if ((stream = xas_audio_stream_new_source((xas_audio_fill)synth_fill, - (xas_audio_cleanup)synth_cleanup, - synth->format, - buffer_size, - synth)) == NULL) { - goto error_audio_stream_new_source; + default: + errno = EINVAL; + + goto error_invalid_type; } - return stream; + return synth; -error_audio_stream_new_source: +error_invalid_type: free(synth); error_malloc_synth: return NULL; } + +void xas_synth_destroy(xas_synth *synth) { + free(synth); +} + +void xas_synth_set_frequency(xas_synth *synth, size_t frequency) { + synth->frequency = frequency; +} + +void xas_synth_start(xas_synth *synth) { + synth->state = XAS_SYNTH_ACTIVE; +} + +void xas_synth_stop(xas_synth *synth) { + synth->state = XAS_SYNTH_IDLE; + synth->phase = 0.0f; +} + +xas_audio_stream *xas_synth_new_stream(xas_synth *synth) { + return xas_audio_stream_new_source((xas_audio_fill)synth_fill, + NULL, + synth->format, + synth->buffer_size, + synth); +} |