aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorspl3g <spleefer6@yandex.ru>2025-10-10 13:34:07 +0300
committerspl3g <spleefer6@yandex.ru>2025-10-10 13:34:29 +0300
commit145229b9ec9b0f50cdef537f1bae5f09c3198ead (patch)
tree7e0757cc1f9ece826a95f5c2caf54ce6a2d653ed /src
parentfebc94a11b127fd9ebb4153c06c9289949ffaab9 (diff)
Make envelope customizable
Diffstat (limited to 'src')
-rw-r--r--src/main.c43
-rw-r--r--src/sounds.c101
-rw-r--r--src/sounds.h17
3 files changed, 119 insertions, 42 deletions
diff --git a/src/main.c b/src/main.c
index d40945b..bd9d5e1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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 { \