diff options
author | gramanas <anastasis.gramm2@gmail.com> | 2023-11-26 16:29:00 +0200 |
---|---|---|
committer | gramanas <anastasis.gramm2@gmail.com> | 2023-11-26 16:29:00 +0200 |
commit | 8d17aa29baf0b33229dbdd82d8d5f6cbe3fe0240 (patch) | |
tree | bc4ec3351f8585b548ddf016c93d3715b324b64c /src/synth_engine_v2.c | |
parent | c03d395f6848fe9b2d1185173a9cf5ec8277394f (diff) | |
download | synth-project-8d17aa29baf0b33229dbdd82d8d5f6cbe3fe0240.tar.gz synth-project-8d17aa29baf0b33229dbdd82d8d5f6cbe3fe0240.tar.bz2 synth-project-8d17aa29baf0b33229dbdd82d8d5f6cbe3fe0240.zip |
Many changes!
Diffstat (limited to 'src/synth_engine_v2.c')
-rw-r--r-- | src/synth_engine_v2.c | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/src/synth_engine_v2.c b/src/synth_engine_v2.c new file mode 100644 index 0000000..726839f --- /dev/null +++ b/src/synth_engine_v2.c @@ -0,0 +1,448 @@ +#include "synth_engine.h" +#include "synth_math.h" +#include "lowpass.h" +#include "filter.h" +#include "control.h" +#include "sound.h" +#include "osc.h" + +#include <string.h> +#include <time.h> + +float +gen0(float f, midi_note_t * midi_note, float x, unsigned int sample_rate) +{ + float sample = osc_sin(midi_note->wvt_index); + midi_note->wvt_index = osc_sin_next(f, midi_note->wvt_index); + return sample; +} + +float +gen1(float f, midi_note_t * midi_note, float x, unsigned int sample_rate) +{ + float sample = osc_saw(midi_note->wvt_index); + midi_note->wvt_index = osc_saw_next(f, midi_note->wvt_index); + return sample; +} + +float +gen2(float f, midi_note_t * midi_note, float x, unsigned int sample_rate) +{ + float sample = osc_weird(midi_note->wvt_index); + midi_note->wvt_index = osc_weird_next(f, midi_note->wvt_index); + return sample; +} + +float +gen3(float f, midi_note_t * midi_note, float x, unsigned int sample_rate) +{ + float sample = osc_tri(midi_note->wvt_index); + midi_note->wvt_index = osc_tri_next(f, midi_note->wvt_index); + return sample; +} + +float +gen4(float f, midi_note_t * midi_note, float x, unsigned int sample_rate) +{ + float sample = osc_sound(midi_note->wvt_index); + midi_note->wvt_index = osc_sound_next(f, midi_note->wvt_index); + return sample; +} + +float +gen5(float f, midi_note_t * midi_note, float x, unsigned int sample_rate) +{ + float sample = osc_digisaw(midi_note->wvt_index); + midi_note->wvt_index = osc_digisaw_next(f, midi_note->wvt_index); + return sample; +} + +float +gen6(float f, midi_note_t * midi_note, float x, unsigned int sample_rate) +{ + float sample = osc_sqr(midi_note->wvt_index); + midi_note->wvt_index = osc_sqr_next(f, midi_note->wvt_index); + return sample; +} + +void deactivate_midi_note(midi_note_t * note) +{ + note->freq = 0; + note->channel = -1; + note->noteOn = -1; + note->noteOff = -1; + note->wvt_index = 0; + note->lfo_index = 0; + note->velocity = -1; + note->elapsed = -1; + note->noteOffSample = 0; + note->active = 0; +} + +int +notes_active(synth_t *synth) +{ + midi_note_t * note; + int j; + for (int i = 0; i < synth->midi_active_n; i++) { + note = synth->midi_active[i]; + if (!fix_adsr(&synth->adsr, + (float)note->noteOn, + (float)note->noteOff, + note->elapsed, + note->noteOffSample) + && note->noteOff != 0) { + deactivate_midi_note(note); + j = i + 1; + for (; j < synth->midi_active_n; j++) { + synth->midi_active[j - 1] = synth->midi_active[j]; + } + synth->midi_active[j - 1] = NULL; + synth->midi_active_n--; + } + } + + return synth->midi_active_n; +} + +#define CC_GET(name) cc_iget(&synth->cc_##name, frame, FRAMES_PER_BUFFER) + +float prev_sample = 0.0f; + +float +do_fliter(synth_t *synth, float *sample, unsigned int sample_rate, int frame) +{ + if (synth->filter) { + // ALLL THE FILTERS + float cutoff = CC_GET(cutoff); + float reso = CC_GET(resonance); + + if (cutoff == 0) cutoff = 0.001; + lpf_update(reso, cutoff, sample_rate); + *sample = lpf_filter(*sample); + + update_bw_low_pass_filter(synth->fff, SAMPLE_RATE, cutoff, reso); + *sample = bw_low_pass(synth->fff, *sample); + } +} + +float +get_max_sample(synth_t *synth, int test_size) +{ + float osc_wave[test_size]; + for (int i = 0; i < test_size; i++) { + osc_wave[i] = 0; + } + + for (int i = 0; i < synth->midi_active_n; i++) { + midi_note_t * note = synth->midi_active[i]; + midi_note_t note_dup; + note_dup.freq = note->freq; + note_dup.channel = note->channel; + note_dup.noteOn = note->noteOn; + note_dup.noteOff = note->noteOff; + note_dup.velocity = note->velocity; + note_dup.wvt_index = 0; + note_dup.lfo_index = note->lfo_index; + note_dup.elapsed = note->elapsed; + note_dup.noteOffSample = note->noteOffSample; + note_dup.adsr = note->adsr; + note_dup.active = note->active; + for (int i = 0; i < test_size; i++) { + osc_wave[i] += synth->gen[synth->geni](note_dup.freq * 3, ¬e_dup, synth->x, SAMPLE_RATE); + } + } + + float max = 0; + for (int i = 0; i < test_size; i++) { + if (fabs(osc_wave[i]) > max) max = fabs(osc_wave[i]); + } + + return max; +} + +float +make_sample(synth_t * synth, unsigned int sample_rate, int frame) +{ + float sample = 0.0f; + midi_note_t * note; + + if (synth->midi_active_n == 0) return sample; + + float rms = 0; + for (int i = 0; i < synth->midi_active_n; i++) { + rms += synth->midi_active[i]->velocity * synth->midi_active[i]->velocity; + } + + rms = sqrt(rms / (float)synth->midi_active_n); + + //float max = get_max_sample(synth, 20); + + for (int i = 0; i < synth->midi_active_n; i++) { + note = synth->midi_active[i]; + float adsr = fix_adsr(&synth->adsr, + note->noteOn, + note->noteOff, + note->elapsed, + note->noteOffSample); + + float targ_freq = note->freq * CC_GET(pitch); + targ_freq = targ_freq + targ_freq * CC_GET(lfo_amp) * osc_sin(note->lfo_index); + + note->lfo_index = osc_sin_next(CC_GET(lfo_freq), note->lfo_index); + + sample += rms * note->velocity * adsr * synth->gen[synth->geni](targ_freq, + note, + synth->x, + sample_rate); + } + + /* filter */ + do_fliter(synth, &sample, sample_rate, frame); + + sample = synth->gain * sample; + + // band stop for high freqs + //sample = bw_band_stop(synth->fff2, sample); + + if (synth->clamp) sample = clamp(sample, -1, 1); + //printf("CLICK! %f\n", fabsf(prev_sample) - fabsf(sample)); + //if (fabsf(fabsf(prev_sample) - fabsf(sample)) > 0.03) printf("CLICK! (diff: %f)\n", fabsf(prev_sample) - fabsf(sample)); + prev_sample = sample; + return sample; +} + +void +add_to_delay(synth_t *synth, float sample) +{ + synth->del[synth->deli++] = sample; + + if (synth->deli >= SAMPLE_RATE * 10) { + synth->deli = 0; + } +} + +void +increment_synth(synth_t *synth) +{ + synth->lfo.elapsed++; + synth->adsr.elapsed++; + + for (int i = 0; i < synth->midi_active_n; i++) { + if (synth->midi_active[i]) + synth->midi_active[i]->elapsed++; + } +} + +void +get_frame(void *outputBuffer, synth_t *synth, int i) +{ + float *out = (float*)outputBuffer + 2 * i; + float s = 0.0f; + + + if (!notes_active(synth)) { + synth->active = 0; + } + + if (!synth->delay) { + synth->counter = 0; + } + + s = make_sample(synth, SAMPLE_RATE, i); + synth->counter++; + if (synth->counter >= (int)(synth->del_time * SAMPLE_RATE * 10)) { + int idx = (synth->deli - (int)(synth->del_time * SAMPLE_RATE * 10)) % (SAMPLE_RATE * 10); + float tmp; + if (idx >= 0) { + tmp = synth->del[idx]; + } else { + tmp = synth->del[SAMPLE_RATE * 10 + idx]; + } + + s = clamp(s + synth->del_feedback * tmp, -1, 1); + } + + add_to_delay(synth, s); + *out++ = s; + *out++ = s; + + // move time + increment_synth(synth); + + // viz + PaUtil_WriteRingBuffer(&synth->viz.wave_buffer, &s, 1); +} + + +int +sound_gen(const void *inputBuffer, void *outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void *synthData) +{ + synth_t *synth = (synth_t*)synthData; + float *out = (float*)outputBuffer; + + float buffer[2 * FRAMES_PER_BUFFER]; + float buffer2[2 * FRAMES_PER_BUFFER]; + + (void) timeInfo; + (void) statusFlags; + (void) inputBuffer; + + clock_t begin = clock(); + + // get_changes(); + for (int i = 0; i < synth->cci; i++) { + cc_prep(synth->ccs[i]); + } + // fill buffer + for( unsigned long i=0; i<framesPerBuffer; i++ ) { + // use iget inside + get_frame(buffer, synth, i); + } + + // output buffer + for( unsigned long i=0; i<framesPerBuffer * 2; i += 2 ) { + // use iget inside + *out++ = buffer[i]; + *out++ = buffer[i+1]; + } + // finalize_changes(); + for (int i = 0; i < synth->cci; i++) { + cc_fix(synth->ccs[i]); + } + + clock_t end = clock(); + double time_spent = (double)(end - begin) / CLOCKS_PER_SEC; + if (time_spent > (double)FRAMES_PER_BUFFER / SAMPLE_RATE) { + printf("To generate %d samples per second we need to generate a sample every 1 / %d second. Since we generate samples by batching them in groups of %d, each group should take longer than %f. This one took %f\n", SAMPLE_RATE, SAMPLE_RATE, FRAMES_PER_BUFFER, (float)FRAMES_PER_BUFFER / SAMPLE_RATE, time_spent); + } + + return paContinue; +} + +void +m_init_synth(synth_t * synth) +{ + synth = (synth_t *)malloc(sizeof(synth_t)); + +} + +void +init_synth(synth_t * synth) +{ + synth->cci = 0; + CC(synth->cc_cutoff, "cutoff", 10, 22000, 30, 5000); + CC(synth->cc_resonance, "resonance", 1, 10, .02, 1); + CC(synth->cc_lfo_freq, "lfo_freq", 1, 1000, 2, 1); + CC(synth->cc_lfo_amp, "lfo_amp", 0, 1, .01f, 0); + CC(synth->cc_pitch, "pitch", -3, 4, 0.01f, 1); + CC(synth->cc_adsr_a, "attack", 0, 3, 0.05f, 0.00); + CC(synth->cc_adsr_d, "decay", 0, 2, 0.05f, 0.3); + CC(synth->cc_adsr_s, "sustain", 0, 1.0f, 0.05f, 0.7f); + CC(synth->cc_adsr_r, "release", 0, 5, 0.05f, 0.2f); + + synth->modi = 0; + + synth->gain = 0.5; + synth->x = 1; + + synth->adsr.a = 0.00001f; + synth->adsr.peak = 1.0f; + synth->adsr.d = 0.3; + synth->adsr.s = 0.7; + synth->adsr.r = 0.4; + synth->adsr.elapsed = 0; + + synth->lfo.freq = 1.0f; + synth->lfo.amp = 0.0f; + synth->lfo.elapsed = 0; + + synth->midi_active_n = 0; + for (int i = 0; i < MIDI_NOTES; i++) { + synth->midi_active[i] = NULL; + 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].wvt_index = 0; + synth->midi_note[i].lfo_index = 0; + synth->midi_note[i].adsr = &(synth->adsr); + } + + synth->octave = 3; + + synth->delay = 0; + synth->del[SAMPLE_RATE * 10]; + synth->deli = 0; + synth->del_time = .1; + synth->del_feedback = 0.5f; + synth->counter; + + synth->filter = 1; + synth->clamp = 1; + + synth->gen[0] = gen0; + synth->gen[1] = gen1; + synth->gen[2] = gen2; + synth->gen[3] = gen3; + synth->gen[4] = gen4; + synth->gen[5] = gen5; + synth->gen[6] = gen6; + synth->geni = 3; + + synth->active = 0; + + lpf_init(); + synth->fff = create_bw_low_pass_filter(2, SAMPLE_RATE, 400); + synth->fff2 = create_bw_band_stop_filter(8, SAMPLE_RATE, 15000, 22000); + + init_sound(synth, sound_gen); + + synth->osctri = make_tri("triangle"); + + synth->viz.rate_divider = 15; +// for (int i = 0; i < RING_SIZE; i++) synth->viz.wave_buffer_data[i] = 0; + synth->viz.wave_buffer_data = (float *)calloc(sizeof(float), RING_SIZE); + PaUtil_InitializeRingBuffer(&synth->viz.wave_buffer, sizeof(float), RING_SIZE, synth->viz.wave_buffer_data); +// for (int i = 0; i < RING_SIZE; i++) synth->viz.fft_buffer_data[i] = 0; + synth->viz.fft_buffer_data = (float *)calloc(sizeof(float), RING_SIZE); + PaUtil_InitializeRingBuffer(&synth->viz.fft_buffer, sizeof(float), RING_SIZE, synth->viz.fft_buffer_data); + + synth->viz.tmp_buffer = (float *)calloc(sizeof(float), RING_SIZE * 8); + synth->viz.wave_viz_buffer = (float *)calloc(sizeof(float), RING_SIZE * 8); + synth->viz.fft_input_buffer = (float *)calloc(sizeof(float), RING_SIZE * 8); + synth->viz.fft_output_buffer = (float *)calloc(sizeof(float), RING_SIZE * 8); + synth->viz.fft_smooth_buffer = (float *)calloc(sizeof(float), RING_SIZE * 8); + + synth->viz.spectrum_enabled = 1; + synth->viz.wave_enabled = 0; + synth->viz.adsr_enabled = 0; + synth->viz.osc_enabled = 0; + synth->viz.freeze = 0; + synth->viz.tmp_index = 0; +} + +void +free_synth(synth_t * synth) +{ + destroy_sound(synth); + + free(synth->viz.wave_buffer_data); + free(synth->viz.fft_buffer_data); + free(synth->viz.tmp_buffer); + free(synth->viz.wave_viz_buffer); + free(synth->viz.fft_input_buffer); + free(synth->viz.fft_output_buffer); + free(synth->viz.fft_smooth_buffer); + + //free(synth->ring_data); + free_bw_low_pass(synth->fff); + free_bw_band_stop(synth->fff2); +} |