#include "synth_engine.h" #include "synth_math.h" #include "lowpass.h" #include "filter.h" #include "control.h" #include "sound.h" #include "osc.h" #include #include 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; icci; 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)); } synth_t * init_synth(void) { synth_t * synth = (synth_t *)malloc(sizeof(synth_t)); if (!synth) return NULL; 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 = (float *) calloc(sizeof(float), SAMPLE_RATE * 30); 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_bw_low_pass(synth->fff); free_bw_band_stop(synth->fff2); free(synth->del); free(synth); }