summaryrefslogtreecommitdiffstats
path: root/src/synth_engine_v2.c
diff options
context:
space:
mode:
authorgramanas <anastasis.gramm2@gmail.com>2023-11-26 16:29:00 +0200
committergramanas <anastasis.gramm2@gmail.com>2023-11-26 16:29:00 +0200
commit8d17aa29baf0b33229dbdd82d8d5f6cbe3fe0240 (patch)
treebc4ec3351f8585b548ddf016c93d3715b324b64c /src/synth_engine_v2.c
parentc03d395f6848fe9b2d1185173a9cf5ec8277394f (diff)
downloadsynth-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.c448
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, &note_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);
+}