summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSamuel Johnson <[email protected]>2025-03-18 12:30:57 -0400
committerSamuel Johnson <[email protected]>2025-03-18 12:30:57 -0400
commitca7ee50998d59951d46647f0d45258f1a4c21b06 (patch)
treebe1c421b754df49dc756eb69ef70bbf468357067
parenta2f29c295d3ebbbe733b69de9f7e64a221d1ee25 (diff)
Add FM synth
-rw-r--r--mmband/api/adsr.h24
-rw-r--r--mmband/api/filter.h0
-rw-r--r--mmband/api/instrument.h39
-rw-r--r--mmband/api/lib.h14
-rw-r--r--mmband/instrument.c108
-rw-r--r--mmband/waves/none.c7
-rw-r--r--mmband/waves/saw.c6
-rw-r--r--mmband/waves/sine.c6
-rw-r--r--mmband/waves/square.c6
-rw-r--r--mmband/waves/triangle.c6
10 files changed, 189 insertions, 27 deletions
diff --git a/mmband/api/adsr.h b/mmband/api/adsr.h
index d9a9e1b..62b58d2 100644
--- a/mmband/api/adsr.h
+++ b/mmband/api/adsr.h
@@ -1,21 +1,23 @@
#ifndef MMBAND_ADSR_H
#define MMBAND_ADSR_H
+#include <mmband/api/lib.h>
+
typedef struct adsr *adsr_ref;
-adsr_ref adsr_new ();
-void adsr_free (adsr_ref adsr);
+MMAPI adsr_ref adsr_new ();
+MMAPI void adsr_free (adsr_ref adsr);
-void adsr_reset (adsr_ref adsr);
-void adsr_gate (adsr_ref adsr);
-float adsr_tick (adsr_ref adsr);
+MMAPI void adsr_reset (adsr_ref adsr);
+MMAPI void adsr_gate (adsr_ref adsr);
+MMAPI float adsr_tick (adsr_ref adsr);
-void adsr_set_attack (adsr_ref adsr, float attack_rate);
-void adsr_set_decay (adsr_ref adsr, float decay_rate);
-void adsr_set_sustain (adsr_ref adsr, float sustain_level);
-void adsr_set_release (adsr_ref adsr, float release_rate);
+MMAPI void adsr_set_attack (adsr_ref adsr, float attack_rate);
+MMAPI void adsr_set_decay (adsr_ref adsr, float decay_rate);
+MMAPI void adsr_set_sustain (adsr_ref adsr, float sustain_level);
+MMAPI void adsr_set_release (adsr_ref adsr, float release_rate);
-void adsr_set_asc_target (adsr_ref adsr, float target);
-void adsr_set_desc_target (adsr_ref adsr, float target);
+MMAPI void adsr_set_asc_target (adsr_ref adsr, float target);
+MMAPI void adsr_set_desc_target (adsr_ref adsr, float target);
#endif
diff --git a/mmband/api/filter.h b/mmband/api/filter.h
deleted file mode 100644
index e69de29..0000000
--- a/mmband/api/filter.h
+++ /dev/null
diff --git a/mmband/api/instrument.h b/mmband/api/instrument.h
index 3fd07da..bad0d48 100644
--- a/mmband/api/instrument.h
+++ b/mmband/api/instrument.h
@@ -1,17 +1,25 @@
#ifndef MMBAND_INSTRUMENT_H
#define MMBAND_INSTRUMENT_H
+#include <mmband/api/lib.h>
+
enum filter_type {
- FILTER_NONE = 0,
+ FILTER_NONE,
FILTER_LOWPASS,
FILTER_HIGHPASS,
- FILTER_NOTCH,
FILTER_LOWSHELF,
- FILTER_HIGHSHELF
+ FILTER_HIGHSHELF,
+ FILTER_NOTCH
+};
+
+enum algorithm {
+ ALGORITHM_NONE,
+ ALGORITHM_RING,
+ ALGORITHM_FREQUENCY
};
enum osc_type {
- OSC_NONE = 0,
+ OSC_NONE,
OSC_SINE,
OSC_SQUARE,
OSC_TRIANGLE,
@@ -21,18 +29,19 @@ enum osc_type {
// INSTRUMENT CREATION, TWEAKS
typedef struct instrument *instrument_ref;
-instrument_ref new_instrument ();
-void free_instrument (instrument_ref instrument);
-// int set_algorithm (instrument_ref instrument, enum algorithm alg);
-int ins_set_osc (instrument_ref instrument, enum osc_type osc);
-void ins_set_sample_rate (instrument_ref instrument, int sample_rate);
+MMAPI instrument_ref ins_new ();
+MMAPI void ins_free (instrument_ref instrument);
+// int ins_set_algorithm (instrument_ref instrument, enum algorithm alg);
+MMAPI void ins_set_carrier (instrument_ref instrument, enum osc_type osc);
+MMAPI void ins_set_modulator (instrument_ref instrument, enum osc_type osc);
+// void ins_set_filter (instrument_ref instrument, enum filter_type filter);
-// OUTPUT CREATION, TWEAKS
-struct audio_out {
- float left_phase;
- float right_phase;
-};
+MMAPI void ins_set_carrier_amplitude (instrument_ref instrument, float amplitude);
+MMAPI void ins_set_carrier_frequency (instrument_ref instrument, float amplitude);
+MMAPI void ins_set_modulator_amplitude (instrument_ref instrument, float amplitude);
+MMAPI void ins_set_frequency_ratio (instrument_ref instrument, float ratio);
+MMAPI void ins_set_frequency (instrument_ref instrument, float frequency);
-struct audio_out instrument_tick (instrument_ref instrument);
+MMAPI float ins_tick (instrument_ref instrument, int sample_rate);
#endif
diff --git a/mmband/api/lib.h b/mmband/api/lib.h
new file mode 100644
index 0000000..5c1f2f8
--- /dev/null
+++ b/mmband/api/lib.h
@@ -0,0 +1,14 @@
+#ifndef MMBAND_LIB_EXPORTS_H
+#define MMBAND_LIB_EXPORTS_H
+
+#if defined _WIN32
+#if defined mmband_EXPORTS
+#define MMAPI __declspec(dllexport)
+#else
+#define MMAPI __declspec(dllimport)
+#endif
+#else
+#define MMAPI
+#endif
+
+#endif
diff --git a/mmband/instrument.c b/mmband/instrument.c
index 96a8952..38c7d43 100644
--- a/mmband/instrument.c
+++ b/mmband/instrument.c
@@ -1,4 +1,110 @@
+#include <math.h>
+#include <stdlib.h>
+
#include <mmband/api/instrument.h>
#include <mmband/api/adsr.h>
-struct instrument { };
+#include <mmband/waves/waveform.h>
+
+struct oscillation {
+ enum osc_type type;
+
+ float frequency;
+ float phase;
+ float amplitude;
+};
+
+struct instrument {
+ struct oscillation carrier;
+ struct oscillation modulator;
+
+ float frequency_ratio;
+};
+
+float osc_tick (struct oscillation *osc, int sample_rate) {
+ float sample = 0.0;
+
+ switch (osc->type) {
+ case OSC_NONE:
+ sample = osc->amplitude * none(osc->phase);
+ break;
+ case OSC_SINE:
+ sample = osc->amplitude * sine(osc->phase);
+ break;
+ case OSC_SQUARE:
+ sample = osc->amplitude * square(osc->phase);
+ break;
+ case OSC_SAW:
+ sample = osc->amplitude * saw(osc->phase);
+ break;
+ case OSC_TRIANGLE:
+ sample = osc->amplitude * triangle(osc->phase);
+ break;
+ }
+
+ osc->phase = fmod(osc->phase + osc->frequency * 2.0 * M_PI / sample_rate, 2.0 * M_PI);
+ return sample;
+}
+
+// Currently default to ring modulation
+// TODO: add others
+float modulate (struct oscillation *carrier, struct oscillation *modulator, int sample_rate) {
+ return osc_tick(carrier, sample_rate) * osc_tick(modulator, sample_rate);
+}
+
+instrument_ref ins_new () {
+ instrument_ref instrument = malloc(sizeof(struct instrument));
+
+ instrument->frequency_ratio = 1.0;
+
+ instrument->carrier.type = OSC_SINE;
+ instrument->carrier.amplitude = 0.0;
+ instrument->carrier.frequency = 0.0;
+ instrument->carrier.phase = 0.0;
+
+ instrument->modulator.type = OSC_SINE;
+ instrument->carrier.amplitude = 0.0;
+ instrument->carrier.frequency = 0.0;
+ instrument->carrier.phase = 0.0;
+
+ return instrument;
+}
+
+void ins_free (instrument_ref instrument) {
+ free(instrument);
+}
+
+void ins_set_carrier (instrument_ref instrument, enum osc_type osc) {
+ instrument->carrier.type = osc;
+ instrument->carrier.amplitude = 0.0;
+ instrument->carrier.frequency = 0.0;
+ instrument->carrier.phase = 0.0;
+}
+
+void ins_set_modulator (instrument_ref instrument, enum osc_type osc) {
+ instrument->modulator.type = osc;
+ instrument->modulator.amplitude = 0.0;
+ instrument->modulator.frequency = 0.0;
+ instrument->modulator.phase = 0.0;
+}
+
+void ins_set_carrier_amplitude (instrument_ref instrument, float amplitude) {
+ instrument->carrier.amplitude = amplitude;
+}
+
+void ins_set_modulator_aplitude (instrument_ref instrument, float amplitude) {
+ instrument->modulator.amplitude = amplitude;
+}
+
+void ins_set_frequency_ratio (instrument_ref instrument, float frequency_ratio) {
+ instrument->frequency_ratio = frequency_ratio;
+}
+
+void ins_set_frequency (instrument_ref instrument, float frequency) {
+ instrument->carrier.frequency = frequency;
+ instrument->modulator.frequency = frequency * instrument->frequency_ratio;
+}
+
+float ins_tick (instrument_ref instrument, int sample_rate) {
+ return modulate(&instrument->carrier, &instrument->modulator, sample_rate);
+}
diff --git a/mmband/waves/none.c b/mmband/waves/none.c
index e69de29..110dc1c 100644
--- a/mmband/waves/none.c
+++ b/mmband/waves/none.c
@@ -0,0 +1,7 @@
+#include <mmband/waves/waveform.h>
+
+float zero (float phase) {
+ (void) phase;
+
+ return 0.0;
+}
diff --git a/mmband/waves/saw.c b/mmband/waves/saw.c
index e69de29..4ce7663 100644
--- a/mmband/waves/saw.c
+++ b/mmband/waves/saw.c
@@ -0,0 +1,6 @@
+#include <math.h>
+#include <mmband/waves/waveform.h>
+
+float saw (float phase) {
+ return -1.0 - (2.0 * fmod(phase / M_PI, 1.0));
+}
diff --git a/mmband/waves/sine.c b/mmband/waves/sine.c
index e69de29..52cf157 100644
--- a/mmband/waves/sine.c
+++ b/mmband/waves/sine.c
@@ -0,0 +1,6 @@
+#include <math.h>
+#include <mmband/waves/waveform.h>
+
+float sine (float phase) {
+ return sinf(phase);
+}
diff --git a/mmband/waves/square.c b/mmband/waves/square.c
index e69de29..97ad5e9 100644
--- a/mmband/waves/square.c
+++ b/mmband/waves/square.c
@@ -0,0 +1,6 @@
+#include <math.h>
+#include <mmband/waves/waveform.h>
+
+float square (float phase) {
+ return (phase <= M_PI) ? 1.0 : -1.0;
+}
diff --git a/mmband/waves/triangle.c b/mmband/waves/triangle.c
index e69de29..bf805ed 100644
--- a/mmband/waves/triangle.c
+++ b/mmband/waves/triangle.c
@@ -0,0 +1,6 @@
+#include <math.h>
+#include <mmband/waves/waveform.h>
+
+float triangle (float phase) {
+ return (acosf(sinf(phase))) / M_PI;
+}