summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgramanas <anastasis.gramm2@gmail.com>2023-04-29 14:34:36 +0300
committergramanas <anastasis.gramm2@gmail.com>2023-04-29 14:34:36 +0300
commit402f6791150d503fc29ed75a7b8be9abfdd3867f (patch)
tree1061ae5cd2f9e1728b59a1ae6fbe0dfe8582c849
parente919ad41b01595d2cd8fb0771bd3542817ec1058 (diff)
downloadsynth-project-402f6791150d503fc29ed75a7b8be9abfdd3867f.tar.gz
synth-project-402f6791150d503fc29ed75a7b8be9abfdd3867f.tar.bz2
synth-project-402f6791150d503fc29ed75a7b8be9abfdd3867f.zip
midi cc
-rw-r--r--src/Makefile.am4
-rw-r--r--src/midi.c60
-rw-r--r--src/synth_engine.c260
-rw-r--r--src/synth_engine.h46
-rw-r--r--src/synth_gui.c30
-rw-r--r--src/synth_math.h36
6 files changed, 287 insertions, 149 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3aff1d3..c775183 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,7 +1,9 @@
#bin_PROGRAMS = food cookbook cook synth
bin_PROGRAMS = synth
-common_sources = filter.c \
+common_sources = adsr.c \
+ adsr.h \
+ filter.c \
filter.h \
lowpass.c \
lowpass.h \
diff --git a/src/midi.c b/src/midi.c
index e1797c8..0bd44a8 100644
--- a/src/midi.c
+++ b/src/midi.c
@@ -17,6 +17,9 @@ void midi_decode(uint32_t msg, synth_t * synth) {
if (synth->n.key == data1) {
synth->n.noteOff = Pa_GetStreamTime(synth->stream);
}
+
+ synth->midi_note[data1].noteOff = Pa_GetStreamTime(synth->stream);
+
break;
case 0x09:
printf("Note On: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
@@ -27,7 +30,17 @@ void midi_decode(uint32_t msg, synth_t * synth) {
synth->n.elapsed = 0;
synth->adsr.elapsed = 0;
synth->active = 1;
- synth->gain = data2 / 127.0;
+ //synth->gain = data2 / 127.0;
+
+
+ //synth->midi_note[i].n = -1;
+ synth->midi_note[data1].freq = notes[data1 % 12][(data1 / 12) % 8];
+ synth->midi_note[data1].channel = channel;
+ synth->midi_note[data1].noteOn = Pa_GetStreamTime(synth->stream);
+ synth->midi_note[data1].noteOff = 0;
+ synth->midi_note[data1].velocity = (float)data2 / 127.0;
+ synth->midi_note[data1].elapsed = 0;
+ synth->midi_note[data1].active = 1;
break;
case 0x0A:
@@ -35,6 +48,41 @@ void midi_decode(uint32_t msg, synth_t * synth) {
break;
case 0x0B:
printf("Control Change: channel=%d, controller=%d, value=%d\n", channel, data1, data2);
+ int x = data2 < 64 ? 1 : -1;
+ switch (data1) {
+ case 0:
+ synth->adsr.a = synth->adsr.a + (x * 0.01);
+ break;
+ case 1:
+ synth->adsr.d = synth->adsr.d + (x * 0.01);
+ break;
+ case 2:
+ synth->adsr.s = synth->adsr.s + (x * 0.01);
+ break;
+ case 3:
+ synth->adsr.r = synth->adsr.r + (x * 0.01);
+ break;
+ case 4:
+ synth->cutoff = synth->cutoff + (x * (10 * log10(synth->cutoff)));
+ break;
+ case 5:
+ synth->resonance = synth->resonance + (x * 0.02);
+ break;
+ case 6:
+ synth->lfo.freq = synth->lfo.freq + (x * 0.1);
+ break;
+ case 7:
+ synth->lfo.amp = synth->lfo.amp + (x * 0.002);
+ break;
+ break;
+ case 28:
+ synth->filter = x - 1;
+ break;
+ case 29:
+ synth->multi = x - 1;
+ break;
+ default:
+ }
break;
case 0x0C:
printf("Program Change: channel=%d, program=%d\n", channel, data1);
@@ -44,6 +92,7 @@ void midi_decode(uint32_t msg, synth_t * synth) {
break;
case 0x0E:
printf("Pitch Bend: channel=%d, value=%d\n", channel, ((data2 << 7) | data1) - 8192);
+ synth->n.freq = (((data2 << 7) | data1) - 8192);
break;
default:
printf("Unknown MIDI message\n");
@@ -58,10 +107,15 @@ midiCallback(PtTimestamp timestamp, void *userData) {
if (!m->stream) return;
- if (!Pm_Poll(m->stream)) return;
+ // if (!Pm_Poll(m->stream)) return;
PmEvent buf;
- Pm_Read(m->stream, &buf, 1);
+ int e = Pm_Read(m->stream, &buf, 1);
+ if (e == 0) return; // nothing to do
+ if (e < 0) {
+ printf("Pm_Read error %d\n", e);
+ return;
+ }
//printf("%d\n", buf.message);
midi_decode(buf.message, m->synth);
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;
}
diff --git a/src/synth_engine.h b/src/synth_engine.h
index b88f3d5..a434b53 100644
--- a/src/synth_engine.h
+++ b/src/synth_engine.h
@@ -8,29 +8,30 @@
#include "notes.h"
#include "filter.h"
+#include "adsr.h"
-#define SAMPLE_RATE (44100)
-//#define SAMPLE_RATE (48000)
+//#define SAMPLE_RATE (44100)
+#define SAMPLE_RATE (48000)
#define FRAMES_PER_BUFFER (210)
+#define VIZ_BUF 1024
+
#define WIDTH 1024
#define HEIGHT 600
+#define MIDI_NOTES 128
+
#ifndef M_PI
#define M_PI (3.14159265)
#endif
-
-typedef struct {
- float a;
- float peak;
- float d;
- float s;
- float r;
+typedef struct lfo_t {
+ float freq;
+ float amp;
unsigned long long elapsed;
-} adsr_t;
+} lfo_t;
-typedef struct {
+typedef struct note_t {
float freq;
PaTime noteOn;
PaTime noteOff;
@@ -38,9 +39,20 @@ typedef struct {
unsigned long long elapsed;
} note_t;
-typedef struct {
+typedef struct midi_note_t {
+ float freq;
+ int channel;
+ PaTime noteOn;
+ PaTime noteOff;
+ float velocity; // normalized
+ unsigned long long elapsed;
+ adsr_t * adsr;
+ int active;
+} midi_note_t;
+
+typedef struct viz_t {
int sample_rate_divider;
- float wave[1000200];
+ float wave[VIZ_BUF];
int wi;
} viz_t;
@@ -51,9 +63,13 @@ typedef struct {
float gain;
float x;
+ midi_note_t midi_note[MIDI_NOTES];
+
note_t n;
adsr_t adsr;
+ lfo_t lfo;
+
int octave;
int poly;
@@ -75,11 +91,11 @@ typedef struct {
viz_t viz;
} synth_t;
-float adsr_amplitude(void *synthData, unsigned long long elapsed);
float make_sample(unsigned long long phase, void *synthData, unsigned int sample_rate, int viz);
void init_synth(synth_t * synth);
void free_synth(synth_t * synth);
-int sound_gen(const void *inputBuffer, void *outputBuffer,
+int sound_gen(const void *inputBuffer,
+ void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
diff --git a/src/synth_gui.c b/src/synth_gui.c
index fc4e5fa..2405d57 100644
--- a/src/synth_gui.c
+++ b/src/synth_gui.c
@@ -34,15 +34,26 @@ keyboard(void *synthData, PaStream *stream)
note = notes[i % 12][(synth->octave + (i / 12)) % 8];
if (note) {
set_note(synth, note, Pa_GetStreamTime(stream), keys[i]);
+
//printf("Note On : %s[%d] %fHz\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8, note);
+ synth->midi_note[i].freq = 16.35 * pow(2, (synth->octave + i / 12.0)); //notes[i % 12][(synth->octave + (i / 12)) % 8];
+ //synth->midi_note[i].freq = notes[i % 12][(synth->octave + (i / 12)) % 8];
+ synth->midi_note[i].channel = -1;
+ synth->midi_note[i].noteOn = Pa_GetStreamTime(synth->stream);
+ synth->midi_note[i].noteOff = 0;
+ synth->midi_note[i].velocity = 1.0;
+ synth->midi_note[i].elapsed = 0;
+ synth->midi_note[i].active = 1;
}
}
}
for (int i = 0; keys[i]; i++) {
if (IsKeyReleased(keys[i])) {
+ synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream);
note = notes[i % 12][(synth->octave + (i / 12)) % 8];
if (synth->n.key == keys[i]) {
synth->n.noteOff = Pa_GetStreamTime(stream);
+ synth->midi_note[i].noteOff = Pa_GetStreamTime(synth->stream);
//printf("Note Off: %s[%d]\n", int_to_note(i % 12), (synth->octave + (i / 12)) % 8);
}
}
@@ -69,6 +80,10 @@ draw_adsr_sliders(synth_t * synth, int x, int y, int width, int height, int offs
synth->cutoff = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "fC: ", buf, synth->cutoff , 0.0f, 11000.0f);
snprintf(buf, sizeof buf, "%.3f", synth->resonance);
synth->resonance = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "fR: ", buf, synth->resonance , 0.001f, 5.0f);
+ snprintf(buf, sizeof buf, "%.3f", synth->lfo.freq);
+ synth->lfo.freq = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "lfo freq: ", buf, synth->lfo.freq , 0.001f, 10.0f);
+ snprintf(buf, sizeof buf, "%.3f", synth->lfo.amp);
+ synth->lfo.amp = GuiSliderBar((Rectangle){ x, y + count++ * (height + offset), width, height }, "lfo amprrrrrr: ", buf, synth->lfo.amp , 0.0f, 0.93f);
}
void
@@ -81,25 +96,26 @@ draw_signals(synth_t * synth, int x, int y, int width, int height)
GuiSpinner((Rectangle){ x+ 100, y - 24 - 6, 100, 24 }, "rate divider: ", &(synth->viz.sample_rate_divider), 1, 10, 0);
int period = (1 / (synth->n.freq + 1)) * SAMPLE_RATE / synth->viz.sample_rate_divider;
+
for (int i = x; i < WIDTH - x; i++) {
- DrawCircle(i , y + height / 2 + floor(50 * synth->viz.wave[x * (SAMPLE_RATE / 2)]), point_radius, MAGENTA);
+ DrawCircle(i , y + height / 2 + floor(250 * synth->viz.wave[i - x]), point_radius, MAGENTA);
}
if (synth->multi) {
for (int i = x; i < WIDTH - x; i++) {
- DrawCircle(i , y + height / 2 + floor(50 * make_sample(i - x, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED);
+ //DrawCircle(i , y + height / 2 + floor(50 * make_sample(i - x, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED);
}
} else {
for (int i = x; i < WIDTH - x; i++) {
- DrawCircle(i , y + height / 2 + floor(50 * make_sample((i - x) % period, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED);
+ //DrawCircle(i , y + height / 2 + floor(50 * make_sample((i - x) % period, synth, SAMPLE_RATE / synth->viz.sample_rate_divider, 1)), point_radius, RED);
}
}
for (int i = x; i < WIDTH - x; i++) {
- DrawCircle(i , y + height - 1+ floor((WIDTH / 24) * - adsr_amplitude(synth, synth->adsr.elapsed)), point_radius, GREEN);
+ //DrawCircle(i , y + height - 1+ floor((WIDTH / 24) * - adsr_amplitude(synth, synth->adsr.elapsed, synth->n.noteOn, synth->n.noteOff)), point_radius, GREEN);
}
float adsr_duration = synth->adsr.a + synth->adsr.d + (synth->adsr.a + synth->adsr.d + synth->adsr.r) / 3.0 + synth->adsr.r;
for (int i = x; i < WIDTH - x; i++) {
- DrawCircle(i , y + height - 1 + floor((WIDTH / 24) * - adsr_amplitude(synth, (i - x) * (adsr_duration * SAMPLE_RATE) / WIDTH)), point_radius, BLUE);
+ //DrawCircle(i , y + height - 1 + floor((WIDTH / 24) * - adsr_amplitude(synth, (i - x) * (adsr_duration * SAMPLE_RATE) / WIDTH, synth->n.noteOn, synth->n.noteOff)), point_radius, BLUE);
}
}
@@ -124,7 +140,7 @@ rayrun(void *synthData)
// Draw
//----------------------------------------------------------------------------------
BeginDrawing();
- ClearBackground(RAYWHITE);
+ ClearBackground(BLACK);
// GUI
char buf[64];
@@ -166,7 +182,7 @@ rayrun(void *synthData)
DrawText("THE SYNTH!!!!!!!!!!!!!!!!!!1", WIDTH / 2 - 100, 50, 20, LIGHTGRAY);
DrawText("KEYBOARD: Q .. ] TOGGLE MULTI: ENTER", WIDTH / 2 -300, HEIGHT - 20 - 50, 20, LIGHTGRAY);
- snprintf(buf, sizeof buf, "time?: %lld adsr: %lld note: %lld", synth->adsr.elapsed / SAMPLE_RATE, synth->adsr.elapsed, synth->n.elapsed);
+ snprintf(buf, sizeof buf, "%f", synth->viz.wave[0]);
DrawText(buf, WIDTH / 2 -300, HEIGHT - 40 - 50, 20, LIGHTGRAY);
EndDrawing();
diff --git a/src/synth_math.h b/src/synth_math.h
index de6fb26..74dec4c 100644
--- a/src/synth_math.h
+++ b/src/synth_math.h
@@ -1,8 +1,10 @@
#ifndef SYNTH_MATH_H
#define SYNTH_MATH_H
-extern long long
-gcd(long long int a, long long int b)
+#include <stddef.h>
+
+static long long
+gcd(long long a, long long b)
{
long long rem;
rem=a-(a/b*b);
@@ -13,10 +15,36 @@ gcd(long long int a, long long int b)
}
// Function to return LCM of two numbers
-extern long long
+static long long
lcm(long long a, long long b)
{
return (a / gcd(a, b)) * b;
}
-
+
+static float
+clamp(float f)
+{
+ if (f <= -1) return -0.9999;
+ if (f >= 1) return 0.9999;
+ return f;
+}
+
+/* 1d convolution */
+static 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];
+ }
+ }
+}
+
#endif /* SYNTH_MATH_H */