full chromatic scale, fix regression of crossfading, second row of keys

This commit is contained in:
veclavtalica 2024-06-24 16:28:19 +03:00
parent 561dece028
commit 1bb675d158
5 changed files with 91 additions and 18 deletions

View File

@ -15,8 +15,9 @@
struct stfu_trojka {
struct stfu_phaser phasers[STFU_TROJKA_OP_COUNT];
struct stfu_envelope envelopes[STFU_TROJKA_OP_COUNT];
float gains[STFU_TROJKA_OP_COUNT];
float gains[STFU_TROJKA_OP_COUNT]; // todo: Combine with indices?
float freq_scales[STFU_TROJKA_OP_COUNT];
float indices[STFU_TROJKA_OP_COUNT - 1]; /* 1 to 100 */
float key_frequency;
float feedback_gain; // todo: Separate gain for channels?
float left_feedback, right_feedback;
@ -28,8 +29,8 @@ static struct stfu_trojka stfu_sample_trojka(struct stfu_trojka synth, float buf
synth.envelopes[i] = stfu_pump_envelope(synth.envelopes[i]);
}
float left_modulator_stack = synth.envelopes[1].v * sinf(synth.phasers[1].v + synth.envelopes[0].v * sinf(synth.phasers[0].v)) + synth.left_feedback * synth.feedback_gain;
float right_modulator_stack = synth.envelopes[1].v * sinf(synth.phasers[1].v + synth.envelopes[0].v * sinf(synth.phasers[0].v)) + synth.right_feedback * synth.feedback_gain;
float left_modulator_stack = synth.envelopes[1].v * synth.indices[1] * sinf(synth.phasers[1].v + synth.envelopes[0].v * synth.indices[0] * sinf(synth.phasers[0].v)) + synth.left_feedback * synth.feedback_gain;
float right_modulator_stack = left_modulator_stack;
synth.left_feedback = left_modulator_stack;
synth.right_feedback = right_modulator_stack;

Binary file not shown.

View File

@ -24,6 +24,9 @@ static float crossfade_ring[CROSSFADE_RING_RANGE] = {0};
static size_t crossfade_ring_needle = 0;
static unsigned int crossfade_frames_left = 0;
// 1.0 is with A at 440
static float octave = 0.5;
static void stream(float *buffer, int num_frames, int num_channels) {
/* Fade away */
for (size_t i = 0; crossfade_frames_left > 0;
@ -53,10 +56,15 @@ static void init(void) {
// .stream_cb = stream,
});
synth.phasers[0] = stfu_init_phaser(220);
synth.phasers[1] = stfu_init_phaser(220 * 0.25);
synth.phasers[2] = stfu_init_phaser(220 * 2.0);
synth.freq_scales[0] = 1.0;
synth.freq_scales[1] = 0.25;
synth.freq_scales[2] = 2.0;
synth.indices[0] = 2.0;
synth.indices[1] = 10.0;
synth.feedback_gain = 0.25;
for (int i = 0; i < STFU_TROJKA_OP_COUNT; ++i) {
synth.envelopes[i] = stfu_init_envelope(
(struct stfu_envelope_point[]){[0] = {.dur = 0.02, .vol = 1.0},
@ -64,7 +72,6 @@ static void init(void) {
[2] = {.dur = 1.0, .vol = 0}},
3);
synth.gains[i] = 1.0;
synth.freq_scales[i] = 1.0;
}
}
@ -76,40 +83,103 @@ static void event(const sapp_event *e) {
if (e->key_repeat)
break;
bool key_was_pressed = false;
switch (e->key_code) {
case SAPP_KEYCODE_Z:
synth = stfu_press_trojka(synth, STFU_SCALE[0]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[0] * octave);
break;
case SAPP_KEYCODE_X:
synth = stfu_press_trojka(synth, STFU_SCALE[1]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[1] * octave);
break;
case SAPP_KEYCODE_C:
synth = stfu_press_trojka(synth, STFU_SCALE[2]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[2] * octave);
break;
case SAPP_KEYCODE_V:
synth = stfu_press_trojka(synth, STFU_SCALE[3]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[3] * octave);
break;
case SAPP_KEYCODE_B:
synth = stfu_press_trojka(synth, STFU_SCALE[4]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[4] * octave);
break;
case SAPP_KEYCODE_N:
synth = stfu_press_trojka(synth, STFU_SCALE[5]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[5] * octave);
break;
case SAPP_KEYCODE_M:
synth = stfu_press_trojka(synth, STFU_SCALE[6]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[6] * octave);
break;
case SAPP_KEYCODE_COMMA:
synth = stfu_press_trojka(synth, STFU_SCALE[7]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[7] * octave);
break;
case SAPP_KEYCODE_PERIOD:
synth = stfu_press_trojka(synth, STFU_SCALE[8]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[8] * octave);
break;
case SAPP_KEYCODE_SLASH:
synth = stfu_press_trojka(synth, STFU_SCALE[9]);
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[9] * octave);
break;
case SAPP_KEYCODE_A:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[0] * (octave * 2));
break;
case SAPP_KEYCODE_S:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[1] * (octave * 2));
break;
case SAPP_KEYCODE_D:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[2] * (octave * 2));
break;
case SAPP_KEYCODE_F:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[3] * (octave * 2));
break;
case SAPP_KEYCODE_G:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[4] * (octave * 2));
break;
case SAPP_KEYCODE_H:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[5] * (octave * 2));
break;
case SAPP_KEYCODE_J:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[6] * (octave * 2));
break;
case SAPP_KEYCODE_K:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[7] * (octave * 2));
break;
case SAPP_KEYCODE_L:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[8] * (octave * 2));
break;
case SAPP_KEYCODE_SEMICOLON:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[9] * (octave * 2));
break;
case SAPP_KEYCODE_APOSTROPHE:
key_was_pressed = true;
synth = stfu_press_trojka(synth, STFU_SCALE[10] * (octave * 2));
break;
default:
break;
}
if (key_was_pressed) {
crossfade_frames_left = STFU_CROSSFADE_BUFFER_FRAMES;
}
break;
}
default:

View File

@ -33,6 +33,8 @@ static const float STFU_SCALE[12] = {
STFU_NOTE_DOWNSCALE_FACTOR,
STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR,
STFU_A4_FREQUENCY,
STFU_A4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR,
STFU_A4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR * STFU_NOTE_UPSCALE_FACTOR,
};
#endif

View File

@ -1,5 +1,5 @@
# STFU ! SoundTracker Format Unirepo
Grassroot music format specifically designed for lofi game soundtracks with accent on binary efficiency in its various forms.
Grassroot music format specifically designed for reproducible lofi game soundtracks with accent on binary efficiency in its various forms.
- Separation of Maker and Player binaries, with Player being absolutely dependency free.
- Samples and instruments are stored outside of tracks in a shared data base allowing reuse.