#include "sequencer.h" /* Main sequencing for the arpeggiator * Inputs : * lfo - Low frequency oscillator which signals when to begin a new note * root - Output phase increment from the YIN block * step - Number of steps in the sequence, provided by the ARM * direction - Sets the direction to up/down/up-down. Provided by the ARM * mode - Sets major/minor tonality and octave or alternatively random mode. Provided by the ARM */ void sequencer(udata_t *y, bool *tlast, bool lfo, udata_t root, control_t steps, control_t direction, control_t mode) { // Contains 2^(0/12) through 2^(12/12) for frequency multipliers const note_offset_t scale_offsets[13] = {1.0, 1.0595, 1.1225, 1.1892, 1.2599, 1.3348, 1.4142, 1.4983, 1.5874, 1.6818, 1.7818, 1.8877, 2}; // Array that contains each note's phase increment (freq) // Indexes 1-6 are the lower octave, Root is at index 7, indexes 8-14 are the upper octave udata_t scale_steps[15]; udata_t current_note; // Octave modifier to offset scale index unsigned char oct = (mode == 2 || mode == 6) ? 7 : 0; // If direction is up or up-down start at the 0th step, otherwise start at the top step static int scale_index = (direction < 2) ? (0+oct) : (steps.to_int() + oct); // Array that contains the phase increments (freqs) for the harmonics of the target note for the DDS block // This is what will ultimately be output from the block static udata_t harmonics[NUM_CH]; static unsigned char out_index = NUM_CH; // Set to an arbitrary value >= NUM_CH // Direction flag used for the up-down mode static char step_dir = 1; // Registers for signals static bool prev_lfo; static control_t prev_mode; static udata_t prev_root; // Logic flags bool is_minor = mode >= 5; bool root_change = (root > prev_root + THRESH) || (root < prev_root - THRESH); bool mode_change = (mode != prev_mode); static bool tlast_enable = true; int i; /* Generate the sequence for the current mode * Only recalculate if the mode or root has changed */ if( (mode != prev_mode) || ((root > prev_root + THRESH) || (root < prev_root - THRESH)) ) { scale_steps[0] = root / 2; // -1 Oct Root scale_steps[1] = scale_steps[0] * scale_offsets[2]; // -1 Oct Major 2 scale_steps[2] = (is_minor) ? (scale_steps[0] * scale_offsets[3]) : (scale_steps[0] * scale_offsets[4]); // -1 Oct Minor/major 3 scale_steps[3] = scale_steps[0] * scale_offsets[5]; // -1 Oct Perfect 4 scale_steps[4] = scale_steps[0] * scale_offsets[6]; // -1 Oct Perfect 5 scale_steps[5] = (is_minor) ? (scale_steps[0] * scale_offsets[8]) : (scale_steps[0] * scale_offsets[9]); // -1 Oct Minor/major 6 scale_steps[6] = (is_minor) ? (scale_steps[0] * scale_offsets[10]) : (scale_steps[0] * scale_offsets[11]); // -1 Oct Minor/major 7 scale_steps[7] = root; // +0 Oct Root // Root to +1 octave scale_steps[8] = scale_steps[7] * scale_offsets[2]; // +0 Oct Major 2 scale_steps[9] = (is_minor) ? (scale_steps[7] * scale_offsets[3]) : (scale_steps[7] * scale_offsets[4]); // +0 Oct Minor/major 3 scale_steps[10] = scale_steps[7] * scale_offsets[5]; // +0 Oct Perfect 4 scale_steps[11] = scale_steps[7] * scale_offsets[6]; // +0 Oct Perfect 5 scale_steps[12] = (is_minor) ? (scale_steps[7] * scale_offsets[8]) : (scale_steps[7] * scale_offsets[9]); // +0 Oct Minor/major 6 scale_steps[13] = (is_minor) ? (scale_steps[7] * scale_offsets[10]) : (scale_steps[7] * scale_offsets[11]); // +0 Oct Minor/major 7 scale_steps[14] = root * 2; // +1 Oct Root if(mode != prev_mode && (mode == 2 || mode == 6)) { // Adjust scale_index to use the higher octave scale_index += 7; } else if(mode != prev_mode && (prev_mode == 2 || prev_mode == 6)) { // Return the index to the lower octave range scale_index -= 7; } } /* Actions that occur when the lfo triggers */ if( lfo && (lfo != prev_lfo) ) { current_note = scale_steps[scale_index]; /* Calculate new phase increments for the current note */ harmonic_loop : for(i = 0; i < NUM_CH; i++) { harmonics[i] = current_note * (i+1); } /* Adjust scale index according to direction */ if(direction == 1) { // Direction is up scale_index++; if(scale_index > (steps-1) + oct) { scale_index = 0 + oct; } } else if(direction == 2) { // Direction is down scale_index--; if(scale_index < oct) { scale_index = (steps-1) + oct; } } else if(direction == 0) { // Direction is up-down scale_index += step_dir; if(scale_index < oct || scale_index > (steps - 1 + oct)) { // Reverse direction and move two steps (so the same note isn't repeated) step_dir = -1*step_dir; scale_index += (step_dir << 1); } } if(out_index != 0) { out_index = 0; tlast_enable = true; } } /* Store last values for comparison */ prev_lfo = lfo; prev_mode = mode; prev_root = root; if(out_index < NUM_CH) { *y = harmonics[out_index]; if(tlast_enable && out_index == NUM_CH-1) { // Need to note the final sample in the frame for the DDS block *tlast = true; tlast_enable = false; } out_index++; } }