diff options
| author | spl3g <spleefer6@yandex.ru> | 2025-10-10 13:34:07 +0300 |
|---|---|---|
| committer | spl3g <spleefer6@yandex.ru> | 2025-10-10 13:34:29 +0300 |
| commit | 145229b9ec9b0f50cdef537f1bae5f09c3198ead (patch) | |
| tree | 7e0757cc1f9ece826a95f5c2caf54ce6a2d653ed /src | |
| parent | febc94a11b127fd9ebb4153c06c9289949ffaab9 (diff) | |
Make envelope customizable
Diffstat (limited to 'src')
| -rw-r--r-- | src/main.c | 43 | ||||
| -rw-r--r-- | src/sounds.c | 101 | ||||
| -rw-r--r-- | src/sounds.h | 17 |
3 files changed, 119 insertions, 42 deletions
@@ -64,24 +64,57 @@ int init_sounds(app_state *state) { state->sound_thread = sound_thread; - synth_message param_message = { + synth_message param_messages[6] = { + { .type = MSG_PARAM_CHANGE, .param_change = { .param_type = PARAM_OSC, .value = OSC_SQUARE, }, - }; - mqueue_push(&state->msg_queue, param_message); - param_message = (synth_message){ + }, + { .type = MSG_PARAM_CHANGE, .param_change = { .param_type = PARAM_VOLUME, .value = 1, }, + }, + { + .type = MSG_PARAM_CHANGE, + .param_change = + { + .param_type = PARAM_ATTACK, + .value = 0.005 * SAMPLE_RATE, + }, + }, + { + .type = MSG_PARAM_CHANGE, + .param_change = + { + .param_type = PARAM_DECAY, + .value = 0.0010 * SAMPLE_RATE, + }, + }, + { + .type = MSG_PARAM_CHANGE, + .param_change = + { + .param_type = PARAM_SUSTAIN, + .value = 0.7, + }, + }, + { + .type = MSG_PARAM_CHANGE, + .param_change = + { + .param_type = PARAM_RELEASE, + .value = 1.000 * SAMPLE_RATE, + }, + }, }; - mqueue_push(&state->msg_queue, param_message); + mqueue_push_many(&state->msg_queue, param_messages, 6); return 0; } diff --git a/src/sounds.c b/src/sounds.c index 9ca88c1..b011f0c 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -14,20 +14,36 @@ int mqueue_get(message_queue *q, synth_message *msg) { return 0; } -int mqueue_push(message_queue *q, synth_message msg) { - pthread_mutex_lock(&(q)->lock); +int mqueue__push_no_lock(message_queue *q, synth_message msg) { size_t next = ((q)->head + 1) % MESSAGE_QUEUE_SIZE; if ((q)->tail == next) { - pthread_mutex_unlock(&(q)->lock); - return 1; + return 1; } (q)->buffer[(q)->head] = msg; (q)->head = next; + return 0; +} +int mqueue_push(message_queue *q, synth_message msg) { + pthread_mutex_lock(&(q)->lock); + int ret = mqueue__push_no_lock(q, msg); pthread_mutex_unlock(&(q)->lock); - return 0; + return ret; +} + +int mqueue_push_many(message_queue *q, synth_message *msg, size_t count) { + pthread_mutex_lock(&(q)->lock); + int ret = 0; + for (size_t i = 0; i < count; i++) { + ret = mqueue__push_no_lock(q, msg[i]); + if (ret != 0) { + break; + } + } + pthread_mutex_unlock(&(q)->lock); + return ret; } float envelope_next(envelope *env) { @@ -41,57 +57,59 @@ float envelope_next(envelope *env) { return 0; } case ENV_ATTACK: { - if (env->counter >= env->attack_time) { + if (env->counter >= env->params.attack_time) { next_state = true; } - value = env->increases[0] * (float)env->counter; + + if (env->current_value == 0) { + env->current_value = 1.0 / (float)env->params.attack_time; + } + + value = env->current_value * (float)env->counter; break; } case ENV_DECAY: { - if (env->counter >= env->decay_time) { + if (env->counter >= env->params.decay_time) { next_state = true; } - value = 1.0 - env->increases[1] * (float)env->counter; + if (env->current_value == 0) { + env->current_value = (1.0 - env->params.sustain_level) / (float)env->params.decay_time; + } + + value = 1.0 - env->current_value * (float)env->counter; break; } case ENV_SUSTAIN: { - value = env->sustain_level; + value = env->params.sustain_level; break; } case ENV_RELEASE: { - if (env->counter >= env->release_time) { + if (env->counter >= env->params.release_time) { env->state = ENV_OFF; - env->counter = 0; + env->counter = env->current_value = 0; return 0; } - value = env->sustain_level - env->increases[2] * (float)env->counter; + + if (env->current_value == 0) { + env->current_value = env->params.sustain_level / (float)env->params.release_time; + } + + value = env->params.sustain_level - env->current_value * (float)env->counter; break; } } if (next_state) { - env->counter = 0; + env->counter = env->current_value = 0; env->state++; } return value; } -void envelope_init(envelope *env) { - env->state = ENV_OFF; - env->counter = 0; - env->attack_time = 0.005 * SAMPLE_RATE; - env->decay_time = 0.0010 * SAMPLE_RATE; - env->sustain_level = 0.7; - env->release_time = 1.000 * SAMPLE_RATE; - - env->increases[0] = 1.0 / (float)env->attack_time; - env->increases[1] = (1.0 - env->sustain_level) / (float)env->decay_time; - env->increases[2] = env->sustain_level / (float)env->release_time; -} - -void envelope_note_on(envelope *env) { +void envelope_note_on(envelope_params params, envelope *env) { env->state = ENV_ATTACK; env->counter = 0; + env->params = params; } void envelope_note_off(envelope *env) { @@ -124,11 +142,11 @@ oscilator_func osc_get(oscilator_type type) { } } -void set_note_on(synth_voices *voices, size_t note_id) { +void set_note_on(synth_params *params, synth_voices *voices, size_t note_id) { if (note_id >= voices->size) { return; } - envelope_note_on(&voices->buffer[note_id].envelope); + envelope_note_on(params->envelope_params, &voices->buffer[note_id].envelope); voices->buffer[note_id].active = true; } @@ -157,6 +175,22 @@ void set_param(synth_params *params, param_type type, float value) { params->master_volume = value; break; } + case PARAM_ATTACK: { + params->envelope_params.attack_time = (int)value; + break; + } + case PARAM_DECAY: { + params->envelope_params.decay_time = (int)value; + break; + } + case PARAM_SUSTAIN: { + params->envelope_params.sustain_level = value; + break; + } + case PARAM_RELEASE: { + params->envelope_params.release_time = (int)value; + break; + } } } @@ -213,7 +247,7 @@ void sound_loop_start(snd_pcm_t *pcm, message_queue *queue, switch (msg.type) { case MSG_NOTE_ON: { size_t note_id = msg.note.note_id; - set_note_on(voices, note_id); + set_note_on(params, voices, note_id); break; } case MSG_NOTE_OFF: { @@ -228,6 +262,7 @@ void sound_loop_start(snd_pcm_t *pcm, message_queue *queue, case MSG_PARAM_CHANGE: { param_type type = msg.param_change.param_type; float value = msg.param_change.value; + printf("%d %f\n", type, value); set_param(params, type, value); break; } @@ -264,15 +299,13 @@ stop: } void fill_voices(synth_voice *voices, float *freqs, size_t freqs_amount) { - envelope env = {0}; - envelope_init(&env); for (size_t i = 0; i < freqs_amount; i++) { voices[i] = (synth_voice){ .active = false, .freq = freqs[i], .phase = 0, .phase_inc = 0, - .envelope = env, + .envelope = {0}, }; } } diff --git a/src/sounds.h b/src/sounds.h index 4b2f78f..49386ce 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -24,6 +24,11 @@ typedef enum { PARAM_OSC, PARAM_VOLUME, + + PARAM_ATTACK, + PARAM_DECAY, + PARAM_SUSTAIN, + PARAM_RELEASE, } param_type; typedef enum { @@ -79,13 +84,17 @@ typedef enum { } envelope_state; typedef struct { - envelope_state state; - int counter; int attack_time; int decay_time; float sustain_level; int release_time; - float increases[3]; +} envelope_params; + +typedef struct { + envelope_state state; + int counter; + float current_value; + envelope_params params; } envelope; typedef struct { @@ -104,12 +113,14 @@ typedef struct { typedef struct { oscilator_type oscilator_type; float master_volume; + envelope_params envelope_params; } synth_params; typedef float (*oscilator_func)(float phase); int mqueue_get(message_queue *q, synth_message *msg); int mqueue_push(message_queue *q, synth_message msg); +int mqueue_push_many(message_queue *q, synth_message *msg, size_t count); #define mqueue_init(q) \ do { \ |
