summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO2
-rw-r--r--source/saw/main.c137
2 files changed, 101 insertions, 38 deletions
diff --git a/TODO b/TODO
index 7db1d98..d4ad698 100644
--- a/TODO
+++ b/TODO
@@ -12,7 +12,6 @@ To-Do list
- Simple tonal synth
- Kick, snare, cymbal
- EQ, delay, reverb, compressor, limiter
- - Sampler
- Sample rendering
- Internal sample rate for time values
@@ -58,6 +57,7 @@ Done
- Sample loading
- WAV import
- Drag & drop audio files
+ - Sampler
- UI
- Piano roll
diff --git a/source/saw/main.c b/source/saw/main.c
index cc2bfa1..02d94c4 100644
--- a/source/saw/main.c
+++ b/source/saw/main.c
@@ -51,6 +51,8 @@
// Constants
//
+#define TIME_EPS 0.0001
+
enum {
// TODO
//
@@ -187,8 +189,6 @@ typedef struct {
f64 begin;
f64 end;
f64 tail;
- f64 fade_in;
- f64 fade_out;
f64 crossfade;
f64 base_frequency;
f64 volume;
@@ -547,6 +547,9 @@ static void saw_audio_render(void) {
case INSTRUMENT_SAMPLER: {
saw_sampler_t *sam = &track->sampler;
+ if (sam->begin + sam->crossfade + TIME_EPS >= sam->end)
+ break;
+
f64 frequency = saw_voices[n].frequency;
f64 amplitude = saw_voices[n].amplitude;
@@ -561,14 +564,86 @@ static void saw_audio_render(void) {
sustain, duration,
release);
- saw_playback_temp[i * CHANNEL_COUNT] +=
- (f32) (saw_sampler(sam, 0, frequency,
- saw_voices[n].time) *
- a);
- saw_playback_temp[i * CHANNEL_COUNT + 1] +=
- (f32) (saw_sampler(sam, 1, frequency,
- saw_voices[n].time) *
- a);
+ f64 crossfade = sam->crossfade;
+ f64 sample_begin = sam->begin;
+ f64 sample_end = sam->end;
+ f64 sample_duration = sample_end - sample_begin -
+ crossfade;
+ f64 sample_tail = sam->tail;
+ f64 body_end = duration + crossfade;
+ f64 tail_begin = duration;
+ f64 tail_end = tail_begin + sample_tail;
+
+ if (t <= body_end) {
+ // Play the body
+ //
+
+ f64 q = t;
+ assert(sample_duration > TIME_EPS);
+ while (q >= sample_duration)
+ q -= sample_duration;
+ q += sample_begin;
+
+ f64 u0 = 1.;
+ if (t > tail_begin && crossfade > TIME_EPS)
+ u0 = 1. - (t - tail_begin) / crossfade;
+
+ if (t >= sample_duration && q < crossfade &&
+ crossfade > TIME_EPS) {
+ // Play the body crossfade
+ //
+
+ f64 u = u0 * (1. - q / crossfade);
+ f64 r = sample_begin + sample_duration + q;
+ i64 k = (i64) floor(r * SAMPLE_RATE + .5);
+
+ saw_playback_temp[i * CHANNEL_COUNT] +=
+ (f32) (saw_sampler(sam, 0, frequency, k) * a *
+ u);
+ saw_playback_temp[i * CHANNEL_COUNT + 1] +=
+ (f32) (saw_sampler(sam, 1, frequency, k) * a *
+ u);
+ }
+
+ {
+ // Play the body main part
+ //
+
+ f64 u = u0;
+ if (t >= sample_duration && q < crossfade &&
+ crossfade > TIME_EPS)
+ u *= q / crossfade;
+
+ f64 r = sample_begin + q;
+ i64 k = (i64) floor(r * SAMPLE_RATE + .5);
+
+ saw_playback_temp[i * CHANNEL_COUNT] +=
+ (f32) (saw_sampler(sam, 0, frequency, k) * a *
+ u);
+ saw_playback_temp[i * CHANNEL_COUNT + 1] +=
+ (f32) (saw_sampler(sam, 1, frequency, k) * a *
+ u);
+ }
+ }
+
+ if (t >= tail_begin && t <= tail_end) {
+ // Play the tail
+ //
+
+ f64 q = t - tail_begin;
+
+ f64 u = 1.;
+ if (q < crossfade && crossfade > TIME_EPS)
+ u = q / crossfade;
+
+ f64 r = sample_end + q;
+ i64 k = (i64) floor(r * SAMPLE_RATE + .5);
+
+ saw_playback_temp[i * CHANNEL_COUNT] +=
+ (f32) (saw_sampler(sam, 0, frequency, k) * a * u);
+ saw_playback_temp[i * CHANNEL_COUNT + 1] +=
+ (f32) (saw_sampler(sam, 1, frequency, k) * a * u);
+ }
saw_voices[n].time++;
@@ -1517,8 +1592,6 @@ static void saw_ui_choose_instrument(saw_track_t *track, i64 x0,
track->sampler.begin = 0.;
track->sampler.end = 1.;
track->sampler.tail = .2;
- track->sampler.fade_in = 0.f;
- track->sampler.fade_out = 0.;
track->sampler.crossfade = .01;
track->sampler.base_frequency = 440.;
track->sampler.volume = .5;
@@ -1667,7 +1740,12 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0,
nvgTextAlign(saw_nvg, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
nvgText(saw_nvg, x0 + width / 2,
frame_height - y0 - height + sample_height / 2,
- "Drop a WAV file here", NULL);
+#ifdef __EMSCRIPTEN__
+ "Not implemented for the web yet",
+#else
+ "Drop a WAV file here",
+#endif
+ NULL);
}
saw_ui_value_float(x, y0 + height - sample_height - text_height, w,
@@ -1680,18 +1758,12 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0,
w, text_height, TINT_WHITE, SZ("Tail"), 100000,
0., 60., &sampler->tail);
saw_ui_value_float(x, y0 + height - sample_height - text_height * 4,
- w, text_height, TINT_WHITE, SZ("Fade in"),
- 100000, 0., 60., &sampler->fade_in);
- saw_ui_value_float(x, y0 + height - sample_height - text_height * 5,
- w, text_height, TINT_WHITE, SZ("Fade out"),
- 100000, 0., 60., &sampler->fade_out);
- saw_ui_value_float(x, y0 + height - sample_height - text_height * 6,
w, text_height, TINT_WHITE, SZ("Crossfade"),
100000, 0., 60., &sampler->crossfade);
- saw_ui_value_float(x, y0 + height - sample_height - text_height * 7,
+ saw_ui_value_float(x, y0 + height - sample_height - text_height * 5,
w, text_height, TINT_WHITE, SZ("Base freq."),
500, 1., 44100., &sampler->base_frequency);
- saw_ui_value_float(x, y0 + height - sample_height - text_height * 8,
+ saw_ui_value_float(x, y0 + height - sample_height - text_height * 6,
w, text_height, TINT_WHITE, SZ("Volume."), 10000,
0., 2., &sampler->volume);
@@ -1701,23 +1773,22 @@ static void saw_ui_sampler(saw_sampler_t *sampler, i64 x0, i64 y0,
nvgTextAlign(saw_nvg, NVG_ALIGN_LEFT | NVG_ALIGN_BASELINE);
nvgText(saw_nvg, x,
frame_height - y0 - height + sample_height +
- (text_height * 19) / 2,
+ (text_height * 15) / 2,
"Envelope", NULL);
- saw_ui_value_float(x,
- y0 + height - sample_height - text_height * 11,
+ saw_ui_value_float(x, y0 + height - sample_height - text_height * 9,
w, text_height, TINT_WHITE, SZ("Sustain"), 10000,
0., 1., &sampler->envelope.sustain);
saw_ui_value_float(x,
- y0 + height - sample_height - text_height * 12,
+ y0 + height - sample_height - text_height * 10,
w, text_height, TINT_WHITE, SZ("Attack"), 100000,
0., 6., &sampler->envelope.attack);
saw_ui_value_float(x,
- y0 + height - sample_height - text_height * 13,
+ y0 + height - sample_height - text_height * 11,
w, text_height, TINT_WHITE, SZ("Decay"), 100000,
0., 6., &sampler->envelope.decay);
saw_ui_value_float(x,
- y0 + height - sample_height - text_height * 14,
+ y0 + height - sample_height - text_height * 12,
w, text_height, TINT_WHITE, SZ("Release"),
100000, 0., 6., &sampler->envelope.release);
}
@@ -2555,14 +2626,12 @@ static void saw_init(void) {
sam->outline.values[i] = fabs(v[k] + v[k + 1]) * .5;
}
- i64 begin, end, tail, fade_in, fade_out, crossfade, bfreq,
- volume, sustain, attack, decay, release;
+ i64 begin, end, tail, crossfade, bfreq, volume, sustain,
+ attack, decay, release;
SCAN_(" begin %lld", 1, &begin);
SCAN_(" end %lld", 1, &end);
SCAN_(" tail %lld", 1, &tail);
- SCAN_(" fade_in %lld", 1, &fade_in);
- SCAN_(" fade_out %lld", 1, &fade_out);
SCAN_(" crossfade %lld", 1, &crossfade);
SCAN_(" base_frequency %lld", 1, &bfreq);
SCAN_(" volume %lld", 1, &volume);
@@ -2574,8 +2643,6 @@ static void saw_init(void) {
sam->begin = begin * .0001;
sam->end = end * .0001;
sam->tail = tail * .0001;
- sam->fade_in = fade_in * .0001;
- sam->fade_out = fade_out * .0001;
sam->crossfade = crossfade * .0001;
sam->base_frequency = bfreq * .0001;
sam->volume = volume * .0001;
@@ -2862,10 +2929,6 @@ static void saw_cleanup(void) {
(i64) floor(sam->end * 10000 + .5));
fprintf(f, "tail %lld\n",
(i64) floor(sam->tail * 10000 + .5));
- fprintf(f, "fade_in %lld\n",
- (i64) floor(sam->fade_in * 10000 + .5));
- fprintf(f, "fade_out %lld\n",
- (i64) floor(sam->fade_out * 10000 + .5));
fprintf(f, "crossfade %lld\n",
(i64) floor(sam->crossfade * 10000 + .5));
fprintf(f, "base_frequency %lld\n",