diff options
author | gramanas <anastasis.gramm2@gmail.com> | 2023-04-29 14:34:36 +0300 |
---|---|---|
committer | gramanas <anastasis.gramm2@gmail.com> | 2023-04-29 14:34:36 +0300 |
commit | 402f6791150d503fc29ed75a7b8be9abfdd3867f (patch) | |
tree | 1061ae5cd2f9e1728b59a1ae6fbe0dfe8582c849 /src/synth_engine.c | |
parent | e919ad41b01595d2cd8fb0771bd3542817ec1058 (diff) | |
download | synth-project-402f6791150d503fc29ed75a7b8be9abfdd3867f.tar.gz synth-project-402f6791150d503fc29ed75a7b8be9abfdd3867f.tar.bz2 synth-project-402f6791150d503fc29ed75a7b8be9abfdd3867f.zip |
midi cc
Diffstat (limited to 'src/synth_engine.c')
-rw-r--r-- | src/synth_engine.c | 260 |
1 files changed, 141 insertions, 119 deletions
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 <string.h> -/* 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; i<framesPerBuffer; i++ ) { - //get_portaudio_frame(outputBuffer, synth); if (!synth->active) { *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; i<MIDI_NOTES; i++) { + 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; + 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; } |