From 402f6791150d503fc29ed75a7b8be9abfdd3867f Mon Sep 17 00:00:00 2001 From: gramanas Date: Sat, 29 Apr 2023 14:34:36 +0300 Subject: midi cc --- src/Makefile.am | 4 +- src/midi.c | 60 ++++++++++++- src/synth_engine.c | 260 +++++++++++++++++++++++++++++------------------------ src/synth_engine.h | 46 ++++++---- src/synth_gui.c | 30 +++++-- src/synth_math.h | 36 +++++++- 6 files changed, 287 insertions(+), 149 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 3aff1d3..c775183 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,9 @@ #bin_PROGRAMS = food cookbook cook synth bin_PROGRAMS = synth -common_sources = filter.c \ +common_sources = adsr.c \ + adsr.h \ + filter.c \ filter.h \ lowpass.c \ lowpass.h \ diff --git a/src/midi.c b/src/midi.c index e1797c8..0bd44a8 100644 --- a/src/midi.c +++ b/src/midi.c @@ -17,6 +17,9 @@ void midi_decode(uint32_t msg, synth_t * synth) { if (synth->n.key == data1) { synth->n.noteOff = Pa_GetStreamTime(synth->stream); } + + synth->midi_note[data1].noteOff = Pa_GetStreamTime(synth->stream); + break; case 0x09: printf("Note On: channel=%d, note=%d, velocity=%d\n", channel, data1, data2); @@ -27,7 +30,17 @@ void midi_decode(uint32_t msg, synth_t * synth) { synth->n.elapsed = 0; synth->adsr.elapsed = 0; synth->active = 1; - synth->gain = data2 / 127.0; + //synth->gain = data2 / 127.0; + + + //synth->midi_note[i].n = -1; + synth->midi_note[data1].freq = notes[data1 % 12][(data1 / 12) % 8]; + synth->midi_note[data1].channel = channel; + synth->midi_note[data1].noteOn = Pa_GetStreamTime(synth->stream); + synth->midi_note[data1].noteOff = 0; + synth->midi_note[data1].velocity = (float)data2 / 127.0; + synth->midi_note[data1].elapsed = 0; + synth->midi_note[data1].active = 1; break; case 0x0A: @@ -35,6 +48,41 @@ void midi_decode(uint32_t msg, synth_t * synth) { break; case 0x0B: printf("Control Change: channel=%d, controller=%d, value=%d\n", channel, data1, data2); + int x = data2 < 64 ? 1 : -1; + switch (data1) { + case 0: + synth->adsr.a = synth->adsr.a + (x * 0.01); + break; + case 1: + synth->adsr.d = synth->adsr.d + (x * 0.01); + break; + case 2: + synth->adsr.s = synth->adsr.s + (x * 0.01); + break; + case 3: + synth->adsr.r = synth->adsr.r + (x * 0.01); + break; + case 4: + synth->cutoff = synth->cutoff + (x * (10 * log10(synth->cutoff))); + break; + case 5: + synth->resonance = synth->resonance + (x * 0.02); + break; + case 6: + synth->lfo.freq = synth->lfo.freq + (x * 0.1); + break; + case 7: + synth->lfo.amp = synth->lfo.amp + (x * 0.002); + break; + break; + case 28: + synth->filter = x - 1; + break; + case 29: + synth->multi = x - 1; + break; + default: + } break; case 0x0C: printf("Program Change: channel=%d, program=%d\n", channel, data1); @@ -44,6 +92,7 @@ void midi_decode(uint32_t msg, synth_t * synth) { break; case 0x0E: printf("Pitch Bend: channel=%d, value=%d\n", channel, ((data2 << 7) | data1) - 8192); + synth->n.freq = (((data2 << 7) | data1) - 8192); break; default: printf("Unknown MIDI message\n"); @@ -58,10 +107,15 @@ midiCallback(PtTimestamp timestamp, void *userData) { if (!m->stream) return; - if (!Pm_Poll(m->stream)) return; + // if (!Pm_Poll(m->stream)) return; PmEvent buf; - Pm_Read(m->stream, &buf, 1); + int e = Pm_Read(m->stream, &buf, 1); + if (e == 0) return; // nothing to do + if (e < 0) { + printf("Pm_Read error %d\n", e); + return; + } //printf("%d\n", buf.message); midi_decode(buf.message, m->synth); diff --git a/src/synth_engine.c b/src/synth_engine.c index 11586da..6710ff6 100644 --- a/src/synth_engine.c +++ b/src/synth_engine.c @@ -1,79 +1,10 @@ #include "synth_engine.h" +#include "synth_math.h" #include "lowpass.h" #include "filter.h" #include -/* 1d convolution */ -void -convole(float *signal, float *filter, size_t signal_size, size_t filter_size, float *out) { - for (size_t i = 0; i < filter_size + signal_size; i++) { - size_t kmin, kmax, k; - out[i] = 0; - /* find overlap */ - kmin = (i >= filter_size - 1) ? i - (filter_size - 1) : 0; - kmax = (i < signal_size - 1) ? i : signal_size - 1; - - /* Add the overlaping values */ - for (k = kmin; k <= kmax; k++) { - out[i] += signal[k] * filter[i - k]; - } - } -} - -float -clamp(float f) -{ - if (f <= -1) return -0.9999; - if (f >= 1) return 0.9999; - return f; -} - -float -adsr_amplitude(void *synthData, unsigned long long elapsed) -{ - synth_t *synth = (synth_t*)synthData; - - float dAmplitude = 0.0; - float dReleaseAmplitude = 0.0; - float dStartAmplitude = synth->adsr.peak; - - float dLifeTime = (elapsed * (1.0 / (float)SAMPLE_RATE)); - - if (synth->n.noteOn != 0 && synth->n.noteOff == 0) { - if (dLifeTime < synth->adsr.a) - dAmplitude = (dLifeTime / synth->adsr.a)*(dLifeTime / synth->adsr.a) * dStartAmplitude; - - if (dLifeTime >= synth->adsr.a && dLifeTime <= ( synth->adsr.a + synth->adsr.d)) - dAmplitude = ((dLifeTime - synth->adsr.a) / synth->adsr.d) * (synth->adsr.s - dStartAmplitude) + dStartAmplitude; - - if (dLifeTime > (synth->adsr.a + synth->adsr.d)) - dAmplitude = synth->adsr.s; - } - else { // Note is off - if (dLifeTime < synth->adsr.a) - dReleaseAmplitude = (dLifeTime / synth->adsr.a)*(dLifeTime / synth->adsr.a) * dStartAmplitude; - - if (dLifeTime >= synth->adsr.a && dLifeTime <= (synth->adsr.a + synth->adsr.d)) - dReleaseAmplitude = ((dLifeTime - synth->adsr.a) / synth->adsr.d) * (synth->adsr.s - dStartAmplitude) + dStartAmplitude; - - if (dLifeTime > (synth->adsr.a + synth->adsr.d)) - dReleaseAmplitude = synth->adsr.s; - - dAmplitude = (((synth->n.noteOn + dLifeTime) - synth->n.noteOff) / synth->adsr.r) * (0.0 - dReleaseAmplitude) + dReleaseAmplitude; - - if (synth->adsr.r < 0) { - dAmplitude = synth->adsr.s; - } - } - // Amplitude should not be negative - if (dAmplitude <= 0.000) - dAmplitude = 0.0; - - return clamp(dAmplitude); -} - - float sin_sample(float amp, float freq, unsigned long long phase, unsigned int sample_rate) { @@ -108,22 +39,24 @@ sqr_sample(float amp, float freq, float duty_cycle, unsigned long long phase, un float gen0(float f, unsigned long long phase, float x, unsigned int sample_rate) { - return sqr_sample(0.1, f, 0.3, phase, sample_rate) - + sqr_sample(0.1, f * 3.0 / 2.0 , 0.5, phase, sample_rate) - + saw_sample(0.3, f, phase, sample_rate) - + sin_sample(0.1, f, phase, sample_rate) - + sin_sample(0.1, f * 5, phase, sample_rate) - /* + sin_sample(0.1, freq * 50 * 1021, phase, sample_rate) */ - /* + sin_sample(0.1, freq * 50 * 3531021, phase, sample_rate) */ - + sin_sample(0.1, f * 7, phase, sample_rate); + return sin_sample(1, f, phase, sample_rate); + /* return sqr_sample(0.1, f, 0.3, phase, sample_rate) */ + /* + sqr_sample(0.1, f * 3.0 / 2.0 , 0.5, phase, sample_rate) */ + /* + saw_sample(0.3, f, phase, sample_rate) */ + /* + sin_sample(0.1, f, phase, sample_rate) */ + /* + sin_sample(0.1, f * 5, phase, sample_rate) */ + /* /\* + sin_sample(0.1, freq * 50 * 1021, phase, sample_rate) *\/ */ + /* /\* + sin_sample(0.1, freq * 50 * 3531021, phase, sample_rate) *\/ */ + /* + sin_sample(0.1, f * 7, phase, sample_rate); */ } float gen1(float f, unsigned long long phase, float x, unsigned int sample_rate) { - return sawX_sample(0.5, f, 5, phase, sample_rate) - + saw_sample(0.3, 2 * f / 5, phase, sample_rate) - + sin_sample(0.2, f * 5.0 / 7.0 , phase, sample_rate); + return saw_sample(1, f, phase, sample_rate); + /* return sawX_sample(0.5, f, 5, phase, sample_rate) */ + /* + saw_sample(0.3, 2 * f / 5, phase, sample_rate) */ + /* + sin_sample(0.2, f * 5.0 / 7.0 , phase, sample_rate); */ } float @@ -132,17 +65,52 @@ gen2(float f, unsigned long long phase, float x, unsigned int sample_rate) /* return sin_sample(0.5, f * sqrt(2) , phase, sample_rate) */ /* + sin_sample(0.5, f, phase, sample_rate); */ - return sawX_sample(1, f, 5, phase, sample_rate); + return sawX_sample(1, f, 15, phase, sample_rate); } float gen3(float f, unsigned long long phase, float x, unsigned int sample_rate) { + return sqr_sample(1, f, .5, phase, sample_rate); /* return sawX_sample(0.7, f, 5, phase, sample_rate) */ /* + sin_sample(0.3, 4.0/17.0*f, phase, sample_rate); */ - return saw_sample(0.5, f * (1 + sqrt(5)) / 2, phase, sample_rate) - + sin_sample(0.3, f * x, phase, sample_rate) - + sqr_sample(0.2, f * x, 0.2 * x * x, phase, sample_rate); + /* return saw_sample(0.5, f * (1 + sqrt(5)) / 2, phase, sample_rate) */ + /* + sin_sample(0.3, f * x, phase, sample_rate) */ + /* + sqr_sample(0.2, f * x, 0.2 * x * x, phase, sample_rate); */ +} + +float +lfo(float f, unsigned long long phase, unsigned int sample_rate) { + return sin_sample(1, f, phase, sample_rate); +} + +int +notes_active(synth_t *synth) +{ + int flag = 0; + + for (int i = 0; i < MIDI_NOTES; i++) { + if (!synth->midi_note[i].active) + continue; + + if (!adsr_amplitude(&synth->adsr, + (float)synth->midi_note[i].noteOn, + (float)synth->midi_note[i].noteOff, + (float)synth->midi_note[i].elapsed) + && synth->midi_note[i].noteOff != 0) { + synth->midi_note[i].freq = 0; + synth->midi_note[i].channel = -1; + synth->midi_note[i].noteOn = -1; + synth->midi_note[i].noteOff = -1; + synth->midi_note[i].velocity = -1; + synth->midi_note[i].elapsed = -1; + synth->midi_note[i].active = 0; + } else { + flag++; + } + } + + return flag; } float @@ -151,37 +119,64 @@ make_sample(unsigned long long phase, void *synthData, unsigned int sample_rate, synth_t *synth = (synth_t*)synthData; float sample = 0; - //LFO! - //if (synth->adsr.elapsed > SAMPLE_RATE / 2) synth->adsr.elapsed = 0; + /* should never be 0 if we are here */ - /* int n = synth->actual_notes_active; */ - /* for (int i = 0; i < n; i++) { */ - /* sample += (1.0 / n) * synth->gen[synth->geni](synth->actual_freq[i] + synth->freq_offset, synth->actual_freq_count[i], synth->x, sample_rate); */ - /* } */ - sample = synth->gen[synth->geni](synth->n.freq + synth->freq_offset, phase, synth->x, sample_rate); + /* Notes */ + float n = notes_active(synth); + float rms = 0; + for (int i = 0; i < MIDI_NOTES; i++) { + if (!synth->midi_note[i].active) + continue; + + rms += synth->midi_note[i].velocity * synth->midi_note[i].velocity; + } + + rms = sqrt(rms / n); - if (!viz && synth->filter) { + for (int i = 0; i < MIDI_NOTES; i++) { + if (!synth->midi_note[i].active) + continue; + + sample += 0.2 * rms + * adsr_amplitude(&synth->adsr, (float)synth->midi_note[i].noteOn, (float)synth->midi_note[i].noteOff, (float)synth->midi_note[i].elapsed) + * synth->gen[synth->geni](synth->midi_note[i].freq + synth->midi_note[i].freq * synth->freq_offset, synth->midi_note[i].elapsed, synth->x, sample_rate); + } + + /* filter */ + if (synth->filter) { // ALLL THE FILTERS - LowPass_Update(synth->resonance, (adsr_amplitude(synth, synth->adsr.elapsed) + 0.1) * round(synth->cutoff) + 1, sample_rate); + float cutoff = round(synth->cutoff) + 1; + + cutoff = cutoff + cutoff * (synth->lfo.amp) * lfo(synth->lfo.freq, synth->lfo.elapsed, sample_rate); + + if (cutoff == 0) cutoff = 0.001; + LowPass_Update(synth->resonance, cutoff, sample_rate); sample = LowPass_Filter(sample); - update_bw_low_pass_filter(synth->fff, SAMPLE_RATE, (adsr_amplitude(synth, synth->adsr.elapsed) + 0.1) * synth->cutoff, synth->resonance); + update_bw_low_pass_filter(synth->fff, SAMPLE_RATE,cutoff, synth->resonance); sample = bw_low_pass(synth->fff, sample); } - sample = synth->gain * adsr_amplitude(synth, synth->adsr.elapsed) * sample; - + sample = synth->gain * sample; // band stop for high freqs - if (!viz) - sample = bw_band_stop(synth->fff2, sample); - + sample = bw_band_stop(synth->fff2, sample); if (synth->clamp) sample = clamp(sample); return sample; } +void +add_to_viz(synth_t *synth, float sample) +{ + synth->viz.wave[synth->viz.wi++] = sample; + + if (synth->viz.wi >= VIZ_BUF) { + synth->viz.wi = 0; + } +} + int sound_gen(const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, @@ -192,23 +187,28 @@ sound_gen(const void *inputBuffer, void *outputBuffer, synth_t *synth = (synth_t*)synthData; float *out = (float*)outputBuffer; - (void) timeInfo; /* Prevent unused variable warnings. */ + (void) timeInfo; (void) statusFlags; (void) inputBuffer; float s = 0.0f; for( unsigned long i=0; iactive) { *out++ = 0.0f; *out++ = 0.0f; + + add_to_viz(synth, 0.0f); + + synth->lfo.elapsed = 0; continue; } - if (adsr_amplitude(synth, synth->adsr.elapsed) == 0 && synth->n.noteOff != 0) { + if (!notes_active(synth)) { + //if (adsr_amplitude(synth, synth->adsr.elapsed, synth->n.noteOn, synth->n.noteOff) == 0 && synth->n.noteOff != 0) { synth->active = 0; *out++ = 0.0f; *out++ = 0.0f; + add_to_viz(synth, 0.0f); continue; } @@ -216,17 +216,24 @@ sound_gen(const void *inputBuffer, void *outputBuffer, *out++ = s; *out++ = s; + synth->lfo.elapsed++; synth->adsr.elapsed++; synth->n.elapsed++; - if (!synth->multi) { - if (synth->n.elapsed >= (1.0 / synth->n.freq) * SAMPLE_RATE) synth->n.elapsed = 0; - } else { + /* if (!synth->multi) { */ + /* if (synth->n.elapsed >= (1.0 / synth->n.freq) * SAMPLE_RATE) synth->n.elapsed = 0; */ + /* } else { */ + /* } */ + + for (int i = 0; i < MIDI_NOTES; i++) { + if (!synth->midi_note[i].active) + continue; + + synth->midi_note[i].elapsed++; } - synth->viz.wi >= 1000199 ? synth->viz.wi = 0 : synth->viz.wi++; - synth->viz.wave[synth->viz.wi] = s; - synth->viz.wi >= 1000199 ? synth->viz.wi = 0 : synth->viz.wi++; - synth->viz.wave[synth->viz.wi] = s; + + // viz + add_to_viz(synth, s); } return paContinue; @@ -246,12 +253,6 @@ init_synth(synth_t * synth) synth->gain = 1; synth->x = 1; - synth->n.freq = 0; - synth->n.noteOn = 0; - synth->n.noteOff = 1; - synth->n.key = 0; - synth->n.elapsed = 0; - synth->adsr.a = 0.0; synth->adsr.peak = 1.0f; synth->adsr.d = 0.3; @@ -259,11 +260,32 @@ init_synth(synth_t * synth) synth->adsr.r = 0.4; synth->adsr.elapsed = 0; + synth->lfo.freq = 1.0f; + synth->lfo.amp = 0.0f; + synth->lfo.elapsed = 0; + + for (int i =0; imidi_note[i].freq = 0; + synth->midi_note[i].channel = -1; + synth->midi_note[i].noteOn = -1; + synth->midi_note[i].noteOff = -1; + synth->midi_note[i].velocity = -1; + synth->midi_note[i].elapsed = -1; + synth->midi_note[i].active = 0; + synth->midi_note[i].adsr = &(synth->adsr); + } + + synth->n.freq = 0; + synth->n.noteOn = 0; + synth->n.noteOff = 1; + synth->n.key = 0; + synth->n.elapsed = 0; + synth->octave = 3; synth->poly = 0; synth->multi = 0; - synth->filter = 0; + synth->filter = 1; synth->cutoff = 22000.0f; synth->resonance = 1.0f; synth->clamp = 1; @@ -289,9 +311,9 @@ init_synth(synth_t * synth) const PaDeviceInfo *deviceInfo; for( i=0; i< Pa_GetDeviceCount(); i++ ) { deviceInfo = Pa_GetDeviceInfo( i ); - //if (!strcmp("HyperX Cloud II Wireless: USB Audio (hw:0,0)", deviceInfo->name)) break; + if (!strcmp("HyperX Cloud II Wireless: USB Audio (hw:2,0)", deviceInfo->name)) break; printf("dev: %s || %f\n", deviceInfo->name, deviceInfo->defaultSampleRate); - if (!strcmp("HDA Intel PCH: ALC1220 Analog (hw:0,0)", deviceInfo->name)) break; + //if (!strcmp("HDA Intel PCH: ALC1220 Analog (hw:0,0)", deviceInfo->name)) break; } diff --git a/src/synth_engine.h b/src/synth_engine.h index b88f3d5..a434b53 100644 --- a/src/synth_engine.h +++ b/src/synth_engine.h @@ -8,29 +8,30 @@ #include "notes.h" #include "filter.h" +#include "adsr.h" -#define SAMPLE_RATE (44100) -//#define SAMPLE_RATE (48000) +//#define SAMPLE_RATE (44100) +#define SAMPLE_RATE (48000) #define FRAMES_PER_BUFFER (210) +#define VIZ_BUF 1024 + #define WIDTH 1024 #define HEIGHT 600 +#define MIDI_NOTES 128 + #ifndef M_PI #define M_PI (3.14159265) #endif - -typedef struct { - float a; - float peak; - float d; - float s; - float r; +typedef struct lfo_t { + float freq; + float amp; unsigned long long elapsed; -} adsr_t; +} lfo_t; -typedef struct { +typedef struct note_t { float freq; PaTime noteOn; PaTime noteOff; @@ -38,9 +39,20 @@ typedef struct { unsigned long long elapsed; } note_t; -typedef struct { +typedef struct midi_note_t { + float freq; + int channel; + PaTime noteOn; + PaTime noteOff; + float velocity; // normalized + unsigned long long elapsed; + adsr_t * adsr; + int active; +} midi_note_t; + +typedef struct viz_t { int sample_rate_divider; - float wave[1000200]; + float wave[VIZ_BUF]; int wi; } viz_t; @@ -51,9 +63,13 @@ typedef struct { float gain; float x; + midi_note_t midi_note[MIDI_NOTES]; + note_t n; adsr_t adsr; + lfo_t lfo; + int octave; int poly; @@ -75,11 +91,11 @@ typedef struct { viz_t viz; } synth_t; -float adsr_amplitude(void *synthData, unsigned long long elapsed); float make_sample(unsigned long long phase, void *synthData, unsigned int sample_rate, int viz); void init_synth(synth_t * synth); void free_synth(synth_t * synth); -int sound_gen(const void *inputBuffer, void *outputBuffer, +int sound_gen(const void *inputBuffer, + void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, diff --git a/src/synth_gui.c b/src/synth_gui.c index fc4e5fa..2405d57 100644 --- a/src/synth_gui.c +++ b/src/synth_gui.c @@ -34,15 +34,26 @@ keyboard(void *synthData, PaStream *stream) note = notes[i % 12][(synth->octave + (i / 12)) % 8]; if (note) { set_note(synth, note, Pa_GetStreamTime(stream), keys[i]); + //printf("Note On : %s[%d] %fHz\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8, note); + synth->midi_note[i].freq = 16.35 * pow(2, (synth->octave + i / 12.0)); //notes[i % 12][(synth->octave + (i / 12)) % 8]; + //synth->midi_note[i].freq = notes[i % 12][(synth->octave + (i / 12)) % 8]; + synth->midi_note[i].channel = -1; + synth->midi_note[i].noteOn = Pa_GetStreamTime(synth->stream); + synth->midi_note[i].noteOff = 0; + synth->midi_note[i].velocity = 1.0; + synth->midi_note[i].elapsed = 0; + synth->midi_note[i].active = 1; } } } for (int i = 0; keys[i]; i++) { if (IsKeyReleased(keys[i])) { + synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream); note = notes[i % 12][(synth->octave + (i / 12)) % 8]; if (synth->n.key == keys[i]) { synth->n.noteOff = Pa_GetStreamTime(stream); + synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream); //printf("Note Off: %s[%d]\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8); } } @@ -69,6 +80,10 @@ draw_adsr_sliders(synth_t * synth, int x, int y, int width, int height, int offs synth->cutoff = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "fC: ", buf, synth->cutoff , 0.0f, 11000.0f); snprintf(buf, sizeof buf, "%.3f", synth->resonance); synth->resonance = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "fR: ", buf, synth->resonance , 0.001f, 5.0f); + snprintf(buf, sizeof buf, "%.3f", synth->lfo.freq); + synth->lfo.freq = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "lfo freq: ", buf, synth->lfo.freq , 0.001f, 10.0f); + snprintf(buf, sizeof buf, "%.3f", synth->lfo.amp); + synth->lfo.amp = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "lfo amprrrrrr: ", buf, synth->lfo.amp , 0.0f, 0.93f); } void @@ -81,25 +96,26 @@ draw_signals(synth_t * synth, int x, int y, int width, int height) GuiSpinner((Rectangle){ x+ 100, y - 24 - 6, 100, 24 }, "rate divider: ", &(synth->viz.sample_rate_divider), 1, 10, 0); int period = (1 / (synth->n.freq + 1)) * SAMPLE_RATE / synth->viz.sample_rate_divider; + for (int i = x; i < WIDTH - x; i++) { - DrawCircle(i , y + height / 2 + floor(50 * synth->viz.wave[x * (SAMPLE_RATE / 2)]), point_radius, MAGENTA); + DrawCircle(i , y + height / 2 + floor(250 * synth->viz.wave[i - x]), point_radius, MAGENTA); } if (synth->multi) { for (int i = x; i < WIDTH - x; i++) { - DrawCircle(i , y + height / 2 + floor(50 * make_sample(i - x, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED); + //DrawCircle(i , y + height / 2 + floor(50 * make_sample(i - x, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED); } } else { for (int i = x; i < WIDTH - x; i++) { - DrawCircle(i , y + height / 2 + floor(50 * make_sample((i - x) % period, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED); + //DrawCircle(i , y + height / 2 + floor(50 * make_sample((i - x) % period, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED); } } for (int i = x; i < WIDTH - x; i++) { - DrawCircle(i , y + height - 1+ floor((WIDTH / 24) * - adsr_amplitude(synth, synth->adsr.elapsed)), point_radius, GREEN); + //DrawCircle(i , y + height - 1+ floor((WIDTH / 24) * - adsr_amplitude(synth, synth->adsr.elapsed, synth->n.noteOn, synth->n.noteOff)), point_radius, GREEN); } float adsr_duration = synth->adsr.a + synth->adsr.d + (synth->adsr.a + synth->adsr.d + synth->adsr.r) / 3.0 + synth->adsr.r; for (int i = x; i < WIDTH - x; i++) { - DrawCircle(i , y + height - 1 + floor((WIDTH / 24) * - adsr_amplitude(synth, (i - x) * (adsr_duration * SAMPLE_RATE) / WIDTH)), point_radius, BLUE); + //DrawCircle(i , y + height - 1 + floor((WIDTH / 24) * - adsr_amplitude(synth, (i - x) * (adsr_duration * SAMPLE_RATE) / WIDTH, synth->n.noteOn, synth->n.noteOff)), point_radius, BLUE); } } @@ -124,7 +140,7 @@ rayrun(void *synthData) // Draw //---------------------------------------------------------------------------------- BeginDrawing(); - ClearBackground(RAYWHITE); + ClearBackground(BLACK); // GUI char buf[64]; @@ -166,7 +182,7 @@ rayrun(void *synthData) DrawText("THE SYNTH!!!!!!!!!!!!!!!!!!1", WIDTH / 2 - 100, 50, 20, LIGHTGRAY); DrawText("KEYBOARD: Q .. ] TOGGLE MULTI: ENTER", WIDTH / 2 -300, HEIGHT - 20 - 50, 20, LIGHTGRAY); - snprintf(buf, sizeof buf, "time?: %lld adsr: %lld note: %lld", synth->adsr.elapsed / SAMPLE_RATE, synth->adsr.elapsed, synth->n.elapsed); + snprintf(buf, sizeof buf, "%f", synth->viz.wave[0]); DrawText(buf, WIDTH / 2 -300, HEIGHT - 40 - 50, 20, LIGHTGRAY); EndDrawing(); diff --git a/src/synth_math.h b/src/synth_math.h index de6fb26..74dec4c 100644 --- a/src/synth_math.h +++ b/src/synth_math.h @@ -1,8 +1,10 @@ #ifndef SYNTH_MATH_H #define SYNTH_MATH_H -extern long long -gcd(long long int a, long long int b) +#include + +static long long +gcd(long long a, long long b) { long long rem; rem=a-(a/b*b); @@ -13,10 +15,36 @@ gcd(long long int a, long long int b) } // Function to return LCM of two numbers -extern long long +static long long lcm(long long a, long long b) { return (a / gcd(a, b)) * b; } - + +static float +clamp(float f) +{ + if (f <= -1) return -0.9999; + if (f >= 1) return 0.9999; + return f; +} + +/* 1d convolution */ +static void +convole(float *signal, float *filter, + size_t signal_size, size_t filter_size, float *out) { + for (size_t i = 0; i < filter_size + signal_size; i++) { + size_t kmin, kmax, k; + out[i] = 0; + /* find overlap */ + kmin = (i >= filter_size - 1) ? i - (filter_size - 1) : 0; + kmax = (i < signal_size - 1) ? i : signal_size - 1; + + /* Add the overlaping values */ + for (k = kmin; k <= kmax; k++) { + out[i] += signal[k] * filter[i - k]; + } + } +} + #endif /* SYNTH_MATH_H */ -- cgit v1.2.3