summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/sequencer.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/sequencer.c b/src/sequencer.c
new file mode 100644
index 0000000..5687640
--- /dev/null
+++ b/src/sequencer.c
@@ -0,0 +1,171 @@
+#include <stdlib.h>
+#include <portmidi.h>
+#include <porttime.h>
+#include <stdio.h>
+#include <string.h>
+#include <raylib.h>
+#include <pthread.h>
+#include <math.h>
+
+#include "synth_common.h"
+
+#define MIDI_NOTE_ON 0x90
+#define MIDI_NOTE_OFF 0x80
+#define MIDI_CHANNEL 0
+#define SLEEP_INTERVAL_MS 2.0 // main loop sleep
+
+
+
+//-------------------------------------------------
+// Helper for time math
+//-------------------------------------------------
+
+typedef struct step_t {
+ PmTimestamp note_on;
+ PmTimestamp note_off;
+ float duration;
+ int note;
+} step_t;
+
+typedef struct pattert_t {
+ step_t *steps;
+ uint n; // total
+ uint c; // current
+} pattern_t;
+
+typedef struct sequencer_t {
+ PortMidiStream *stream;
+ int exitted;
+
+ float bpm;
+ int steps;
+ pattern_t *pattern;
+} sequencer_t;
+
+sequencer_t *
+init_sequencer() {
+ sequencer_t *seq = (sequencer_t *)malloc(sizeof(sequencer_t));
+
+ seq->exitted = 0;
+ seq->bpm = 100.0f;
+ seq->steps = 16;
+
+ seq->pattern = (pattern_t *)malloc(sizeof(pattern_t));
+ seq->pattern->steps = (step_t *)malloc(16 * sizeof(step_t));
+ seq->pattern->n = 16;
+ seq->pattern->c = 0;
+
+ for (uint i = 0; i < seq->pattern->n; i++) {
+ step_t *step = &seq->pattern->steps[i];
+ step->note = 40 + i;
+ }
+
+ seq->stream = NULL;
+ PmError err = Pm_Initialize();
+ if (err != pmNoError) {
+ fprintf(stdout, "Pm Error: %s\n", Pm_GetErrorText(err));
+ }
+
+ const PmDeviceInfo *info;
+ int i;
+ for (i = 0; i < Pm_CountDevices(); i++) {
+ info = Pm_GetDeviceInfo(i);
+ if (!info->output) {
+ continue;
+ }
+ printf("%d: %s [input: %d output: %d opened: %d is_virt:%d] (interface: %s)\n", i, info->name, info->input, info->output, info->opened, info->is_virtual, info->interf);
+ if (0 == strcmp("Midi Through Port-0", info->name))
+ break;
+ }
+
+ printf("Selected device: %s [input: %d output: %d opened: %d is_virt:%d] (interf: %s)\n", info->name, info->input, info->output, info->opened, info->is_virtual, info->interf);
+
+ //no start for output Pt_Start(1, midiCallback, m);
+ err = Pm_OpenOutput(&(seq->stream), i, NULL, 512, NULL, NULL, 0);
+
+ if (err != pmNoError) {
+ fprintf(stdout, "Pm Error: %s\n", Pm_GetErrorText(err));
+ }
+
+ return seq;
+}
+
+void
+free_sequencer(sequencer_t * seq) {
+ Pm_WriteShort(seq->stream, 0, Pm_Message(0xFC /* MIDI_STOP */, 0, 0));
+
+ Pm_Close(seq->stream);
+ Pm_Terminate();
+
+ free(seq);
+}
+
+static inline double ms_per_beat(sequencer_t * seq) {
+ return 60000.0 / seq->bpm;
+}
+static inline double ms_per_step(sequencer_t * seq) {
+ return ms_per_beat(seq) / seq->steps;
+}
+
+void
+rayrun(sequencer_t * seq) {
+ (void)seq;
+ SetTraceLogLevel(LOG_ERROR);
+ InitWindow(WIDTH, HEIGHT, "Raylib sequencer");
+ SetTargetFPS(60);
+ while (!WindowShouldClose()) {
+ // Draw
+ //----------------------------------------------------------------------------------
+ BeginDrawing();
+ ClearBackground(BLACK);
+
+
+ EndDrawing();
+ //----------------------------------------------------------------------------------
+ }
+ seq->exitted = 1;
+ CloseWindow();
+}
+
+void *
+sequencer_thread(void *arg)
+{
+ sequencer_t *seq = (sequencer_t *)arg;
+
+ while (!seq->exitted) {
+ //PmTimestamp current_time = Pt_Time();
+
+ step_t *step = &seq->pattern->steps[seq->pattern->c++];
+ if (seq->pattern->c >= seq->pattern->n) seq->pattern->c = 0;
+
+ Pm_WriteShort(seq->stream, 0, Pm_Message(MIDI_NOTE_ON | MIDI_CHANNEL, step->note, 100));
+
+ Pt_Sleep(ms_per_step(seq)*4);
+ Pm_WriteShort(seq->stream, 0, Pm_Message(MIDI_NOTE_OFF | MIDI_CHANNEL, step->note, 0));
+
+ //Pt_Sleep(SLEEP_INTERVAL_MS);
+ }
+
+ printf("[Sequencer] Stopping.\n");
+ return NULL;
+}
+
+
+int
+main(void) {
+ sequencer_t * seq = init_sequencer();
+
+ pthread_t seq_thread;
+
+ // start sequencer thread
+ pthread_create(&seq_thread, NULL, sequencer_thread, seq);
+
+ // start gui
+ rayrun(seq);
+
+ pthread_join(seq_thread, NULL);
+
+ free_sequencer(seq);
+
+ return 0;
+}