stfu/Source/Maker/main.c

177 lines
5.6 KiB
C

#include <stdio.h>
#include <string.h>
#define SOKOL_IMPL
#define SOKOL_GLCORE
#include "sokol_app.h"
#include "sokol_audio.h"
#include "sokol_log.h"
#include "../config.h"
#include "../envelope.c"
// #include "../interp.c"
#include "../oscillators.c"
#include "../phaser.c"
static struct stfu_sinewave sine0;
static struct stfu_phaser phaser0;
static struct stfu_phaser phaser1;
static struct stfu_phaser phaser2;
static struct stfu_envelope envelope;
static float key_frequency = STFU_C4_FREQUENCY;
#define CROSSFADE_RING_RANGE \
(STFU_CROSSFADE_BUFFER_FRAMES * STFU_AUDIO_CHANNEL_COUNT)
static float crossfade_ring[CROSSFADE_RING_RANGE] = {0};
static size_t crossfade_ring_needle = 0;
static unsigned int crossfade_frames_left = 0;
static void sample(float buffer[static 2]) {
phaser0 = stfu_pump_phaser(phaser0);
phaser1 = stfu_pump_phaser(phaser1);
phaser2 = stfu_pump_phaser(phaser2);
envelope = stfu_pump_envelope(envelope);
float left = envelope.v * sinf(phaser2.v + sinf(phaser0.v + sinf(phaser1.v)));
float right =
envelope.v * sinf(phaser2.v + sinf(phaser0.v + sinf(phaser1.v)));
buffer[0] = left;
buffer[1] = right;
}
static void stream(float *buffer, int num_frames, int num_channels) {
/* Fade away */
for (size_t i = 0; crossfade_frames_left > 0;
crossfade_frames_left--, i += 2) {
crossfade_ring[(crossfade_ring_needle + i) % CROSSFADE_RING_RANGE] *=
(float)crossfade_frames_left / STFU_CROSSFADE_BUFFER_FRAMES;
crossfade_ring[(crossfade_ring_needle + i + 1) % CROSSFADE_RING_RANGE] *=
(float)crossfade_frames_left / STFU_CROSSFADE_BUFFER_FRAMES;
}
/* Drive the ring buffer */
// todo: Use memcpy for left and right side of the ring.
while (num_frames--) {
buffer[0] = crossfade_ring[crossfade_ring_needle % CROSSFADE_RING_RANGE];
buffer[1] =
crossfade_ring[(crossfade_ring_needle + 1) % CROSSFADE_RING_RANGE];
sample(&crossfade_ring[crossfade_ring_needle % CROSSFADE_RING_RANGE]);
buffer = &buffer[2];
crossfade_ring_needle += 2;
}
}
static void init(void) {
saudio_setup(&(saudio_desc){
.sample_rate = STFU_AUDIO_FRAME_RATE,
.num_channels = STFU_AUDIO_CHANNEL_COUNT,
// .stream_cb = stream,
});
// sine0 = stfu_init_sinewave(STFU_A4_FREQUENCY / 2.0f, 0.0f, 0.8f);
phaser0 = stfu_init_phaser(key_frequency);
phaser1 = stfu_init_phaser(key_frequency * 0.25);
phaser2 = stfu_init_phaser(key_frequency * 2.0);
envelope = stfu_init_envelope(
(struct stfu_envelope_point[]){[0] = {.dur = 0.02, .vol = 1.0},
[1] = {.dur = 0.5, .vol = 0.33},
[2] = {.dur = 1.0, .vol = 0}},
3);
}
static void cleanup(void) { saudio_shutdown(); }
static void event(const sapp_event *e) {
switch (e->type) {
case SAPP_EVENTTYPE_KEY_DOWN: {
if (e->key_repeat)
break;
switch (e->key_code) {
case SAPP_KEYCODE_Z:
key_frequency = STFU_C4_FREQUENCY;
break;
case SAPP_KEYCODE_X:
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR;
break;
case SAPP_KEYCODE_C:
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR *
STFU_NOTE_UPSCALE_FACTOR;
break;
case SAPP_KEYCODE_V:
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR *
STFU_NOTE_UPSCALE_FACTOR * STFU_NOTE_UPSCALE_FACTOR;
break;
case SAPP_KEYCODE_B:
key_frequency = STFU_C4_FREQUENCY * STFU_NOTE_UPSCALE_FACTOR *
STFU_NOTE_UPSCALE_FACTOR * STFU_NOTE_UPSCALE_FACTOR *
STFU_NOTE_UPSCALE_FACTOR;
break;
case SAPP_KEYCODE_N:
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR *
STFU_NOTE_DOWNSCALE_FACTOR * STFU_NOTE_DOWNSCALE_FACTOR *
STFU_NOTE_DOWNSCALE_FACTOR;
break;
case SAPP_KEYCODE_M:
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR *
STFU_NOTE_DOWNSCALE_FACTOR * STFU_NOTE_DOWNSCALE_FACTOR;
break;
case SAPP_KEYCODE_COMMA:
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR *
STFU_NOTE_DOWNSCALE_FACTOR;
break;
case SAPP_KEYCODE_PERIOD:
key_frequency = STFU_A4_FREQUENCY * STFU_NOTE_DOWNSCALE_FACTOR;
break;
case SAPP_KEYCODE_SLASH:
key_frequency = STFU_A4_FREQUENCY;
break;
default:
break;
}
phaser0 = stfu_set_phaser_frequency(phaser0, key_frequency);
phaser1 = stfu_set_phaser_frequency(phaser1, key_frequency * 0.25);
phaser2 = stfu_set_phaser_frequency(phaser2, key_frequency * 2.0);
envelope = stfu_trigger_envelope(envelope);
crossfade_frames_left = STFU_CROSSFADE_BUFFER_FRAMES;
break;
}
default:
break;
}
}
static void frame(void) {
int frames = (int)(sapp_frame_duration() * (float)STFU_AUDIO_FRAME_RATE);
int expected = saudio_expect();
frames = frames > expected ? expected : frames;
// todo: Prevent drifting apart.
static float buffer[STFU_AUDIO_FRAME_RATE * STFU_AUDIO_CHANNEL_COUNT];
while (frames > 0) {
int now = frames > STFU_AUDIO_FRAME_RATE ? STFU_AUDIO_FRAME_RATE : frames;
stream(buffer, now, STFU_AUDIO_CHANNEL_COUNT);
saudio_push(buffer, now);
frames -= now;
}
}
sapp_desc sokol_main(int argc, char *argv[]) {
return (sapp_desc){
.width = 640,
.height = 480,
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
.event_cb = event,
.logger.func = slog_func,
.gl_major_version = 2,
.gl_minor_version = 0,
// .swap_interval = 0,
};
}