shithub: orca

Download patch

ref: d69dbb86405af9c82a8ae5c60027cf09e0c29034
parent: c5f0c601ae93df571ed74e52db54eefa42e63a0d
author: cancel <cancel@cancel.fm>
date: Mon Jan 20 13:55:47 EST 2020

Add MIDI CC operator (!)

Fixes #20

--- a/bank.h
+++ b/bank.h
@@ -2,7 +2,8 @@
 #include "base.h"
 
 typedef enum {
-  Oevent_type_midi,
+  Oevent_type_midi_note,
+  Oevent_type_midi_cc,
   Oevent_type_osc_ints,
   Oevent_type_udp_string,
 } Oevent_types;
@@ -14,8 +15,13 @@
 typedef struct {
   U8 oevent_type;
   U8 channel, octave, note, velocity, duration;
-} Oevent_midi;
+} Oevent_midi_note;
 
+typedef struct {
+  U8 oevent_type;
+  U8 channel, control, value;
+} Oevent_midi_cc;
+
 enum { Oevent_osc_int_count = 16 };
 
 typedef struct {
@@ -35,7 +41,8 @@
 
 typedef union {
   Oevent_any any;
-  Oevent_midi midi;
+  Oevent_midi_note midi_note;
+  Oevent_midi_cc midi_cc;
   Oevent_osc_ints osc_ints;
   Oevent_udp_string udp_string;
 } Oevent;
--- a/sim.c
+++ b/sim.c
@@ -262,7 +262,26 @@
 END_OPERATOR
 
 BEGIN_OPERATOR(midicc)
-  // TODO unimplemented
+  for (Usz i = 1; i < 4; ++i) {
+    PORT(0, (Isz)i, IN);
+  }
+  STOP_IF_NOT_BANGED;
+  Glyph channel_g = PEEK(0, 1);
+  Glyph control_g = PEEK(0, 2);
+  Glyph value_g = PEEK(0, 3);
+  if (channel_g == '.' || control_g == '.')
+    return;
+  Usz channel = index_of(channel_g);
+  if (channel > 15)
+    return;
+  Usz control = index_of(control_g);
+  Usz value = safe_index_of(value_g) * 127 / 35;
+  Oevent_midi_cc *oe =
+      (Oevent_midi_cc *)oevent_list_alloc_item(extra_params->oevent_list);
+  oe->oevent_type = Oevent_type_midi_cc;
+  oe->channel = (U8)channel;
+  oe->control = (U8)control;
+  oe->value = (U8)value;
 END_OPERATOR
 
 BEGIN_OPERATOR(comment)
@@ -320,9 +339,9 @@
     if (vel_num > 127)
       vel_num = 127;
   }
-  Oevent_midi *oe =
-      (Oevent_midi *)oevent_list_alloc_item(extra_params->oevent_list);
-  oe->oevent_type = (U8)Oevent_type_midi;
+  Oevent_midi_note *oe =
+      (Oevent_midi_note *)oevent_list_alloc_item(extra_params->oevent_list);
+  oe->oevent_type = (U8)Oevent_type_midi_note;
   oe->channel = (U8)channel_num;
   oe->octave = octave_num;
   oe->note = note_num;
--- a/tui_main.c
+++ b/tui_main.c
@@ -626,14 +626,21 @@
     Oevent const *ev = oevent_list->buffer + i;
     Oevent_types evt = ev->any.oevent_type;
     switch (evt) {
-    case Oevent_type_midi: {
-      Oevent_midi const *em = &ev->midi;
-      wprintw(win,
-              "MIDI\tchannel %d\toctave %d\tnote %d\tvelocity %d\tlength %d",
-              (int)em->channel, (int)em->octave, (int)em->note,
-              (int)em->velocity, (int)em->duration);
+    case Oevent_type_midi_note: {
+      Oevent_midi_note const *em = &ev->midi_note;
+      wprintw(
+          win,
+          "MIDI Note\tchannel %d\toctave %d\tnote %d\tvelocity %d\tlength %d",
+          (int)em->channel, (int)em->octave, (int)em->note, (int)em->velocity,
+          (int)em->duration);
       break;
     }
+    case Oevent_type_midi_cc: {
+      Oevent_midi_cc const *ec = &ev->midi_cc;
+      wprintw(win, "MIDI CC\tchannel %d\tcontrol %d\tvalue %d",
+              (int)ec->channel, (int)ec->control, (int)ec->value);
+      break;
+    }
     case Oevent_type_osc_ints: {
       Oevent_osc_ints const *eo = &ev->osc_ints;
       wprintw(win, "OSC\t%c\tcount: %d ", eo->glyph, eo->count, eo->count);
@@ -1043,8 +1050,8 @@
       break;
     Oevent const *e = events + i;
     switch ((Oevent_types)e->any.oevent_type) {
-    case Oevent_type_midi: {
-      Oevent_midi const *em = &e->midi;
+    case Oevent_type_midi_note: {
+      Oevent_midi_note const *em = &e->midi_note;
       Usz note_number = (Usz)(12u * em->octave + em->note);
       if (note_number > 127)
         note_number = 127;
@@ -1064,6 +1071,41 @@
       ++midi_note_count;
       break;
     }
+    case Oevent_type_midi_cc: {
+      Oevent_midi_cc const *ec = &e->midi_cc;
+      // Note that we're not preserving the exact order of MIDI events as
+      // emitted by the orca VM. Notes and CCs that are emitted in the same
+      // step will always have the CCs sent first. Not sure if this is OK or
+      // not. If it's not OK, we can either loop again a second time to always
+      // send CCs after notes, or if that's not also OK, we can make the stack
+      // buffer more complicated and interleave the CCs in it.
+      switch (midi_mode_type) {
+      case Midi_mode_type_null:
+        break;
+      case Midi_mode_type_osc_bidule: {
+        if (!oosc_dev)
+          break; // not sure if needed
+        I32 ints[3];
+        ints[0] = (0xb << 4) | ec->channel; // status
+        ints[1] = ec->control;
+        ints[2] = ec->value;
+        oosc_send_int32s(oosc_dev, midi_mode->osc_bidule.path, ints,
+                         ORCA_ARRAY_COUNTOF(ints));
+        break;
+      }
+#ifdef FEAT_PORTMIDI
+      case Midi_mode_type_portmidi: {
+        int istatus = (0x9 << 4) | (int)ec->channel;
+        PmError pme = Pm_WriteShort(
+            midi_mode->portmidi.stream, 0,
+            Pm_Message(istatus, (int)ec->control, (int)ec->value));
+        (void)pme;
+        break;
+      }
+#endif
+      }
+      break;
+    }
     case Oevent_type_osc_ints: {
       // kinda lame
       if (!oosc_dev)
@@ -1091,7 +1133,7 @@
     }
   }
 
-  if (midi_note_count > 0 && midi_mode) {
+  if (midi_note_count > 0) {
     Usz start_note_offs, end_note_offs;
     susnote_list_add_notes(susnote_list, new_susnotes, midi_note_count,
                            &start_note_offs, &end_note_offs);