summaryrefslogtreecommitdiff
path: root/source/saw/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/saw/main.c')
-rw-r--r--source/saw/main.c231
1 files changed, 136 insertions, 95 deletions
diff --git a/source/saw/main.c b/source/saw/main.c
index 38d292f..7bcc6d7 100644
--- a/source/saw/main.c
+++ b/source/saw/main.c
@@ -58,17 +58,26 @@ enum {
CHANNEL_COUNT = 2,
SAMPLE_RATE = 44100,
#ifdef __EMSCRIPTEN__
- BUFFER_SIZE = 2048 * 32,
+ BUFFER_SIZE = 1024 * 16,
#else
- BUFFER_SIZE = 2048 * 4,
+ BUFFER_SIZE = 1024 * 2,
#endif
+#ifdef __EMSCRIPTEN__
+ TRACK_COUNT = 8,
+ ROLL_COUNT = 16,
+ PITCH_COUNT = 80,
+ VOICE_COUNT = 16,
+ UNISON_COUNT = 100,
+ SHEET_SIZE = 200,
+#else
TRACK_COUNT = 16,
ROLL_COUNT = 32,
PITCH_COUNT = 80,
VOICE_COUNT = 32,
UNISON_COUNT = 100,
SHEET_SIZE = 200,
+#endif
ROLL_DEFAULT_RATE = 8,
ROLL_DEFAULT_UI_OFFSET_Y = 710,
@@ -212,6 +221,7 @@ static i64 saw_playback_lookahead = 0;
static i64 saw_playback_offset_read = 0;
static i64 saw_playback_offset_write = 0;
static f32 saw_playback_buffer[BUFFER_SIZE] = { 0.f };
+static f32 saw_playback_temp[BUFFER_SIZE];
static mtx_t saw_playback_mutex;
static i64 saw_current_track = 0;
@@ -338,105 +348,134 @@ static void saw_audio_render(void) {
// FIXME
// Improve performance.
- if (mtx_lock(&saw_playback_mutex) != thrd_success) {
- assert(0);
- return;
- }
-
i64 frame_count = (BUFFER_SIZE / CHANNEL_COUNT) -
saw_playback_lookahead;
- for (i64 i = 0; i < frame_count; i++) {
- if (saw_playback_on) {
- // Note triggers
- //
+ if (frame_count > 0) {
+ memset(saw_playback_temp, 0,
+ frame_count * CHANNEL_COUNT * sizeof *saw_playback_temp);
- for (i32 k = 0; k < ROLL_COUNT; k++) {
- saw_roll_t *roll = saw_rolls + k;
- if (!roll->enabled || saw_playback_frame + 1 <= roll->time ||
- saw_playback_frame + 1 > roll->time + roll->duration)
- continue;
+ for (i64 i = 0; i < frame_count; i++) {
+ if (saw_playback_on) {
+ // Note triggers
+ //
- i64 play_frame = roll->loop_duration == 0
- ? saw_playback_frame
- : saw_playback_frame -
- ((saw_playback_frame + 1 -
- roll->time) /
- roll->loop_duration) *
- roll->loop_duration;
-
- for (i32 i = 0; i < SHEET_SIZE; i++) {
- saw_roll_note_t *note = roll->notes + i;
- if (!note->enabled)
- continue;
- i64 note_frame = roll->time + note->time;
- if (play_frame + 1 <= note_frame || play_frame > note_frame)
+ for (i32 k = 0; k < ROLL_COUNT; k++) {
+ saw_roll_t *roll = saw_rolls + k;
+ if (!roll->enabled ||
+ saw_playback_frame + 1 <= roll->time ||
+ saw_playback_frame + 1 > roll->time + roll->duration)
continue;
- saw_play_voice(saw_tracks + roll->track, roll, note->pitch,
- note->duration);
+ i64 play_frame = roll->loop_duration == 0
+ ? saw_playback_frame
+ : saw_playback_frame -
+ ((saw_playback_frame + 1 -
+ roll->time) /
+ roll->loop_duration) *
+ roll->loop_duration;
+
+ for (i32 i = 0; i < SHEET_SIZE; i++) {
+ saw_roll_note_t *note = roll->notes + i;
+ if (!note->enabled)
+ continue;
+ i64 note_frame = roll->time + note->time;
+ if (play_frame + 1 <= note_frame ||
+ play_frame > note_frame)
+ continue;
+
+ saw_play_voice(saw_tracks + roll->track, roll,
+ note->pitch, note->duration);
+ }
}
+
+ ++saw_playback_frame;
}
- ++saw_playback_frame;
+ // Oscillators
+ //
+ {
+ for (i32 n = 0; n < VOICE_COUNT; n++) {
+ if (!saw_voices[n].enabled)
+ continue;
+
+ saw_track_t *track = saw_tracks + saw_voices[n].track;
+
+ i32 wave_type = track->instrument;
+ f64 warp = track->warp;
+ f64 frequency = saw_voices[n].frequency;
+ f64 amplitude = saw_voices[n].amplitude;
+ f64 phase_l = track->phase + saw_voices[n].phase[0];
+ f64 phase_r = track->phase + saw_voices[n].phase[1];
+
+ f64 attack = track->envelope.attack;
+ f64 decay = track->envelope.decay;
+ f64 sustain = track->envelope.sustain;
+ f64 duration = saw_voices[n].duration;
+ f64 release = track->envelope.release;
+
+ f64 t = (f64) saw_voices[n].time / (f64) SAMPLE_RATE;
+ f64 a = amplitude * saw_envelope(t, attack, decay, sustain,
+ duration, release);
+
+ saw_playback_temp[i * CHANNEL_COUNT] +=
+ (f32) (saw_oscillator(wave_type, frequency, phase_l,
+ warp, t) *
+ a);
+ saw_playback_temp[i * CHANNEL_COUNT + 1] +=
+ (f32) (saw_oscillator(wave_type, frequency, phase_r,
+ warp, t) *
+ a);
+
+ saw_voices[n].time++;
+
+ if (t > duration + release)
+ saw_voices[n].enabled = 0;
+ }
+ }
}
- // Oscillators
- //
- {
- i64 k = (saw_playback_offset_write + i * CHANNEL_COUNT) %
- BUFFER_SIZE;
+ i64 n0 = frame_count < (BUFFER_SIZE - saw_playback_offset_write) /
+ CHANNEL_COUNT
+ ? frame_count
+ : (BUFFER_SIZE - saw_playback_offset_write) /
+ CHANNEL_COUNT;
+ i64 n1 = frame_count - n0;
- saw_playback_buffer[k] = 0.f;
- saw_playback_buffer[k + 1] = 0.f;
+ if (mtx_lock(&saw_playback_mutex) != thrd_success) {
+ assert(0);
+ return;
+ }
- for (i32 n = 0; n < VOICE_COUNT; n++) {
- if (!saw_voices[n].enabled)
- continue;
+ if (n0 > 0)
+ memcpy(saw_playback_buffer + saw_playback_offset_write,
+ saw_playback_temp,
+ n0 * CHANNEL_COUNT * sizeof *saw_playback_temp);
- saw_track_t *track = saw_tracks + saw_voices[n].track;
-
- i32 wave_type = track->instrument;
- f64 warp = track->warp;
- f64 frequency = saw_voices[n].frequency;
- f64 amplitude = saw_voices[n].amplitude;
- f64 phase_l = track->phase + saw_voices[n].phase[0];
- f64 phase_r = track->phase + saw_voices[n].phase[1];
-
- f64 attack = track->envelope.attack;
- f64 decay = track->envelope.decay;
- f64 sustain = track->envelope.sustain;
- f64 duration = saw_voices[n].duration;
- f64 release = track->envelope.release;
-
- f64 t = (f64) saw_voices[n].time / (f64) SAMPLE_RATE;
- f64 a = amplitude * saw_envelope(t, attack, decay, sustain,
- duration, release);
-
- saw_playback_buffer[k] += (f32) (saw_oscillator(
- wave_type, frequency,
- phase_l, warp, t) *
- a);
- saw_playback_buffer[k + 1] += (f32) (saw_oscillator(
- wave_type, frequency,
- phase_r, warp, t) *
- a);
-
- saw_voices[n].time++;
-
- if (t > duration + release)
- saw_voices[n].enabled = 0;
- }
- }
- }
+ if (n1 > 0)
+ memcpy(saw_playback_buffer,
+ saw_playback_temp + (n0 * CHANNEL_COUNT),
+ n1 * CHANNEL_COUNT * sizeof *saw_playback_temp);
- saw_playback_offset_write = (saw_playback_offset_write +
- frame_count * CHANNEL_COUNT) %
- BUFFER_SIZE;
+ saw_playback_offset_write = (saw_playback_offset_write +
+ frame_count * CHANNEL_COUNT) %
+ BUFFER_SIZE;
- saw_playback_lookahead += frame_count;
+ saw_playback_lookahead += frame_count;
- mtx_unlock(&saw_playback_mutex);
+ mtx_unlock(&saw_playback_mutex);
+ }
+
+#ifndef __EMSCRIPTEN__
+ if (frame_count == 0 && !saw_playback_on) {
+ // Sleep for 1/5 of the buffer duration
+ thrd_sleep(
+ &(struct timespec) {
+ .tv_nsec = (200000000ll * BUFFER_SIZE / CHANNEL_COUNT) /
+ SAMPLE_RATE },
+ NULL);
+ }
+#endif
}
static void saw_audio_callback(ma_device *device, void *void_out_,
@@ -458,12 +497,20 @@ static void saw_audio_callback(ma_device *device, void *void_out_,
? frame_count
: saw_playback_lookahead;
- for (i64 i = 0; i < n; i++) {
- i64 k = (saw_playback_offset_read + i * CHANNEL_COUNT) %
- BUFFER_SIZE;
- out[i * 2] = saw_playback_buffer[k];
- out[i * 2 + 1] = saw_playback_buffer[k + 1];
- }
+ i64 n0 = n < (BUFFER_SIZE - saw_playback_offset_read) /
+ CHANNEL_COUNT
+ ? n
+ : (BUFFER_SIZE - saw_playback_offset_read) /
+ CHANNEL_COUNT;
+ i64 n1 = n - n0;
+
+ if (n0 > 0)
+ memcpy(out, saw_playback_buffer + saw_playback_offset_read,
+ n0 * CHANNEL_COUNT * sizeof *out);
+
+ if (n1 > 0)
+ memcpy(out + (n0 * CHANNEL_COUNT), saw_playback_buffer,
+ n1 * CHANNEL_COUNT * sizeof *out);
saw_playback_offset_read = (saw_playback_offset_read +
n * CHANNEL_COUNT) %
@@ -1946,12 +1993,6 @@ static void saw_init(void) {
}
static void saw_frame(void) {
- // TODO
- // Adjust sleep depending on how much compute we need
-
- // Sleep to prevent high CPU load
- thrd_sleep(&(struct timespec) { .tv_nsec = 10000000 }, NULL);
-
saw_audio_render();
i64 frame_width = sapp_width();