summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Makefile.am10
-rw-r--r--src/generator.c70
-rw-r--r--src/gtk.c78
-rw-r--r--src/lowpass.c2
-rw-r--r--src/midi.c9
-rw-r--r--src/synth.c4
-rw-r--r--src/synth_engine.c62
-rw-r--r--src/synth_engine.h3
-rw-r--r--src/synth_gui.c3
9 files changed, 215 insertions, 26 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 6e75352..45ac871 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,5 +1,5 @@
#bin_PROGRAMS = food cookbook cook synth
-bin_PROGRAMS = synth
+bin_PROGRAMS = synth gtk
common_sources = adsr.c \
adsr.h \
@@ -32,6 +32,8 @@ common_sources = adsr.c \
synth_gui.h \
synth_math.h
+gtk_sources =
+
# -fwhole-program allows cross-file inlining, but only works when you put all
# the source files on one gcc command-line. -flto is another way to get the
# same effect. (Link-Time Optimization). clang supports -flto but not
@@ -45,7 +47,11 @@ common_sources = adsr.c \
AM_CFLAGS = -O3 -march=native -fno-math-errno -funroll-loops -flto -pthread
synth_SOURCES = synth.c $(common_sources)
-synth_LDADD = -lportaudio -lrt -lm -lasound -lraylib -lportmidi -ljack -lfftw3f -lsndfile
+synth_LDADD = -lportaudio -lrt -lm -lasound -lraylib -lportmidi -ljack -lfftw3f -lsndfile -lconfig
+
+gtk_SOURCES = gtk.c $(common_sources) $(gtk_sources)
+gtk_LDADD = -lportaudio -lrt -lm -lasound -lraylib -lportmidi -ljack -lfftw3f -lsndfile -lconfig -lgtk-4 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -lgdk_pixbuf-2.0 -lcairo-gobject -lcairo -lgraphene-1.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0
+gtk_CFLAGS = -I/usr/include/gtk-4.0 -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/sysprof-6 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/fribidi -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/graphene-1.0 -I/usr/lib/graphene-1.0/include -mfpmath=sse -msse -msse2 -pthread
#cookbook_SOURCES = cookbook.c $(common_sources)
#cookbook_SOURCES = cookbook.c $(common_sources)
#cook_SOURCES = cook.c $(common_sources)
diff --git a/src/generator.c b/src/generator.c
index 4e81297..ab2206f 100644
--- a/src/generator.c
+++ b/src/generator.c
@@ -1,16 +1,76 @@
+#include <libconfig.h>
+
#include "generator.h"
float
-generate(generator * g, synth_t * s, int i)
+generate(generator * g, synth_t * s, int i, sound_node * root)
{
float sample = 0;
- float f = get_frequency(g, s, i);'
-
- sample = osc_saw(midi_note->wvt_index);
- midi_note->wvt_index = osc_saw_next(f, midi_note->wvt_index);
+ sampe = play_tree(root, s->midi_note[i]);
return sample;
}
+
+int
+sound_tree_add_node(sound_node * root, const char * cmp)
+{
+
+}
+
+int
+load_preset(sound_node * tree, const char * path)
+{
+ config_t cfg;
+ config_setting_t *setting, *x;
+ const char *str;
+
+ config_init(&cfg);
+ if (! config_read_file(&cfg, "../preset.synth")) {
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
+ config_error_line(&cfg), config_error_text(&cfg));
+ config_destroy(&cfg);
+ return(EXIT_FAILURE);
+ }
+ setting = config_lookup(&cfg, "patch");
+ if (setting != NULL) {
+ int count = config_setting_length(setting);
+
+ for(int i = 0; i < count; ++i) {
+ x = config_setting_get_elem(setting, i);
+ printf("%s = %f\n", config_setting_name(x), config_setting_get_float(x));
+ // TODO
+ sound_tree_add_node(tree, name);
+ }
+ }
+
+
+ setting = config_tree_setting(&cfg);
+ if (setting != NULL) {
+ int count = config_setting_length(setting);
+
+ for(int i = 0; i < count; ++i) {
+ chat * name = config_setting_name(x);
+ x = config_setting_get_elem(setting, i);
+ printf("%s -- %d\n", config_setting_name(x), config_setting_type(x));
+
+ if (name[0] == 'o') { // osc
+ // TODO
+ configure_osc(tree, id);
+ } else if (name[0] == 'a') { // adsr
+ // TODO
+ configure_adsr(tree, id);
+ } else if (name[0] == 'l') { // lfo
+ // TODO
+ configure_lfo(tree, id);
+ } else {
+ printf("%s: wrong!", name);
+ }
+ }
+ }
+
+ config_destroy(&cfg);
+
+}
diff --git a/src/gtk.c b/src/gtk.c
new file mode 100644
index 0000000..2b91b94
--- /dev/null
+++ b/src/gtk.c
@@ -0,0 +1,78 @@
+/*
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com/
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/* audio */
+#include <string.h>
+#include <portaudio.h>
+
+#include <portmidi.h>
+
+/* graphics */
+#include <gtk-4.0/gtk/gtk.h>
+
+/* synth */
+#include "synth_engine.h"
+#include "midi.h"
+
+#define NUM_SECONDS (1)
+
+#define WAVE_SIZE (44100)
+
+static void
+activate (GtkApplication* app,
+ gpointer user_data)
+{
+ GtkWidget *window;
+
+ window = gtk_application_window_new (app);
+ gtk_window_set_title (GTK_WINDOW (window), "Synth");
+ gtk_window_set_default_size (GTK_WINDOW (window), WIDTH, HEIGHT);
+ gtk_window_present (GTK_WINDOW (window));
+}
+
+
+int
+main(int argc, char * argv[]) {
+ synth_t synth;
+ midi_t midi;
+
+ init_synth(&synth);
+ init_midi(&midi, &synth);
+
+ GtkApplication *app;
+ int status;
+
+ app = gtk_application_new ("org.gtk.example", G_APPLICATION_DEFAULT_FLAGS);
+ g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
+ status = g_application_run (G_APPLICATION (app), argc, argv);
+ g_object_unref (app);
+
+ // rayrun(&synth);
+
+ terminate_midi(&midi);
+ free_synth(&synth);
+
+ return status;
+}
diff --git a/src/lowpass.c b/src/lowpass.c
index ccb41dd..0ec53be 100644
--- a/src/lowpass.c
+++ b/src/lowpass.c
@@ -181,6 +181,8 @@ signed char lpf_init()
void lpf_close()
{
+ if (iir.coef)
+ free(iir.coef);
}
diff --git a/src/midi.c b/src/midi.c
index c01b803..e711ecb 100644
--- a/src/midi.c
+++ b/src/midi.c
@@ -14,12 +14,12 @@ void midi_decode(uint32_t msg, synth_t * synth) {
switch (message) {
case 0x08:
- // printf("Note Off: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
+ printf("Note Off: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
synth->midi_note[data1].noteOff = Pa_GetStreamTime(synth->stream);
synth->midi_note[data1].noteOffSample = synth->midi_note[data1].elapsed;
break;
case 0x09:
- // printf("Note On: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
+ printf("Note On: channel=%d, note=%d, velocity=%d\n", channel, data1, data2);
//synth->midi_note[i].n = -1;
synth->midi_note[data1].freq = notes[data1 % 12][(data1 / 12) % 8];
synth->midi_note[data1].channel = channel;
@@ -127,9 +127,10 @@ init_midi(midi_t *m, synth_t *synth)
info = Pm_GetDeviceInfo(i);
printf("%d: %s [input: %d output: %d opened: %d is_virt:%d] (interf: %s) -- %d\n", i, info->name, info->input, info->output, info->opened, info->is_virtual, info->interf, Pm_GetDefaultInputDeviceID());
//if (!strcmp("MPK225 MIDI", info->name) && !info->input) break;
- //if (!strcmp("MPK225 Port A", info->name) && info->input == 1) break;
+ if (!strcmp("MPK225 Port A", info->name) && info->input == 1) break;
//if (!strcmp("CH345 MIDI 1", info->name) && info->input == 1) break;
- if (!strcmp("Midi Through Port-0", info->name) && info->input == 1) break;
+ //if (!strcmp("Midi Through Port-0", info->name) && info->input == 1) break;
+ //if (!strcmp("DigitalKBD MIDI 1", info->name) && info->input == 1) break;
}
Pt_Start(1, midiCallback, m);
diff --git a/src/synth.c b/src/synth.c
index 1113a56..ea4a8f7 100644
--- a/src/synth.c
+++ b/src/synth.c
@@ -30,18 +30,16 @@
#include <portmidi.h>
/* graphics */
+#include "synth_gui.h"
/* synth */
#include "synth_engine.h"
-#include "synth_gui.h"
#include "midi.h"
#define NUM_SECONDS (1)
#define WAVE_SIZE (44100)
-
-
int
main(void) {
synth_t synth;
diff --git a/src/synth_engine.c b/src/synth_engine.c
index 517f9d8..b47d510 100644
--- a/src/synth_engine.c
+++ b/src/synth_engine.c
@@ -167,8 +167,9 @@ make_sample(void *synthData, unsigned int sample_rate, int frame)
// if rms == 0 we can deduce there are no notes however notes_active handles
// stopping any already playing notes and if we remove it we need to make
- // sure that notes stop some other way (it laso happens every frame)
- rms = sqrt(rms / n);
+ // sure that notes stop some other way (it also happens every frame)
+ rms = sqrt(rms / (float)n);
+ // printf("rms %f\n", rms);
for (int i = 0; i < MIDI_NOTES; i++) {
if (!synth->midi_note[i].active)
@@ -195,7 +196,7 @@ make_sample(void *synthData, unsigned int sample_rate, int frame)
synth->x,
sample_rate);
- sample += rms * adsr * synth_sample;
+ sample += synth->midi_note[i].velocity * adsr * synth_sample;
}
/* filter */
@@ -234,6 +235,16 @@ add_to_viz(synth_t *synth, float sample)
}
void
+add_to_fftviz(synth_t *synth, float sample)
+{
+ synth->fftviz.wave[synth->fftviz.wi++] = sample;
+
+ if (synth->fftviz.wi >= VIZ_BUF) {
+ synth->fftviz.wi = 0;
+ }
+}
+
+void
add_to_delay(synth_t *synth, float sample)
{
synth->del[synth->deli++] = sample;
@@ -304,7 +315,30 @@ get_frame(void *outputBuffer, synth_t *synth, int i)
#include "fftw3.h"
int
-process(float * buffer)
+get_spectrum(synth_t * synth, float * buffer)
+{
+ int fft_output_len = FRAMES_PER_BUFFER / 2 + 1;
+ float input[FRAMES_PER_BUFFER];
+
+ for( unsigned long i=0; i < FRAMES_PER_BUFFER * 2; i += 2 ) {
+ input[i / 2] = buffer[i];
+ }
+ fftwf_complex* output = (fftwf_complex*)fftwf_malloc(sizeof(fftwf_complex) * fft_output_len);
+
+ fftwf_plan forward_plan = fftwf_plan_dft_r2c_1d(fft_output_len, input, output, FFTW_ESTIMATE);
+
+ fftwf_execute(forward_plan);
+
+ for (int i=0; i < fft_output_len - 2*fft_output_len/3; i++ ) {
+ add_to_fftviz(synth, sqrt(output[i][0] * output[i][0] + output[i][1] * output[i][1]));
+ }
+
+ fftwf_destroy_plan(forward_plan);
+ fftwf_free(output);
+}
+
+int
+process(synth_t * synth, float * buffer)
{
int len = FRAMES_PER_BUFFER;
@@ -322,6 +356,8 @@ process(float * buffer)
fftwf_execute(forward_plan);
+ // cont:
+ /* printf("ASDASD!!!\n"); */
/* for (int i=0; i < (len / 2 + 1); i++ ) { */
/* if (frequency_signal[i][0] > 1) { */
/* frequency_signal[i][0] = 0; */
@@ -329,15 +365,16 @@ process(float * buffer)
/* if (frequency_signal[i][1] > 1) { */
/* frequency_signal[i][1] = 0; */
/* } */
- /* printf("%f %f | ", sqrt(frequency_signal[i][0] * frequency_signal[i][0] + frequency_signal[i][1] * frequency_signal[i][1]), atan2(frequency_signal[i][1], frequency_signal[i][0])); */
+ /* printf("%f %f | \n", sqrt(frequency_signal[i][0] * frequency_signal[i][0] + frequency_signal[i][1] * frequency_signal[i][1]), atan2(frequency_signal[i][1], frequency_signal[i][0])); */
- /* float f = atan2(frequency_signal[i][1], frequency_signal[i][0]); */
- /* if (f > M_PI / 2 && f < 2 * M_PI / 3) { */
- /* frequency_signal[i][0] = 0.0; */
- /* frequency_signal[i][1] = 0.0; */
- /* } */
+ /* /\* float f = atan2(frequency_signal[i][1], frequency_signal[i][0]); *\/ */
+ /* /\* if (f > M_PI / 2 && f < 2 * M_PI / 3) { *\/ */
+ /* /\* frequency_signal[i][0] = 0.0; *\/ */
+ /* /\* frequency_signal[i][1] = 0.0; *\/ */
+ /* /\* } *\/ */
/* } */
+ /* printf("ASDASD!!!\n"); */
fftwf_execute(backward_plan);
for (unsigned long i=0; i < len * 2; i += 2) {
@@ -401,7 +438,8 @@ sound_gen(const void *inputBuffer, void *outputBuffer,
get_frame(buffer, synth, i);
}
// process buffer
- //if (synth->multi) process(buffer);
+ // process(synth, buffer);
+ get_spectrum(synth, buffer);
// output buffer
for( unsigned long i=0; i<framesPerBuffer * 2; i += 2 ) {
@@ -481,6 +519,8 @@ init_synth(synth_t * synth)
synth->viz.sample_rate_divider = 1;
synth->viz.wi = 0;
+ synth->fftviz.sample_rate_divider = 1;
+ synth->fftviz.wi = 0;
lpf_init();
synth->fff = create_bw_low_pass_filter(2, SAMPLE_RATE, 400);
diff --git a/src/synth_engine.h b/src/synth_engine.h
index aee38d9..da15fe2 100644
--- a/src/synth_engine.h
+++ b/src/synth_engine.h
@@ -15,7 +15,7 @@
#ifndef M_PI
-#define M_PI (3.14159265)
+#define M_PI (3.14159265)
#endif
typedef struct lfo_t {
@@ -90,6 +90,7 @@ typedef struct {
int active;
viz_t viz;
+ viz_t fftviz;
osc_t * osctri;
} synth_t;
diff --git a/src/synth_gui.c b/src/synth_gui.c
index ed10547..c210f2b 100644
--- a/src/synth_gui.c
+++ b/src/synth_gui.c
@@ -191,6 +191,9 @@ draw_signals(synth_t * synth, int x, int y, int width, int height)
else
DrawCircle(i , y + height / 2 + floor(50 * synth->viz.wave[i - x]), point_radius, RAYWHITE);
}
+ for (int i = x; i < WIDTH - x; i++) {
+ DrawCircle(i , y + height / 2 + floor(5 * synth->fftviz.wave[i - x]) * -1, point_radius, RED);
+ }
int c = 0;
for (int i = 0; i < MIDI_NOTES; i++) {