I wrote a couple scale quantizer OPs for Teletype based on @discohead’s N.S lookup table. These are my first OPs and my C is rusty so I’m sure I’m missing something, but I can only get one of my two OPs (QT.S) to work correctly. nb: these OPs are just working with semitones; I might convert to volts later, I dunno.
QT.S simply checks the input semitones against all semitone values on the specified row of table_n_s until it finds the highest value less than the input. I feel like my code’s a bit messy (I wanted to wrap all the input values in useful ways) but it’s working great.
QT.SC is similar but the allowed values are selected by giving scale (0-8), degree (0-6) and chord type / voices (1-7). 1 voice gives a single note, 2 is a third, 3 is a triad, 4 is a seventh, etc. My problem is that my wrapping math is not working when a given degree + chord exceeds the length of the scale. This line: dix = (2 * i + degree) % 7; is supposed to pick the table index and wrap gracefully while checking the input semitones against the table_n_s value but when I test on TT it’s not selecting any values which occur after the wrapping starts. I could use a fresh set of eyes!
QT.S input root scale
static void op_QT_S_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t note_in = cs_pop(cs);
int16_t root = cs_pop(cs);
int16_t scale = cs_pop(cs) % 9;
if (scale < 0) scale = 9 + scale;
note_in = note_in - root;
int16_t octave = (note_in >= 0) ? (note_in / 12) : ((note_in + 1) / 12 - 1);
if (note_in >= 0) {
note_in = note_in % 12;
}
else {
if (note_in % 12 == 0) {
note_in = 0;
}
else {
note_in = 12 + (note_in % 12);
}
}
int16_t note_out;
for (uint8_t i = 0; i < 7; i++) {
if (note_in >= table_n_s[scale][i]) note_out = table_n_s[scale][i];
}
cs_push(cs, 12 * octave + note_out + root);
}
QT.SC input root scale degree voices
static void op_QT_SC_get(const void *NOTUSED(data), scene_state_t *NOTUSED(ss),
exec_state_t *NOTUSED(es), command_state_t *cs) {
int16_t note_in = cs_pop(cs);
int16_t root = cs_pop(cs);
int16_t scale = cs_pop(cs) % 9;
if (scale < 0) scale = 9 + scale;
int16_t degree = cs_pop(cs);
int16_t degree_octave = (degree >= 0) ? (degree / 7) : ((degree + 1) / 7 - 1);
if (degree >= 0) {
degree = degree % 7;
}
else {
if (degree % 7 == 0) {
degree = 0;
}
else {
degree = 7 + (degree % 7);
}
}
int16_t voices = cs_pop(cs);
if (voices < 1) voices = 1;
if (voices > 7) voices = 7;
note_in = note_in - root;
int16_t octave = (note_in >= 0) ? (note_in / 12) : ((note_in + 1) / 12 - 1);
if (note_in >= 0) {
note_in = note_in % 12;
}
else {
if (note_in % 12 == 0) {
note_in = 0;
}
else {
note_in = 12 + (note_in % 12);
}
}
bool quant = false;
int16_t max_n_s_val = 0;
int16_t n_s_val;
int16_t note_out;
int16_t dix;
for (int16_t i = 0; i < voices; i++) {
dix = (2 * i + degree) % 7;
n_s_val = table_n_s[scale][dix];
if (n_s_val > max_n_s_val) max_n_s_val = n_s_val;
if (note_in >= n_s_val) {
note_out = n_s_val;
quant = true;
}
}
if (!quant) note_out = max_n_s_val - 12;
cs_push(cs, 12 * (octave + degree_octave) + note_out + root);
}