OSCtoCV Library
OSCtoCV_Euclidean.cpp
- Committer:
- casiotone401
- Date:
- 2016-01-28
- Revision:
- 2:9fa7540890c9
- Parent:
- 1:981b62bb5c87
File content as of revision 2:9fa7540890c9:
/* OSCtoCV_Euclidean.cpp */ #include "mbed.h" #include "OSCtoCV_Euclidean.h" #include "OSCtoCV.h" //------------------------------------------------------------- // Global Variables int channels = MAXCHANNELS; unsigned int beat_holder[MAXCHANNELS]; unsigned int channelbeats[MAXCHANNELS][5]; bool pulses_active = false; // is active while a beat pulse is playing bool lights_active = false; int pulse_length = TRIGGER_DURATION; //pulse length unsigned int last_read[MAXCHANNELS]; unsigned int last_changed[MAXCHANNELS]; unsigned int last_sync; unsigned int euc_time; int masterclock; //------------------------------------------------------------- // Euclidean Sequencer unsigned int EuclideanSeq(int trigger, bool reset, bool gatesoff, bool auto_offset) { /* What's in the loop: Update euc_time variable Check to see if it is euc_time go go to sleep Changes routine - update beat_holder when channelbeats changes - triggered by changes == true Trigger routines - on trigget update displays and pulse Read encoders Read switches */ int offset; static uint8_t nn, kk, oo; static unsigned int cnt_auto_offset; static uint8_t changes[MAXCHANNELS] = {0}; static int nknob, kknob, oknob; static int _nknob, _kknob, _oknob; static bool triggerState = false; uint8_t i, ch; uint8_t maxn = MAXSTEPS; // maximums and minimums for n and k uint8_t minn = 1; uint8_t mink = 1; uint8_t mino = 0; static uint8_t active_channel; euc_time = gTimer.read_ms(); nn = channelbeats[active_channel][0]; kk = channelbeats[active_channel][1]; oo = channelbeats[active_channel][3]; // Stop & Reset (gCtrlSW[0]) if (reset) { for (ch = 0; ch < channels; ++ch) { for (i = 0; i < MAXSTEPS; ++i) { for (ch = 0; ch < channels; ++ch) { sendMes.setTopAddress(SetMatrixAddress(ch * 2 + 1, i, EUCLID)); // ch * 2 + 1 sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); } } } masterclock = cnt_auto_offset = active_channel = channelbeats[ch][2] = 0; return 0; } // UPDATE BEAT HOLDER WHEN KNOBS ARE MOVED if (changes[active_channel]) { beat_holder[active_channel] = Euclid(nn, kk, oo); switch (changes[active_channel]) { case 1: case 3: for (int i = 0; i < MAXSTEPS; ++i) { if (BitRead(beat_holder[active_channel], nn - 1 - i) && (i < nn)) { sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, EUCLID)); sendMes.setArgs("i", 1); osc.sendOsc(&sendMes); } else { sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, EUCLID)); sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); } } break; case 2: for (int i = 0; i < MAXSTEPS; ++i) { if (i < nn) { sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, EUCLID)); sendMes.setArgs("i", 1); osc.sendOsc(&sendMes); } else { sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, EUCLID)); sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); } } break; default: break; } changes[active_channel] = 0; last_changed[active_channel] = gTimer.read_ms(); } // ANALOG PULSE TRIGGER if (trigger && !triggerState) { Sync(active_channel, gatesoff); triggerState = true; if (auto_offset) { cnt_auto_offset++; if (cnt_auto_offset == 64) // auto offset { cnt_auto_offset = 0; for (i = 0; i < MAXCHANNELS; ++i) { offset = (MAXSTEPS / 2) - (rand() % (MAXSTEPS - 1)); if ((oo + offset) > (nn - 1)) { offset = 0; oo = (nn - 1); } else if ((oo + offset) < mino) { offset = 0; oo = mino; } channelbeats[i][3] = (oo + offset); last_read[i] = gTimer.read_ms(); changes[i] = 3; // o change = 3 } } } } else if (!trigger) { triggerState = false; } // READ K KNOB kknob = EncodeReadK(active_channel); if (_kknob != kknob) { _kknob = kknob; if (kknob != 0 && (euc_time - last_read[active_channel] > READ_DELAY)) { if ((kk + kknob) > nn) { kknob = 0; kk = nn; } else if ((kk + kknob) < mink) { kknob = 0; kk = mink; }; kk = channelbeats[active_channel][1] = (kk + kknob); // update with encoder reading last_read[active_channel] = gTimer.read_ms(); changes[active_channel] = 1; // k change = 1 } } // READ N KNOB nknob = EncodeReadN(active_channel); if (_nknob != nknob) { _nknob = nknob; if (nknob != 0 && (euc_time - last_read[active_channel] > READ_DELAY)) { if ((nn + nknob) > maxn) { nknob = 0; nn = maxn; } else if ((nn + nknob) < minn) { nknob = 0; nn = minn; }; if (kk > (nn + nknob)) {// check if new n is lower than k + reduce K if it is channelbeats[active_channel][1] = (nn + nknob); }; if (oo > (nn + nknob - 1)) {// check if new n is lower than o + reduce o if it is channelbeats[active_channel][3] = (nn + nknob - 1); }; nn = channelbeats[active_channel][0] = (nn + nknob); // update with encoder reading oo = channelbeats[active_channel][3]; last_read[active_channel] = gTimer.read_ms(); changes[active_channel] = 2; // n change = 2 } } // READ O KNOB oknob = EncodeReadO(active_channel); if (_oknob != oknob) { _oknob = oknob; if (oknob != 0 && (euc_time - last_read[active_channel] > READ_DELAY)) { // Sense check o encoder reading to prevent crashes if ((oo + oknob) > (nn - 1)) { oknob = 0; oo = (nn - 1); } else if ((oo + oknob) < mino) { oknob = 0; oo = mino; } channelbeats[active_channel][3] = (oo + oknob); last_read[active_channel] = gTimer.read_ms(); changes[active_channel] = 3; // o change = 3 } } // ENABLE RESET BUTTON ** ADD FLASH RESET HERE *** if (gCtrlSW[1] && channelbeats[active_channel][2]) { for (ch = 0; ch < channels; ++ch) { channelbeats[ch][2] = 0; } } // TURN OFF ANY LIGHTS THAT ARE ON if ((euc_time - last_sync) > pulse_length && lights_active) { for (ch = 0; ch < channels; ++ch) { sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 3 - ch, EUCLID)); sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 5, EUCLID)); sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); } lights_active = false; } // FINISH ANY PULSES THAT ARE ACTIVE - PULSES LAST 1/4 AS LONG AS LIGHTS if (euc_time - last_sync > (pulse_length / 4) && pulses_active) { for (ch = 0; ch < channels; ++ch) { if (!gatesoff) { gGATES[ch] = false; gCLOCKOUT = false; //digitalWrite(sparepin, LOW); } } pulses_active = false; } ++active_channel; active_channel &= (channels - 1); return triggerState; } //------------------------------------------------------------- // Init Euclidean Sequencer void InitEuclideanSeq(void) { // Initialize Euclid Sequencer channelbeats[0][0] = 16; channelbeats[0][1] = 8; channelbeats[0][2] = 0; channelbeats[0][3] = 0; channelbeats[1][0] = 16; channelbeats[1][1] = 9; channelbeats[1][2] = 0; channelbeats[1][3] = 0; channelbeats[2][0] = 16; channelbeats[2][1] = 7; channelbeats[2][2] = 0; channelbeats[2][3] = 0; channelbeats[3][0] = 16; channelbeats[3][1] = 9; channelbeats[3][2] = 0; channelbeats[3][3] = 0; for (int i = 0; i < channels; ++i) { beat_holder[i] = Euclid(channelbeats[i][0], channelbeats[i][1], channelbeats[i][3]); } } //------------------------------------------------------------- // Euclid calculation function unsigned int Euclid(int n, int k, int o) { // inputs: n=total, k=beats, o = offset int pauses = (n - k); int pulses = k; int offset = o; int steps = n; int per_pulse = (pauses / k); int remainder = (pauses % pulses); unsigned int workbeat[n]; unsigned int outbeat; uint16_t outbeat2; int workbeat_count = n; int a_remainder, b_remainder; int groupa, groupb; int i, j; int trim_count; for (i = 0; i < n; ++i) { // Populate workbeat with unsorted pulses and pauses if (i < pulses) { workbeat[i] = 1; } else { workbeat[i] = 0; } } if (per_pulse > 0 && remainder < 2) { // Handle easy cases where there is no or only one remainer for (i = 0; i < pulses; ++i) { for (j = (workbeat_count - 1); j > (workbeat_count - per_pulse - 1); --j) { workbeat[i] = ConcatBin(workbeat[i], workbeat[j]); } workbeat_count = (workbeat_count - per_pulse); } outbeat = 0; // Concatenate workbeat into outbeat - according to workbeat_count for (i = 0; i < workbeat_count; ++i) { outbeat = ConcatBin(outbeat, workbeat[i]); } if (offset != 0) { outbeat2 = BitReadOffset(offset, outbeat, steps); // Add offset to the step pattern } else { outbeat2 = outbeat; } return outbeat2; } else { groupa = pulses; groupb = pauses; while (groupb > 1) { //main recursive loop if (groupa > groupb) { // more Group A than Group B a_remainder = (groupa - groupb); // what will be left of groupa once groupB is interleaved trim_count = 0; for (i = 0; i < (groupa - a_remainder); ++i) { //count through the matching sets of A, ignoring remaindered workbeat[i] = ConcatBin(workbeat[i], workbeat[workbeat_count - 1 - i]); ++trim_count; } workbeat_count = (workbeat_count - trim_count); groupa = groupb; groupb = a_remainder; } else if (groupb > groupa) { // More Group B than Group A b_remainder = (groupb - groupa); // what will be left of group once group A is interleaved trim_count = 0; for (i = workbeat_count-1; i >= (groupa + b_remainder); --i) { //count from right back through the Bs workbeat[workbeat_count - i - 1] = ConcatBin(workbeat[workbeat_count - 1 - i], workbeat[i]); ++trim_count; } workbeat_count = (workbeat_count - trim_count); groupb = b_remainder; } else if (groupa == groupb) { // groupa = groupb trim_count = 0; for (i = 0; i < groupa; ++i) { workbeat[i] = ConcatBin(workbeat[i], workbeat[workbeat_count - 1 - i]); ++trim_count; } workbeat_count = (workbeat_count - trim_count); groupb = 0; } } outbeat = 0; // Concatenate workbeat into outbeat - according to workbeat_count for (i = 0; i < workbeat_count; ++i) { outbeat = ConcatBin(outbeat, workbeat[i]); } if (offset != 0) { outbeat2 = BitReadOffset(offset, outbeat, steps); // Add offset to the step pattern } else { outbeat2 = outbeat; } return outbeat2; } } //------------------------------------------------------------- // Reads a bit of a number int BitRead(uint16_t b, int bitPos) { int x; x = b & (1 << bitPos); return x == 0 ? 0 : 1; } //------------------------------------------------------------- // Function to right rotate n by d bits uint16_t BitReadOffset(int shift, uint16_t value, uint16_t pattern_length) { uint16_t mask = ((1 << pattern_length) - 1); value &= mask; return ((value >> shift) | (value << (pattern_length - shift))) & mask; } //------------------------------------------------------------- // Function to find the binary length of a number by counting bitwise int findlength(unsigned int bnry) { bool lengthfound = false; int i; int length = 1; // no number can have a length of zero - single 0 has a length of one, but no 1s for the sytem to count for (i = 32; i >= 0; i--) { if ((BitRead(bnry, i)) && !lengthfound) { length = (i + 1); lengthfound = true; } } return length; } //------------------------------------------------------------- // Function to concatenate two binary numbers bitwise unsigned int ConcatBin(unsigned int bina, unsigned int binb) { int binb_len = findlength(binb); unsigned int sum = (bina << binb_len); sum = sum | binb; return sum; } //------------------------------------------------------------- // routine triggered by each beat void Sync(int active_channel, bool gatesoff) { int read_head, erase; int rand_vel, rand_len; int ch, i; if (masterclock % 2 == 0) { sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 7, EUCLID)); sendMes.setArgs("i", 1); osc.sendOsc(&sendMes); } else { sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 7, EUCLID)); sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); } // Cycle through channels for (ch = 0; ch < channels; ++ch) { read_head = (channelbeats[ch][0] - channelbeats[ch][2] - 1); if (ch != active_channel || (euc_time - last_changed[active_channel]) > DISPLAY_UPDATE) { if (channelbeats[ch][2] < MAXSTEPS) { for (i = 0; i < MAXSTEPS; ++i) { if (BitRead(beat_holder[ch],channelbeats[ch][0] - 1 - i) && i < channelbeats[ch][0]) { sendMes.setTopAddress(SetMatrixAddress(ch * 2, i, EUCLID)); sendMes.setArgs("i", 1); osc.sendOsc(&sendMes); } else { sendMes.setTopAddress(SetMatrixAddress(ch * 2, i, EUCLID)); sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); } } } } if (!masterclock) { erase = MAXSTEPS - 1; } else { erase = masterclock - 1; } sendMes.setTopAddress(SetMatrixAddress((ch * 2) + 1, erase, EUCLID)); sendMes.setArgs("i", 0); osc.sendOsc(&sendMes); sendMes.setTopAddress(SetMatrixAddress((ch * 2) + 1, masterclock, EUCLID)); sendMes.setArgs("i", 1); osc.sendOsc(&sendMes); // turn on pulses on channels where a beat is present if (BitRead(beat_holder[ch], read_head)) { if (!gatesoff) { gGATES[ch] = true; // pulse out } sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 3 - ch, EUCLID)); sendMes.setArgs("i", 1); osc.sendOsc(&sendMes); lights_active = pulses_active = true; if (!ch || (ch == 2)) { rand_vel = 127 - (rand() % 20); // random velocity ch1, ch3 } else { rand_vel = 95 - (rand() % 10); // random velocity ch2, ch4 } rand_len = 127 - (rand() % 17); // random Amp EG Decay midi.sendControlChange(0x07, rand_vel, (ch + 1)); // volca sample Vol midi.sendControlChange(0x30, rand_len, (ch + 1)); // volca sample Amp EG Decay midi.sendNoteOn(0, 127, (ch + 1)); // volca sample trriger on } // send off pulses to spare output for the first channel if (!(BitRead(beat_holder[ch], read_head)) && !ch) { // only relates to first channel if (!gatesoff) { gCLOCKOUT = true; } sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 5, EUCLID)); sendMes.setArgs("i", 1); osc.sendOsc(&sendMes); lights_active = pulses_active = true; } // move counter to next position, ready for next pulse ++channelbeats[ch][2]; if ((channelbeats[ch][2]) >= (channelbeats[ch][0])) { channelbeats[ch][2] = 0; } } ++masterclock; masterclock &= (MAXSTEPS - 1); pulse_length = ((euc_time - last_sync) / 5); last_sync = euc_time; } /* 3 functions to read each encoder returns +1, 0 or -1 dependent on direction Contains no internal debounce, so calls should be delayed */ //------------------------------------------------------------- // Check Euclidean Seq N(length) Value int EncodeReadN(int ch) { static float _enc[4]; int result = 0; switch (ch) { case 0: if (gEucA[0] == 0) { _enc[ch] = result = 0; } else if (gEucA[0] < _enc[ch]) { result = -1; _enc[ch] = gEucA[0]; } else if (gEucA[0] > _enc[ch]) { result = 1; _enc[ch] = gEucA[0]; } break; case 1: if (gEucA[3] == 0) { _enc[ch] = result = 0; } else if (gEucA[3] < _enc[ch]) { result = -1; _enc[ch] = gEucA[3]; } else if (gEucA[3] > _enc[ch]) { result = 1; _enc[ch] = gEucA[3]; } break; case 2: if (gEucB[0] == 0) { _enc[ch] = result = 0; } else if (gEucB[0] < _enc[ch]) { result = -1; _enc[ch] = gEucB[0]; } else if (gEucB[0] > _enc[ch]) { result = 1; _enc[ch] = gEucB[0]; } break; case 3: if (gEucB[3] == 0) { _enc[ch] = result = 0; } else if (gEucB[3] < _enc[ch]) { result = -1; _enc[ch] = gEucB[3]; } else if (gEucB[3] > _enc[ch]) { result = 1; _enc[ch] = gEucB[3]; } break; default: break; } return result; } //------------------------------------------------------------- // Check Euclidean Seq K(Density) Value int EncodeReadK(int ch) { static float _enc[4]; int result = 0; switch (ch) { case 0: if (gEucA[1] == 0) { _enc[ch] = result = 0; } else if (gEucA[1] < _enc[ch]) { result = -1; _enc[ch] = gEucA[1]; } else if (gEucA[1] > _enc[ch]) { result = 1; _enc[ch] = gEucA[1]; } break; case 1: if (gEucA[4] == 0) { _enc[ch] = result = 0; } else if (gEucA[4] < _enc[ch]) { result = -4; _enc[ch] = gEucA[4]; } else if (gEucA[4] > _enc[ch]) { result = 4; _enc[ch] = gEucA[4]; } break; case 2: if (gEucB[1] == 0) { _enc[ch] = result = 0; } else if (gEucB[1] < _enc[ch]) { result = -1; _enc[ch] = gEucB[1]; } else if (gEucB[1] > _enc[ch]) { result = 1; _enc[ch] = gEucB[1]; } break; case 3: if (gEucB[4] == 0) { _enc[ch] = result = 0; } else if (gEucB[4] < _enc[ch]) { result = -1; _enc[ch] = gEucB[4]; } else if (gEucB[4] > _enc[ch]) { result = 1; _enc[ch] = gEucB[4]; } break; default: break; } return result; } //------------------------------------------------------------- // Check Euclidean Seq O(Offset) Value int EncodeReadO(int ch) { static float _enc[4]; int result = 0; switch (ch) { case 0: if (gEucA[2] == 0) { _enc[ch] = result = 0; } else if (gEucA[2] < _enc[ch]) { result = -1; _enc[ch] = gEucA[2]; } else if (gEucA[2] > _enc[ch]) { result = 1; _enc[ch] = gEucA[2]; } break; case 1: if (gEucA[5] == 0) { _enc[ch] = result = 0; } else if (gEucA[5] < _enc[ch]) { result = -1; _enc[ch] = gEucA[5]; } else if (gEucA[5] > _enc[ch]) { result = 1; _enc[ch] = gEucA[5]; } break; case 2: if (gEucB[2] == 0) { _enc[ch] = result = 0; } else if (gEucB[2] < _enc[ch]) { result = -1; _enc[ch] = gEucB[2]; } else if (gEucB[2] > _enc[ch]) { result = 1; _enc[ch] = gEucB[2]; } break; case 3: if (gEucB[5] == 0) { _enc[ch] = result = 0; } else if (gEucB[5] < _enc[ch]) { result = -1; _enc[ch] = gEucB[5]; } else if (gEucB[5] > _enc[ch]) { result = 1; _enc[ch] = gEucB[5]; } break; default: break; } return result; }