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;
}