summaryrefslogtreecommitdiffstats
path: root/src/synth_engine.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/synth_engine.c')
-rw-r--r--src/synth_engine.c260
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;
}