diff options
| -rw-r--r-- | examples/say.c | 82 | ||||
| -rw-r--r-- | examples/spatial.c | 50 | ||||
| -rw-r--r-- | examples/test.c | 73 | ||||
| -rw-r--r-- | include/xas/synth.h | 48 | ||||
| -rw-r--r-- | src/synth.c | 154 | 
5 files changed, 247 insertions, 160 deletions
| diff --git a/examples/say.c b/examples/say.c index 92856f2..fa16242 100644 --- a/examples/say.c +++ b/examples/say.c @@ -40,41 +40,15 @@ static void usage(int argc, char **argv, const char *message, ...) {      exit(EX_USAGE);  } -static int16_t sine_sample(xas_synth *synth, synth_sine *sine) { -    static float tau = 2.0f * M_PI; - -    int16_t ret; - -    if (sine->flags & SYNTH_STATUS_ON) { -        ret = (int16_t)roundf((INT16_MAX >> 2) * sinf(sine->phase)); - -        sine->phase += tau / (synth->format.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) { -    synth_sine sine_channels[2] = { -        { SYNTH_STATUS_ON, 0.0f, 220 }, -        { SYNTH_STATUS_ON, 0.0f, 420 }, -    }; -      xas_mixer *mixer;      xas_bank *bank;      xas_vox *vox; +    xas_synth *sine_l, +                *sine_r; +      xas_bank_player *player;      xas_audio_stream *voice, @@ -97,6 +71,18 @@ int main(int argc, char **argv) {          usage(argc, argv, "No output file provided");      } +    if ((sine_l = xas_synth_new(format, +                                  buffer_size, +                                  XAS_SYNTH_SINE)) == NULL) { +        goto error_synth_new_l; +    } + +    if ((sine_r = xas_synth_new(format, +                                  buffer_size, +                                  XAS_SYNTH_SINE)) == NULL) { +        goto error_synth_new_r; +    } +      if ((vox = xas_vox_new(format,                               buffer_size,                               "/usr/bin/text2wave")) == NULL) { @@ -125,20 +111,12 @@ int main(int argc, char **argv) {          goto error_bank_player_stream_new;      } -    if ((synth_l = xas_synth_new((xas_synth_callback_sample)sine_sample, -                                   (xas_synth_callback_cleanup)sine_cleanup, -                                   format, -                                   buffer_size, -                                   &sine_channels[0])) == NULL) { -        goto error_synth_new_l; +    if ((synth_l = xas_synth_new_stream(sine_l)) == NULL) { +        goto error_synth_new_stream_l;      } -    if ((synth_r = xas_synth_new((xas_synth_callback_sample)sine_sample, -                                   (xas_synth_callback_cleanup)sine_cleanup, -                                   format, -                                   buffer_size, -                                   &sine_channels[1])) == NULL) { -        goto error_synth_new_r; +    if ((synth_r = xas_synth_new_stream(sine_r)) == NULL) { +        goto error_synth_new_stream_r;      }      if ((mixer = xas_mixer_new(format, buffer_size)) == NULL) { @@ -157,10 +135,18 @@ int main(int argc, char **argv) {          goto error_mixer_input_add;      } +    xas_synth_set_frequency(sine_l, 220); +    xas_synth_start(sine_l); + +    xas_synth_set_frequency(sine_l, 420); +    xas_synth_start(sine_r); +      /*       * Time to fill the sample bank, meow!       */ -    xas_vox_say(vox, "I want to eat your soul.  You don't understand.  I really want to eat your soul.\n"); +    xas_vox_say(vox, "I want to eat your soul."); +    xas_vox_say(vox, "You don't understand."); +    xas_vox_say(vox, "I really want to eat your soul.");      xas_vox_generate(vox); @@ -192,6 +178,8 @@ int main(int argc, char **argv) {      xas_mixer_destroy(mixer);      xas_audio_stream_destroy(synth_r);      xas_audio_stream_destroy(synth_l); +    xas_synth_destroy(sine_r); +    xas_synth_destroy(sine_l);      xas_audio_stream_destroy(player_stream);      xas_audio_stream_destroy(voice);      xas_audio_stream_destroy(output); @@ -210,10 +198,10 @@ error_mixer_input_add:  error_mixer_new:      xas_audio_stream_destroy(synth_r); -error_synth_new_r: +error_synth_new_stream_r:      xas_audio_stream_destroy(synth_l); -error_synth_new_l: +error_synth_new_stream_l:      xas_audio_stream_destroy(player_stream);  error_bank_player_stream_new: @@ -232,5 +220,11 @@ error_bank_new:      xas_vox_destroy(vox);  error_vox_new: +    xas_synth_destroy(sine_r); + +error_synth_new_r: +    xas_synth_destroy(sine_l); + +error_synth_new_l:      return EX_OSERR;  } diff --git a/examples/spatial.c b/examples/spatial.c index ec606d6..c5c658c 100644 --- a/examples/spatial.c +++ b/examples/spatial.c @@ -39,32 +39,11 @@ static void usage(int argc, char **argv, const char *message, ...) {      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->format.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_spatial_scene *scene; +    xas_synth *sine; +      xas_audio_stream *synth,                         *voice,                         *output, @@ -72,11 +51,6 @@ int main(int argc, char **argv) {      xas_vox *vox; -    synth_sine sine_channels[2] = { -        { SYNTH_STATUS_ON, 0.0f, 2600 }, -        { SYNTH_STATUS_ON, 0.0f,  420 }, -    }; -      xas_audio_format format = {          .channels    = XAS_AUDIO_STEREO,          .sample_size = XAS_AUDIO_PCM_16_BIT, @@ -102,14 +76,16 @@ int main(int argc, char **argv) {          goto error_riff_new_file;      } -    if ((synth = xas_synth_new((xas_synth_callback_sample)sine_sample, -                                 (xas_synth_callback_cleanup)sine_cleanup, -                                 format, -                                 buffer_size, -                                 &sine_channels[0])) == NULL) { +    if ((sine = xas_synth_new(format, +                                buffer_size, +                                XAS_SYNTH_SINE)) == NULL) {          goto error_synth_new;      } +    if ((synth = xas_synth_new_stream(sine)) == NULL) { +        goto error_synth_new_stream; +    } +      if ((vox = xas_vox_new(format,                               buffer_size,                               "/usr/bin/text2wave")) == NULL) { @@ -136,7 +112,7 @@ int main(int argc, char **argv) {      if (xas_spatial_scene_add_object(scene,                                         (xas_spatial_coord){ 5.2, 0.0, 0.0 },                                         synth, -                                       &sine_channels[0]) == NULL) { +                                       sine) == NULL) {          goto error_spatial_scene_add_object;      } @@ -147,6 +123,9 @@ int main(int argc, char **argv) {          goto error_spatial_scene_add_object;      } +    xas_synth_set_frequency(sine, 320); +    xas_synth_start(sine); +      xas_vox_sayf(vox, "I want to eat your soul.\n");      xas_vox_sayf(vox, "You don't understand.\n");      xas_vox_sayf(vox, "I really want to eat your soul.\n"); @@ -196,6 +175,9 @@ error_vox_stream_new:  error_vox_new:      xas_audio_stream_destroy(synth); +error_synth_new_stream: +    xas_synth_destroy(sine); +  error_synth_new:      xas_audio_stream_destroy(wave); diff --git a/examples/test.c b/examples/test.c index 1fbd8c4..272e32d 100644 --- a/examples/test.c +++ b/examples/test.c @@ -11,16 +11,6 @@  #include <xas/mixer.h>  #include <xas/riff.h> -#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; @@ -38,29 +28,6 @@ static void usage(int argc, char **argv, const char *message, ...) {      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->format.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; @@ -68,10 +35,8 @@ int main(int argc, char **argv) {                         *synth_r,                         *wave; -    synth_sine sine_channels[2] = { -        { SYNTH_STATUS_ON, 0.0f, 220 }, -        { SYNTH_STATUS_ON, 0.0f, 420 }, -    }; +    xas_synth *sine_l, +                *sine_r;      xas_audio_format format = {          .channels    = XAS_AUDIO_STEREO, @@ -93,22 +58,26 @@ int main(int argc, char **argv) {          goto error_riff_new_file;      } -    if ((synth_l = xas_synth_new((xas_synth_callback_sample)sine_sample, -                                   (xas_synth_callback_cleanup)sine_cleanup, -                                   format, +    if ((sine_l = xas_synth_new(format,                                     buffer_size, -                                   &sine_channels[0])) == NULL) { +                                   XAS_SYNTH_SINE)) == NULL) {          goto error_synth_new_l;      } -    if ((synth_r = xas_synth_new((xas_synth_callback_sample)sine_sample, -                                   (xas_synth_callback_cleanup)sine_cleanup, -                                   format, +    if ((synth_l = xas_synth_new_stream(sine_l)) == NULL) { +        goto error_synth_new_stream_l; +    } + +    if ((sine_r = xas_synth_new(format,                                     buffer_size, -                                   &sine_channels[1])) == NULL) { +                                   XAS_SYNTH_SINE)) == NULL) {          goto error_synth_new_r;      } +    if ((synth_r = xas_synth_new_stream(sine_r)) == NULL) { +        goto error_synth_new_stream_r; +    } +      if ((mixer = xas_mixer_new(format, buffer_size)) == NULL) {          goto error_mixer_new;      } @@ -121,6 +90,12 @@ int main(int argc, char **argv) {          goto error_mixer_input_add;      } +    xas_synth_set_frequency(sine_l, 2600); +    xas_synth_start(sine_l); + +    xas_synth_set_frequency(sine_r, 420); +    xas_synth_start(sine_r); +      for (i=0; i<duration_s; i++) {          void *buf;          ssize_t readlen; @@ -140,7 +115,9 @@ int main(int argc, char **argv) {      xas_mixer_destroy(mixer);      xas_audio_stream_destroy(synth_r); +    xas_synth_destroy(sine_r);      xas_audio_stream_destroy(synth_l); +    xas_synth_destroy(sine_l);      xas_audio_stream_destroy(wave);      return EX_OK; @@ -153,9 +130,15 @@ error_mixer_input_add:  error_mixer_new:      xas_audio_stream_destroy(synth_r); +error_synth_new_stream_r: +    xas_synth_destroy(sine_r); +  error_synth_new_r:      xas_audio_stream_destroy(synth_l); +error_synth_new_stream_l: +    xas_synth_destroy(sine_l); +  error_synth_new_l:      xas_audio_stream_destroy(wave); diff --git a/include/xas/synth.h b/include/xas/synth.h index 20446cd..53f3343 100644 --- a/include/xas/synth.h +++ b/include/xas/synth.h @@ -6,23 +6,49 @@  #include <xas/audio.h> -typedef struct _xas_synth xas_synth; +#define XAS_SYNTH_DEFAULT_FREQUENCY 2600 /* Hz */ -typedef int16_t (*xas_synth_callback_sample)(xas_synth *synth, void *ctx); +enum xas_synth_type { +    XAS_SYNTH_SINE, +    XAS_SYNTH_SQUARE, +    XAS_SYNTH_TRIANGLE, +    XAS_SYNTH_SAWTOOTH +}; -typedef void (*xas_synth_callback_cleanup)(xas_synth *synth, void *ctx); +enum xas_synth_state { +    XAS_SYNTH_IDLE, +    XAS_SYNTH_ACTIVE +}; + +typedef struct _xas_synth xas_synth; + +typedef int16_t (*xas_synth_sample_callback)(xas_synth *synth);  struct _xas_synth { +    enum xas_synth_type  type; +    enum xas_synth_state state; +      xas_audio_format format; -    xas_synth_callback_sample  sample; -    xas_synth_callback_cleanup cleanup; -    void *ctx; +    size_t buffer_size; + +    xas_synth_sample_callback sample; + +    float phase; +    size_t frequency;  }; -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_synth *xas_synth_new(xas_audio_format format, +                             size_t buffer_size, +                             enum xas_synth_type type); + +void xas_synth_destroy(xas_synth *synth); + +void xas_synth_set_frequency(xas_synth *synth, size_t frequency); + +void xas_synth_start(xas_synth *synth); + +void xas_synth_stop(xas_synth *synth); + +xas_audio_stream *xas_synth_new_stream(xas_synth *synth);  #endif /* _XAS_SYNTH_H */ 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); +} | 
 
    