#include #include #include #include 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(synth->gain * (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; float duty = synth->duty; if (synth->state == XAS_SYNTH_ACTIVE) { ret = (synth->phase - (duty * tau)) > 0.0? (int16_t)roundf(synth->gain * (INT16_MAX / 4)): (int16_t)roundf(synth->gain * (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(synth->gain * (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(synth->gain * (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, xas_audio_stream *stream) { size_t i; if (synth->frequency > 0) { for (i=0; isample(synth); } } else { for (i=0; isample = 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; default: errno = EINVAL; goto error_invalid_type; } synth->type = type; return 0; error_invalid_type: return -1; } 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->obj.start = (xas_object_start_callback)synth_start; synth->obj.stop = (xas_object_stop_callback)synth_stop; synth->obj.set_gain = (xas_object_set_gain_callback)set_gain; synth->obj.stream_new = (xas_object_stream_new_callback)xas_synth_stream_new; synth->obj.destroy = (xas_object_destroy_callback)xas_synth_destroy; synth->state = XAS_SYNTH_IDLE; synth->phase = 0.0f; synth->gain = XAS_SYNTH_DEFAULT_GAIN; synth->duty = XAS_SYNTH_DEFAULT_DUTY; 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; if (set_type(synth, type) < 0) { goto error_set_type; } return synth; error_set_type: free(synth); error_malloc_synth: return NULL; } void xas_synth_destroy(xas_synth *synth) { free(synth); } void xas_synth_set_gain(xas_synth *synth, float gain) { synth->gain = gain; } void xas_synth_set_duty(xas_synth *synth, float duty) { synth->duty = duty; } void xas_synth_set_type(xas_synth *synth, enum xas_synth_type type) { set_type(synth, type); } 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_stream_new(xas_synth *synth) { return xas_audio_stream_new_source((xas_audio_fill)synth_fill, NULL, synth->format, synth->buffer_size, synth); }