shithub: orca

Download patch

ref: 9af409de7612cd10d19b9ead384ce5ed05243d01
parent: b89be487f952392a1ccd2788f2dcac1023f0358d
author: cancel <cancel@cancel.fm>
date: Fri Dec 7 08:42:13 EST 2018

Add start of midi events

--- a/bank.c
+++ b/bank.c
@@ -96,3 +96,22 @@
   *cursor = offset;
   return 0;
 }
+
+void oevent_list_init(Oevent_list* olist) {
+  olist->buffer = NULL;
+  olist->count = 0;
+  olist->capacity = 0;
+}
+void oevent_list_deinit(Oevent_list* olist) { free(olist->buffer); }
+void oevent_list_clear(Oevent_list* olist) { olist->count = 0; }
+Oevent* oevent_list_alloc_item(Oevent_list* olist) {
+  Usz count = olist->count;
+  if (olist->capacity == count) {
+    Usz capacity = count < 16 ? 16 : orca_round_up_power2(count);
+    olist->buffer = realloc(olist->buffer, capacity * sizeof(Oevent));
+    olist->capacity = capacity;
+  }
+  Oevent* result = olist->buffer + count;
+  olist->count = count + 1;
+  return result;
+}
--- a/bank.h
+++ b/bank.h
@@ -29,3 +29,32 @@
 Usz bank_read(char const* restrict bank_data, Usz bank_size,
               Bank_cursor* restrict cursor, Usz index, I32* restrict dest,
               Usz dest_count);
+
+typedef enum {
+  Oevent_type_midi,
+} Oevent_types;
+
+typedef struct {
+  U8 oevent_type;
+  U8 channel;
+  U8 octave;
+  U8 note;
+  U8 velocity;
+  U8 bar_divisor;
+} Oevent_midi;
+
+typedef union {
+  U8 oevent_type;
+  Oevent_midi midi;
+} Oevent;
+
+typedef struct {
+  Oevent* buffer;
+  Usz count;
+  Usz capacity;
+} Oevent_list;
+
+void oevent_list_init(Oevent_list* olist);
+void oevent_list_deinit(Oevent_list* olist);
+void oevent_list_clear(Oevent_list* olist);
+Oevent* oevent_list_alloc_item(Oevent_list* olist);
--- a/cli_main.c
+++ b/cli_main.c
@@ -101,13 +101,16 @@
   markmap_reusable_ensure_size(&markmap_r, field.height, field.width);
   Bank bank;
   bank_init(&bank);
+  Oevent_list oevent_list;
+  oevent_list_init(&oevent_list);
   Usz max_ticks = (Usz)ticks;
   for (Usz i = 0; i < max_ticks; ++i) {
     orca_run(field.buffer, markmap_r.buffer, field.height, field.width, i,
-             &bank, ORCA_PIANO_BITS_NONE);
+             &bank, &oevent_list, ORCA_PIANO_BITS_NONE);
   }
   markmap_reusable_deinit(&markmap_r);
   bank_deinit(&bank);
+  oevent_list_deinit(&oevent_list);
   field_fput(&field, stdout);
   field_deinit(&field);
   return 0;
--- a/sim.c
+++ b/sim.c
@@ -87,6 +87,50 @@
   return false;
 }
 
+static U8 midi_note_number_of(Glyph g) {
+  switch (g) {
+  case 'C':
+    return 0;
+  case 'c':
+    return 1;
+  case 'D':
+    return 2;
+  case 'd':
+    return 3;
+  case 'E':
+    return 4;
+  case 'F':
+    return 5;
+  case 'f':
+    return 6;
+  case 'G':
+    return 7;
+  case 'g':
+    return 8;
+  case 'A':
+    return 9;
+  case 'a':
+    return 10;
+  case 'B':
+    return 11;
+  default:
+    return UINT8_MAX;
+  }
+}
+
+static ORCA_FORCE_NO_INLINE U8 midi_velocity_of(Glyph g) {
+  Usz n = index_of(g);
+  // scale [0,9] to [0,127]
+  if (n < 10) return (U8)(n * 14 + 1);
+  n -= 10;
+  // scale [0,25] to [0,127]
+  // js seems to send 1 when original n is < 10, and 0 when n is 11. Is that
+  // the intended behavior?
+  if (n == 0) return UINT8_C(0);
+  if (n >= 26) return UINT8_C(127);
+  return (U8)(n * 5 - 3);
+}
+
 ORCA_FORCE_NO_INLINE
 static void oper_movement_phase0(Gbuffer gbuf, Mbuffer mbuf, Usz const height,
                                  Usz const width, Usz const y, Usz const x,
@@ -127,6 +171,7 @@
   Bank_cursor cursor;
   Glyph const* vars_slots;
   Piano_bits piano_bits;
+  Oevent_list* oevent_list;
 } Oper_phase1_extras;
 
 static void oper_bank_store(Oper_phase0_extras* extra_params, Usz width, Usz y,
@@ -145,6 +190,9 @@
                    &extra_params->cursor, index, out_vals, out_count);
 }
 
+// ORCA_FORCE_NO_INLINE
+// static void oper_add_midi_event(Oper_phase1_extras* extra_params,
+
 ORCA_FORCE_STATIC_INLINE
 Usz usz_clamp(Usz val, Usz min, Usz max) {
   if (val < min)
@@ -290,7 +338,8 @@
 #define ORCA_SOLO_OPERATORS(_)                                                 \
   _('!', keys)                                                                 \
   _('#', comment)                                                              \
-  _('*', bang)
+  _('*', bang)                                                                 \
+  _(':', midi)
 
 #define ORCA_DUAL_OPERATORS(_)                                                 \
   _('A', 'a', add)                                                             \
@@ -374,6 +423,36 @@
 BEGIN_SOLO_PHASE_1(bang)
 END_PHASE
 
+BEGIN_SOLO_PHASE_0(midi)
+  BEGIN_ACTIVE_PORTS
+    for (Usz i = 1; 1 < 6; ++i) {
+      PORT(0, (Isz)i, IN);
+    }
+  END_PORTS
+END_PHASE
+BEGIN_SOLO_PHASE_1(midi)
+  STOP_IF_NOT_BANGED;
+  Glyph channel_g = PEEK(0, 1);
+  Glyph octave_g = PEEK(0, 2);
+  Glyph note_g = PEEK(0, 3);
+  Glyph velocity_g = PEEK(0, 4);
+  Glyph length_g = PEEK(0, 5);
+  U8 octave_num = (U8)index_of(octave_g);
+  if (octave_num == 0) return;
+  if (octave_num > 9) octave_num = 9;
+  U8 note_num = midi_note_number_of(note_g);
+  if (note_num == UINT8_MAX) return;
+  Usz channel_num = index_of(channel_g);
+  if (channel_num > 15) channel_num = 15;
+  Oevent_midi* oe = (Oevent_midi*)oevent_list_alloc_item(extra_params->oevent_list);
+  oe->oevent_type = (U8)Oevent_type_midi;
+  oe->channel = (U8)channel_num;
+  oe->octave = (U8)usz_clamp(index_of(channel_g), 1, 9);
+  oe->note = note_num;
+  oe->velocity = midi_velocity_of(velocity_g);
+  oe->bar_divisor = (U8)usz_clamp(index_of(length_g), 1, 16);
+END_PHASE
+
 BEGIN_DUAL_PHASE_0(add)
   REALIZE_DUAL;
   BEGIN_DUAL_PORTS
@@ -960,20 +1039,22 @@
 }
 
 void orca_run(Gbuffer gbuf, Mbuffer mbuf, Usz height, Usz width,
-              Usz tick_number, Bank* bank, Piano_bits piano_bits) {
+              Usz tick_number, Bank* bank, Oevent_list* oevent_list,
+              Piano_bits piano_bits) {
   Glyph vars_slots[('Z' - 'A' + 1) + ('z' - 'a' + 1)];
   memset(vars_slots, '.', sizeof(vars_slots));
   mbuffer_clear(mbuf, height, width);
-  Oper_phase0_extras bank_write_params;
-  bank_write_params.bank = bank;
-  bank_write_params.bank_size = 0;
-  bank_write_params.vars_slots = &vars_slots[0];
-  sim_phase_0(gbuf, mbuf, height, width, tick_number, &bank_write_params);
-  Oper_phase1_extras bank_read_params;
-  bank_read_params.bank = bank;
-  bank_read_params.bank_size = bank_write_params.bank_size;
-  bank_cursor_reset(&bank_read_params.cursor);
-  bank_read_params.vars_slots = &vars_slots[0];
-  bank_read_params.piano_bits = piano_bits;
-  sim_phase_1(gbuf, mbuf, height, width, tick_number, &bank_read_params);
+  oevent_list_clear(oevent_list);
+  Oper_phase0_extras phase0_extras;
+  phase0_extras.bank = bank;
+  phase0_extras.bank_size = 0;
+  phase0_extras.vars_slots = &vars_slots[0];
+  sim_phase_0(gbuf, mbuf, height, width, tick_number, &phase0_extras);
+  Oper_phase1_extras phase1_extras;
+  phase1_extras.bank = bank;
+  phase1_extras.bank_size = phase0_extras.bank_size;
+  bank_cursor_reset(&phase1_extras.cursor);
+  phase1_extras.vars_slots = &vars_slots[0];
+  phase1_extras.piano_bits = piano_bits;
+  sim_phase_1(gbuf, mbuf, height, width, tick_number, &phase1_extras);
 }
--- a/sim.h
+++ b/sim.h
@@ -16,4 +16,5 @@
 }
 
 void orca_run(Gbuffer gbuf, Mbuffer markmap, Usz height, Usz width,
-              Usz tick_number, Bank* bank, Piano_bits piano_bits);
+              Usz tick_number, Bank* bank, Oevent_list* oevent_list,
+              Piano_bits piano_bits);
--- a/tui_main.c
+++ b/tui_main.c
@@ -386,7 +386,8 @@
     return delta_rulers > 0 ? ruler * (Usz)delta_rulers : 1;
   }
   // could overflow if inputs are big
-  if (delta_rulers < 0) in += ruler - 1;
+  if (delta_rulers < 0)
+    in += ruler - 1;
   Isz n = ((Isz)in - 1) / (Isz)ruler + delta_rulers;
   if (n < 0)
     n = 0;
@@ -508,6 +509,8 @@
   bank_init(&bank);
   Undo_history undo_hist;
   undo_history_init(&undo_hist);
+  Oevent_list oevent_list;
+  oevent_list_init(&oevent_list);
 
   // Enable UTF-8 by explicitly initializing our locale before initializing
   // ncurses.
@@ -587,7 +590,7 @@
       field_resize_raw_if_necessary(&scratch_field, field.height, field.width);
       field_copy(&field, &scratch_field);
       orca_run(field.buffer, markmap_r.buffer, field.height, field.width,
-               tick_num, &bank, piano_bits);
+               tick_num, &bank, &oevent_list, piano_bits);
       field_copy(&scratch_field, &field);
       needs_remarking = false;
     }
@@ -724,7 +727,7 @@
     case AND_CTRL('f'):
       undo_history_push(&undo_hist, &field, tick_num);
       orca_run(field.buffer, markmap_r.buffer, field.height, field.width,
-               tick_num, &bank, piano_bits);
+               tick_num, &bank, &oevent_list, piano_bits);
       ++tick_num;
       piano_bits = ORCA_PIANO_BITS_NONE;
       needs_remarking = true;
@@ -786,5 +789,6 @@
   field_deinit(&field);
   field_deinit(&scratch_field);
   undo_history_deinit(&undo_hist);
+  oevent_list_deinit(&oevent_list);
   return 0;
 }