shithub: orca

Download patch

ref: 0bc6f862455f014cb4873e8a38940b40b184f93a
parent: 5a81794d5f9980b00ca5322e23074e8691ce2510
author: cancel <cancel@cancel.fm>
date: Tue Dec 18 19:15:47 EST 2018

Update numeric behavior of glyphs

--- a/sim.c
+++ b/sim.c
@@ -5,18 +5,54 @@
 //////// Utilities
 
 static Glyph const indexed_glyphs[] = {
-    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd',
-    'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
-    's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '.', '*', ':', ';', '#',
+    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b',
+    'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+    'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
 };
 
-enum { Glyphs_array_num = sizeof indexed_glyphs };
+enum {
+  Glyphs_array_num = sizeof indexed_glyphs,
+  Glyphs_index_max = 36,
+};
 
 // Always returns 0 through (sizeof indexed_glyphs) - 1, and works on
 // capitalized glyphs as well. The index of the lower-cased glyph is returned
 // if the glyph is capitalized.
 #if 1
+// Branchless implementation
 static Usz index_of(Glyph c) {
+  int i = c;
+  enum {
+    // All number chars have this bit set. Some alpha chars do.
+    Num_bit = 1 << 4,
+    // All alpha chars have this bit set. No number chars do.
+    Alpha_bit = 1 << 6,
+    // The bits we use from a number char (0000 1111) to get an index number
+    Lower_4 = 0xF,
+    // The bits we use from an alpha char (0001 1111) to get an index number
+    Lower_5 = 0x1F,
+  };
+  union {
+    uint32_t u;
+    int32_t i;
+  } pui;
+  // Turn the alpha bit into a mask of all 32 bits
+  pui.u = (uint32_t)(i & Alpha_bit) << UINT32_C(25);
+  int alpha_mask = pui.i >> 31;
+  // Turn the number bit into a mask of all 32 bits
+  pui.u = (uint32_t)(i & Num_bit) << UINT32_C(27);
+  int num_mask = pui.i >> 31;
+  // If it's an alpha char, we add 9 to it, bringing 'a'/'A' from 1 to 10, 'b'
+  // to 11, etc.
+  return (Usz)((i & ((alpha_mask & Lower_5) | (num_mask & Lower_4))) +
+               (9 & alpha_mask));
+  // If the glyph might be a non-valid char in certain ranges (like '^' char)
+  // we will return a number here greater than 35. We could do % 36 here if we
+  // wanted to be really safe.
+}
+#else
+// Reference implementation
+static Usz index_of(Glyph c) {
   if (c == '.')
     return 0;
   if (c >= '0' && c <= '9')
@@ -25,33 +61,8 @@
     return (Usz)(c - 'A' + 10);
   if (c >= 'a' && c <= 'z')
     return (Usz)(c - 'a' + 10);
-  switch (c) {
-  case '*':
-    return 37;
-  case ':':
-    return 38;
-  case ';':
-    return 49;
-  case '#':
-    return 40;
-  }
   return 0;
 }
-#else
-// Reference implementation
-inline static Glyph glyph_lowered(Glyph c) {
-  return (c >= 'A' && c <= 'Z') ? (char)(c - ('a' - 'A')) : c;
-}
-static Usz index_of(Glyph c) {
-  Glyph c0 = glyph_lowered(c);
-  if (c0 == '.')
-    return 0;
-  for (Usz i = 0; i < Glyphs_array_num; ++i) {
-    if (indexed_glyphs[i] == c0)
-      return i;
-  }
-  return 0;
-}
 #endif
 
 static inline Glyph glyph_of(Usz index) {
@@ -62,7 +73,7 @@
 static Glyph glyphs_add(Glyph a, Glyph b) {
   Usz ia = index_of(a);
   Usz ib = index_of(b);
-  return indexed_glyphs[(ia + ib) % Glyphs_array_num];
+  return indexed_glyphs[(ia + ib) % Glyphs_index_max];
 }
 
 static Glyph glyphs_mod(Glyph a, Glyph b) {
@@ -121,13 +132,16 @@
 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);
+  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);
+  if (n == 0)
+    return UINT8_C(0);
+  if (n >= 26)
+    return UINT8_C(127);
   return (U8)(n * 5 - 3);
 }
 
@@ -434,19 +448,24 @@
   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;
+  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;
+  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);
+  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(octave_num, 1, 9);
   oe->note = note_num;
   oe->velocity = midi_velocity_of(velocity_g);
-  oe->bar_divisor = (U8)usz_clamp(index_of(length_g), 1, 36);
+  oe->bar_divisor = (U8)usz_clamp(index_of(length_g), 1, Glyphs_index_max);
 END_PHASE
 
 BEGIN_DUAL_PHASE_0(add)
@@ -774,7 +793,7 @@
         ++count;
       ++i;
     }
-    Glyph g = glyph_of(count % Glyphs_array_num);
+    Glyph g = glyph_of(count % Glyphs_index_max);
     POKE(1, 0, g);
   }
 END_PHASE