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); +} | 
 
    