summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/synth.c154
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);
+}