OSC-CV Converter
Dependencies: Bonjour OSCReceiver TextLCD mbed mbed-rpc BurstSPI DebouncedInterrupt FastIO MIDI OSC OSCtoCV ClockControl
OSC to CV Converter
http://gtbts.tumblr.com/post/125663817741/osc-to-cv-converter-ver2-mbed-osctocv
Revision 15:3e4bc47d6a39, committed 2015-08-02
- Comitter:
- casiotone401
- Date:
- Sun Aug 02 10:01:07 2015 +0000
- Parent:
- 14:977f3c5a4b4e
- Child:
- 16:1196b8c87bb7
- Commit message:
- ver. 2
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/BurstSPI.lib Sun Aug 02 10:01:07 2015 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/Sissors/code/BurstSPI/#bc069279eb37
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DebouncedInterrupt.lib Sun Aug 02 10:01:07 2015 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/kandangath/code/DebouncedInterrupt/#9733f886810a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FastIO.lib Sun Aug 02 10:01:07 2015 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/Sissors/code/FastIO/#87872fcf8586
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MIDI.lib Sun Aug 02 10:01:07 2015 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/okini3939/code/MIDI/#0eeca7deec08
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/OSC.lib Sun Aug 02 10:01:07 2015 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/users/casiotone401/code/OSC/#507dea4cc97a
--- a/example.h Thu Oct 16 14:14:25 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,675 +0,0 @@ -//------------------------------------------------------------- -// TI DAC8568 OSC-CV Converter -// -// DAC8568 16bit Octal DAC http://www.ti.com/product/dac8568 -// -// referred to -// xshige's OSCReceiver -// http://mbed.org/users/xshige/programs/OSCReceiver/ -// radiojunkbox's OSC-CV_Example -// http://mbed.org/users/radiojunkbox/code/KAMUI_OSC-CV_Example/ -// Robin Price's Homebrew midi-cv box -// http://crx091081gb.net/?p=69 -// Masahiro Hattori's TextLCD Module Functions -// http://www.eleclabo.com/denshi/device/lcd1602/gcram.html -// Dirk-Willem van Gulik's BonjourLib -// http://mbed.org/users/dirkx/code/BonjourLib/file/bb6472f455e8/services/mDNS -// -// Released under the MIT License: http://mbed.org/license/mit -//------------------------------------------------------------- - -#pragma O3 -#pragma Otime - -#include "mbed.h" -#include "TextLCD.h" //edit "writeCommand" "writeData" protected -> public -#include "EthernetNetIf.h" -#include "HTTPServer.h" -#include "mDNSResponder.h" // mDNS response to announce oneselve -#include "UDPSocket.h" -#include "OSCReceiver.h" -#include <stdlib.h> -#include <ctype.h> -#include <math.h> - -//------------------------------------------------------------- -// Define - -#define MODE_LIN 0 // Linear ~LinearCV Mode -#define MODE_QChr 1 // Chromatic ~Quantize Mode -#define MODE_QMaj 2 // Major -#define MODE_QDor 3 // Dorian -#define MODE_Q5th 4 // 5th -#define MODE_QWht 5 // Wholetone -#define MODE_Calb 6 // Calibration - -#define QUAN_RES1 116 // Quantize voltage Steps -#define QUAN_RES2 69 -#define QUAN_RES3 68 -#define QUAN_RES4 17 -#define QUAN_RES5 58 - -#define MODE_NUM 7 // Modes - -#define SPI_RATE 40000000 // 40Mbps SPI Clock -#define SCALING_N 38400.0 -#define INPUT_PORT 12345 // Input Port Number - -#define POLLING_INTERVAL 20 // Polling Interval (us) - -//------------------------------------------------------------- -// DAC8568 Control Bits - -#define WRITE 0x00 -#define UPDATE 0x01 -#define WRITE_UPDATE_ALL 0x02 // LDAC Write to Selected Update All -#define WRITE_UPDATE_N 0x03 // LDAC Write to Selected Update Respective -#define POWER 0x04 -#define CLR 0x05 // Clear Code Register -#define WRITE_LDAC_REG 0x06 -#define RESET 0x07 // Software Reset DAC8568 -#define SETUP_INTERNAL_REF 0x08 - -//------------------------------------------------------------- - -#define _DISABLE 0 -#define _ENABLE 1 - -//------------------------------------------------------------- -// Functions - -inline void NetPoll(void); -void InitOSCCV(void); -inline void UpdateCV(int, int, const unsigned int*); -void SetCV(void); -void CheckSW(void); -void CVMeter(int, const unsigned int*); -void WriteCustomChar(unsigned char, unsigned char*); -int SetupEthNetIf(void); -void onUDPSocketEvent(UDPSocketEvent); - -//------------------------------------------------------------- -// Silentway Calibration Data Mapping -// http://www.expert-sleepers.co.uk/silentway.html - -// Chromatic Scale -const float calibMap1[QUAN_RES1] = { -0.00663080, 0.01433030, 0.02202980, 0.02972930, 0.03742880, -0.04512830, 0.05282781, 0.06052731, 0.06822681, 0.07592630, -0.08362581, 0.09132531, 0.09902481, 0.10672431, 0.11442380, -0.12212331, 0.12951356, 0.13671936, 0.14392516, 0.15113096, -0.15833676, 0.16554256, 0.17274836, 0.17995416, 0.18715996, -0.19436575, 0.20157155, 0.20877735, 0.21598317, 0.22318897, -0.23039477, 0.23760056, 0.24480636, 0.25202271, 0.25926629, -0.26650983, 0.27375340, 0.28099698, 0.28824055, 0.29548413, -0.30272770, 0.30997124, 0.31721482, 0.32445839, 0.33170196, -0.33894554, 0.34618911, 0.35343266, 0.36067623, 0.36791980, -0.37516347, 0.38241133, 0.38965923, 0.39690709, 0.40415496, -0.41140282, 0.41865072, 0.42589858, 0.43314645, 0.44039431, -0.44764221, 0.45489007, 0.46213794, 0.46938580, 0.47663370, -0.48388156, 0.49112943, 0.49837729, 0.50566339, 0.51296055, -0.52025765, 0.52755481, 0.53485191, 0.54214907, 0.54944617, -0.55674326, 0.56404042, 0.57133752, 0.57863468, 0.58593178, -0.59322894, 0.60052603, 0.60782319, 0.61512029, 0.62241745, -0.62976688, 0.63714498, 0.64452308, 0.65190119, 0.65927929, -0.66665739, 0.67403549, 0.68141359, 0.68879169, 0.69616979, -0.70354789, 0.71092600, 0.71830410, 0.72568226, 0.73306036, -0.74043846, 0.74781656, 0.75820577, 0.76986063, 0.78151548, -0.79317033, 0.80482519, 0.81648004, 0.82813489, 0.83978975, -0.85144460, 0.86309946, 0.87475431, 0.90686423, 0.93941462, -0.97196496 -}; - -// Major Scale -const float calibMap2[QUAN_RES2] = { -0.00663080, 0.01433030, 0.02972930, 0.04512830, 0.05282781, -0.06822681, 0.08362581, 0.09902481, 0.10672431, 0.12212331, -0.13671936, 0.14392516, 0.15833676, 0.17274836, 0.18715996, -0.19436575, 0.20877735, 0.22318897, 0.23039477, 0.24480636, -0.25926629, 0.27375340, 0.28099698, 0.29548413, 0.30997124, -0.31721482, 0.33170196, 0.34618911, 0.36067623, 0.36791980, -0.38241133, 0.39690709, 0.40415496, 0.41865072, 0.43314645, -0.44764221, 0.45489007, 0.46938580, 0.48388156, 0.49112943, -0.50566339, 0.52025765, 0.53485191, 0.54214907, 0.55674326, -0.57133752, 0.57863468, 0.59322894, 0.60782319, 0.62241745, -0.62976688, 0.64452308, 0.65927929, 0.66665739, 0.68141359, -0.69616979, 0.71092600, 0.71830410, 0.73306036, 0.74781656, -0.75820577, 0.78151548, 0.80482519, 0.82813489, 0.83978975, -0.86309946, 0.90686423, 0.93941462 -}; - -// Dorian Scale -const float calibMap3[QUAN_RES3] = { -0.00663080, 0.01433030, 0.02972930, 0.04512830, 0.06052731, -0.06822681, 0.08362581, 0.09902481, 0.10672431, 0.12212331, -0.13671936, 0.15113096, 0.15833676, 0.17274836, 0.18715996, -0.19436575, 0.20877735, 0.22318897, 0.23760056, 0.24480636, -0.25926629, 0.27375340, 0.28099698, 0.29548413, 0.30997124, -0.32445839, 0.33170196, 0.34618911, 0.36067623, 0.36791980, -0.38241133, 0.39690709, 0.41140282, 0.41865072, 0.43314645, -0.44764221, 0.45489007, 0.46938580, 0.48388156, 0.49837729, -0.50566339, 0.52025765, 0.53485191, 0.54214907, 0.55674326, -0.57133752, 0.58593178, 0.59322894, 0.60782319, 0.62241745, -0.62976688, 0.64452308, 0.65927929, 0.67403549, 0.68141359, -0.69616979, 0.71092600, 0.71830410, 0.73306036, 0.74781656, -0.76986063, 0.78151548, 0.80482519, 0.82813489, 0.83978975, -0.86309946, 0.90686423, 0.97196496 -}; - -// 5th -const float calibMap4[QUAN_RES4] = { -0.00663080, 0.06052731, 0.11442380, 0.16554256, 0.21598317, -0.26650983, 0.31721482, 0.36791980, 0.41865072, 0.46938580, -0.52025765, 0.57133752, 0.62241745, 0.67403549, 0.72568226, -0.79317033, 0.87475431 - -}; - -// Whole tone -const float calibMap5[QUAN_RES5] = { -0.00663080, 0.02202980, 0.03742880, 0.05282781, 0.06822681, -0.08362581, 0.09902481, 0.11442380, 0.12951356, 0.14392516, -0.15833676, 0.17274836, 0.18715996, 0.20157155, 0.21598317, -0.23039477, 0.24480636, 0.25926629, 0.27375340, 0.28824055, -0.30272770, 0.31721482, 0.33170196, 0.34618911, 0.36067623, -0.37516347, 0.38965923, 0.40415496, 0.41865072, 0.43314645, -0.44764221, 0.46213794, 0.47663370, 0.49112943, 0.50566339, -0.52025765, 0.53485191, 0.54944617, 0.56404042, 0.57863468, -0.59322894, 0.60782319, 0.62241745, 0.63714498, 0.65190119, -0.66665739, 0.68141359, 0.69616979, 0.71092600, 0.72568226, -0.74043846, 0.75820577, 0.78151548, 0.80482519, 0.82813489, -0.85144460, 0.87475431, 0.93941462 - -}; - -//------------------------------------------------------------- -// CV Meter Custom Character - -const unsigned char str1[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F}; -const unsigned char str2[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F}; -const unsigned char str3[8] = {0x00,0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F}; -const unsigned char str4[8] = {0x00,0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F}; -const unsigned char str5[8] = {0x00,0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F}; -const unsigned char str6[8] = {0x00,0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}; -const unsigned char str7[8] = {0x00,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}; -const unsigned char str8[8] = {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F}; - -//------------------------------------------------------------- -// Global Variables - -static float gOSC_cv[8]; -static float gGlide; -unsigned int gMode; - -//------------------------------------------------------------- -// mbed Functions - -TextLCD gLCD(p9, p10, p11, p12, p13, p14); // rs, e, d4-d7 - -SPI gSPI(p5,p6,p7); // SPI (p6 unconnected) -DigitalOut gSYNCMODE(p15); // SYNC DAC8568 -DigitalOut gLDAC(p16); // LDAC DAC8568 - -DigitalOut gGATES[4] = {p21, p22, p23, p24}; // GateOut -DigitalOut gLEDS[4] = {p18, p19, p20, p28}; // LED -DigitalOut gCLOCKOUT(p25); // ClockOut - -AnalogIn gAIN(p17); // Glide Potentiometer -InterruptIn gSW(p30); // Mode SW - -Ticker gSetter; // Ticker SetCV -Ticker gPoller; // Ticker Polling - -// Ethernet -EthernetNetIf gEth; -UDPSocket gUdp; - -//------------------------------------------------------------- -// main - -int main() -{ - int i; - float pot, _pot; - - if(SetupEthNetIf() == -1) - { - for(i = 0; i < 4; i++) - { - gLEDS[i] = 1; - wait(0.25); - } - return -1; - } - - // mdns (Bonjour) - HTTPServer svr; - mDNSResponder mdns; - - svr.addHandler<SimpleHandler>("/"); - svr.bind(INPUT_PORT); - IpAddr ip = gEth.getIp(); - mdns.announce(ip, "OSCtoCV", "_osc._udp", INPUT_PORT, "mbed(OSCtoCV)", (char *[]) {"path=/",NULL}); - - InitOSCCV(); - - pot = _pot = 0; - gGlide = gMode = 0; - - gLCD.locate( 9, 0 ); - gLCD.printf("OSC-CV"); - gLCD.locate( 0, 1 ); - gLCD.printf("12345678 G>>%3.2f", gGlide); - - // loop - while(1) - { - gGlide = pot = gAIN.read(); - - if(abs(pot - _pot) > 0.01f) - { - gLCD.locate( 0, 1 ); - gLCD.printf("12345678 G>>%3.2f", gGlide); - - _pot = gAIN.read(); - } - - SetCV(); - } -} - -//------------------------------------------------------------- -// Ethernet Polling - -inline void NetPoll() -{ - Net::poll(); -} - -//------------------------------------------------------------- -// Initialize OSC-CV - -void InitOSCCV() -{ - // write custom char LCD CGRAM - WriteCustomChar(0x00, str1); - WriteCustomChar(0x01, str2); - WriteCustomChar(0x02, str3); - WriteCustomChar(0x03, str4); - WriteCustomChar(0x04, str5); - WriteCustomChar(0x05, str6); - WriteCustomChar(0x06, str7); - WriteCustomChar(0x07, str8); - - // Init. SPI - gLDAC = _ENABLE; - gSPI.format(8,1); // Data word length 8bit, Mode=1 - gSPI.frequency(SPI_RATE); - - UpdateCV(CLR, 0, 0); // Ignore CLR Pin - - gSW.mode(PullUp); // Use internal pullup for ModeSW - wait(.001); - - gSW.rise(&CheckSW); // InterruptIn rising edge(ModeSW) - gPoller.attach_us(&NetPoll, POLLING_INTERVAL); // Ticker Polling - - wait(0.2); -} - -//------------------------------------------------------------- -// SPI Transfer -// DAC8568 data word length 32bit (8bit shift out) - -inline void UpdateCV(int control, int address, const unsigned int *data) -{ - __disable_irq(); - - switch(control) - { - case WRITE_UPDATE_N: - { - gSYNCMODE = _DISABLE; - gSPI.write(00000000|control); // padding at beginning of byte and control bits - gSPI.write(address << 4 | *data >> 12); // address(ch) bits - gSPI.write((*data << 4) >> 8); // middle 8 bits of data - gSPI.write((*data << 12) >> 8 | 00001111); - gSYNCMODE = _ENABLE; - gLDAC = _DISABLE; - gLDAC = _ENABLE; - break; - } - case RESET: - { - gSYNCMODE = _DISABLE; - gSPI.write(00000111); // Software RESET - gSPI.write(00000000); - gSPI.write(00000000); - gSPI.write(00000000); - gSYNCMODE = _ENABLE; - break; - } - case CLR: - { - gSYNCMODE = _DISABLE; - gSPI.write(00000101); // CLR Register - gSPI.write(00000000); - gSPI.write(00000000); - gSPI.write(00000011); // Ignore CLR Pin - gSYNCMODE = _ENABLE; - break; - } - } - - __enable_irq(); -} - -//------------------------------------------------------------- -// Calculate CV - -void SetCV() -{ - static int ch; - float glidecv[8]; - unsigned int cv[8]; - static float oldcv[8]; - static unsigned int quan; - float qcv; - - switch(gMode) - { - case MODE_LIN: - - glidecv[ch] = oldcv[ch] * gGlide + gOSC_cv[ch] * (1.0f - gGlide); - oldcv[ch] = glidecv[ch]; - cv[ch] = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); - break; - - case MODE_QChr: - - quan = 40616 / QUAN_RES1; - qcv = calibMap1[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - oldcv[ch] = glidecv[ch]; - cv[ch] = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); - break; - - case MODE_QMaj: - - quan = 40616 / QUAN_RES2; - qcv = calibMap2[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - oldcv[ch] = glidecv[ch]; - cv[ch] = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); - break; - - case MODE_QDor: - - quan = 40616 / QUAN_RES3; - qcv = calibMap3[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - oldcv[ch] = glidecv[ch]; - cv[ch] = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); - break; - - case MODE_Q5th: - - quan = 40616 / QUAN_RES4; - qcv = calibMap4[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - oldcv[ch] = glidecv[ch]; - cv[ch] = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); - break; - - case MODE_QWht: - - quan = 40616 / QUAN_RES5; - qcv = calibMap5[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = oldcv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - oldcv[ch] = glidecv[ch]; - cv[ch] = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); - break; - - case MODE_Calb: - - cv[ch] = 19212; // A440.0Hz - - UpdateCV(WRITE_UPDATE_N, ch, &cv[ch]); - break; - } - - CVMeter(ch, &cv[ch]); - ch++; - ch &= 0x07; -} - -//------------------------------------------------------------- -// Check SW - -void CheckSW() -{ - if(gMode < MODE_NUM - 1) - { - gMode++; - - } else { - - gMode = 0; - } - - switch(gMode) - { - case MODE_LIN: - gLCD.locate( 9, 0 ); - gLCD.printf("OSC-CV "); - break; - - case MODE_QChr: - gLCD.locate( 9, 0 ); - gLCD.printf("QUAN_C "); - break; - - case MODE_QMaj: - gLCD.locate( 9, 0 ); - gLCD.printf("QUAN_M "); - break; - - case MODE_QDor: - gLCD.locate( 9, 0 ); - gLCD.printf("QUAN_D "); - break; - - case MODE_Q5th: - gLCD.locate( 9, 0 ); - gLCD.printf("QUAN_5 "); - break; - - case MODE_QWht: - gLCD.locate( 9, 0 ); - gLCD.printf("QUAN_W "); - break; - - case MODE_Calb: - gLCD.locate( 9, 0 ); - gLCD.printf("Calibr "); - break; - } -} - -//------------------------------------------------------------- -// CV meter - -void CVMeter(int ch, const unsigned int *level) -{ - unsigned int cvmeter; - - cvmeter = *level / 4860; - // cvmeter = *level / (SCALING_N / 7.9); - - gLCD.locate ( ch, 0 ); - gLCD.putc(cvmeter); // put custom char -} - -//------------------------------------------------------------- -// Write command Custom Char LCD CGRAM(CV Meter) - -void WriteCustomChar(unsigned char addr, unsigned char *c) -{ - char cnt = 0; - addr = ((addr << 3) | 0x40); - - while(cnt < 0x08) - { - gLCD.writeCommand(addr | cnt); - gLCD.writeData(*c); - cnt++; - c++; - } -} - -//------------------------------------------------------------- -// Setup Ethernet port - -int SetupEthNetIf() -{ - gLCD.locate( 0, 1 ); - gLCD.printf("Setting up... "); -// printf("Setting up...\r\n"); - EthernetErr ethErr = gEth.setup(); - - if(ethErr) - { - gLCD.locate( 0, 1 ); - gLCD.printf("Error in setup."); -// printf("Error %d in setup.\r\n", ethErr); - - return -1; - } -// printf("Setup OK\r\n"); - -// printf("IP address %d.%d.%d.%d\r\n", gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], gEth.getIp()[3]); - Host broadcast(IpAddr(gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], 255), INPUT_PORT, NULL); - gUdp.setOnEvent(&onUDPSocketEvent); - gUdp.bind(broadcast); - - gLCD.locate( 0, 1 ); - gLCD.printf("%03d.%03d.%03d.%03d", gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], gEth.getIp()[3]); - wait(2.0); - - return 0; -} - -//------------------------------------------------------------- -// Handller receive UDP Packet - -void onUDPSocketEvent(UDPSocketEvent e) -{ - union OSCarg msg[10]; - static int num; - - switch(e) - { - case UDPSOCKET_READABLE: // The only event for now - char buf[256] = {0}; - Host host; - - while( int len = gUdp.recvfrom( buf, 256, &host )) - { - if(len <= 0) break; - // printf("\r\nFrom %d.%d.%d.%d:\r\n", - // host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3]); - - getOSCmsg(buf,msg); - // printf("OSCmsg: %s %s %f %i\r\n", - // msg[0].address, msg[1].typeTag, msg[2].f, msg[2].i); - - len = strlen(msg[0].address); - if(isdigit(msg[0].address[len-1])) num = msg[0].address[len-1] - '0' - 1; - else num = -1; - - unsigned int absv = msg[2].f + 0; //convert -0 to 0 - - // address pattern SYNC & GATE (Type Tag int, float) - if((strncmp(msg[0].address+(len-1)-4, "sync", 4)==0) && (num == -1)) { - if(num > 1) break; - if(absv >= 1 || msg[2].i >= 1) gCLOCKOUT = 1; - else gCLOCKOUT = 0; - break; - - } else if ((strncmp(msg[0].address+(len-1)-4, "gate", 4)==0) && (num != -1)) { - if(num > 3) break; - if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; - break; - // (touchOSC Control push, toggle) - } else if ((strncmp(msg[0].address+(len-1)-4, "push", 4)==0) && (num != -1)) { - if(num > 3) break; - if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; - break; - - } else if ((strncmp(msg[0].address+(len-1)-6, "toggle", 6)==0) && (num != -1)) { - if(num > 3) break; - if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; - break; - - } else if ((strncmp(msg[0].address,"/1/multipush",12)==0) && (num != -1)) { - if(num > 3) break; - if(absv >= 1 || msg[2].i >= 1) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; - break; - } - - // address pattern CV (Type Tag float) - if((strncmp(msg[0].address+(len-1)-2, "cv", 2)==0) && (num != -1)) { - if(num > 7) break; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - break; - // (touchOSC Control fader, rotary, xy, multixy, multifader) - } else if ((strncmp(msg[0].address+(len-1)-5, "fader", 5)==0) && (num != -1)) { - if(num > 7) break; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - break; - - } else if ((strncmp(msg[0].address+(len-1)-6, "rotary", 6)==0) && (num != -1)) { - if(num > 7) break; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - break; - - } else if ((strncmp(msg[0].address+(len-1)-2, "xy", 2)==0) && (num != -1)) { - if(num > 7) break; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - if(msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N); - break; - - } else if ((strncmp(msg[0].address+(len-1)-9, "multixy1/", 9)==0) && (num != -1)) { - if(num > 7) break; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - if(msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N); - break; - - } else if ((strncmp(msg[0].address+(len-1)-12, "multifader1/", 12)==0) && (num != -1)) { - if(num > 7) break; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - } - } - } - }
--- a/main.cpp Thu Oct 16 14:14:25 2014 +0000 +++ b/main.cpp Sun Aug 02 10:01:07 2015 +0000 @@ -1,5 +1,7 @@ //------------------------------------------------------------- -// TI DAC8568 OSC-CV Converter +// OSCtoCV Converter +// Schematic, touchOSC template & VST Plug-in +// http://gtbts.tumblr.com/post/125663817741/osc-to-cv-converter-ver2-mbed-osctocv // // DAC8568 16bit Octal DAC http://www.ti.com/product/dac8568 // @@ -14,6 +16,9 @@ // http://www.eleclabo.com/denshi/device/lcd1602/gcram.html // Dirk-Willem van Gulik's BonjourLib // http://mbed.org/users/dirkx/code/BonjourLib/file/bb6472f455e8/services/mDNS +// ADDAC System & sneak-thief's Euclidean Polyrhythm generator +// https://github.com/addacsystem/ADDAC-Library +// https://www.muffwiggler.com/forum/viewtopic.php?p=1451228#1451228 // // Released under the MIT License: http://mbed.org/license/mit //------------------------------------------------------------- @@ -22,12 +27,17 @@ #pragma Otime #include "mbed.h" +#include "FastIO.h" +#include "DebouncedInterrupt.h" +#include "BurstSPI.h" #include "TextLCD.h" //edit "writeCommand" "writeData" protected -> public #include "EthernetNetIf.h" #include "HTTPServer.h" #include "mDNSResponder.h" // mDNS response to announce oneselve #include "UDPSocket.h" #include "OSCReceiver.h" +#include "mbedOSC.h" +#include "MIDI.h" #include <stdlib.h> #include <ctype.h> #include <math.h> @@ -36,10 +46,12 @@ // Define #define MODE_Calb 0 // Calibration (for VCO Tuning) -#define MODE_LIN 1 // Linear LinearCV -#define MODE_SEQ 2 // Mode Shift - -#define MODE_NUM 3 // Modes +#define MODE_OSC 1 // Mode OSCtoCV +#define MODE_SEQ 2 // Mode Shift Sequencer +#define MODE_185 3 // Mode M185 Sequencer +#define MODE_EUC 4 // Mode Euclidean Sequencer + +#define MODE_TOTAL 5 // Modes #define Lin 0 // Linear LinearCV #define Chr 1 // Chromatic @@ -51,17 +63,20 @@ #define S5th 7 // 5th #define Wht 8 // Wholetone -#define QUAN_RES1 115 // Quantize voltage Steps -#define QUAN_RES2 67 -#define QUAN_RES3 39 -#define QUAN_RES4 48 -#define QUAN_RES5 67 -#define QUAN_RES6 67 -#define QUAN_RES7 17 -#define QUAN_RES8 57 - -#define SPI_RATE 20000000 // 20Mbps SPI Clock -#define SCALING_N 38400.0 +#define SCALE_NUM 9 // Count Scale +#define SCALE_AOUT (65535 / SCALE_NUM - 1) + +#define QUAN_RES1 116 // Quantize voltage Steps +#define QUAN_RES2 68 +#define QUAN_RES3 46 +#define QUAN_RES4 40 +#define QUAN_RES5 68 +#define QUAN_RES6 68 +#define QUAN_RES7 16 +#define QUAN_RES8 58 + +#define SPI_RATE 20000000 // 10Mbps SPI Clock +#define SCALING_N 32256.0f #define INPUT_PORT 12345 // Input Port Number #define POLLING_INTERVAL 20 // Polling Interval (us) @@ -80,6 +95,7 @@ #define SETUP_INTERNAL_REF 0x08 //------------------------------------------------------------- +// Gate Sequencer Macros #define _DISABLE 0 #define _ENABLE 1 @@ -88,7 +104,17 @@ #define GATE2 1 #define GATE3 2 #define GATE4 3 -#define GATEALL 4 +#define SUBGATE 4 +#define GATE_TOTAL 5 + +#define INVERT 1 +#define NON_INVERT 0 + +#define GATESOUT_ON 0 +#define GATESOUT_OFF 1 + +#define SYNC_ON 0 +#define SYNC_OFF 1 //------------------------------------------------------------- // Beats (Note values) @@ -97,174 +123,217 @@ #define N2ND 2 // harf #define N4TH 4 // quarter #define N8TH 8 -#define N16TH 16 -#define N32TH 32 -#define N64TH 64 +#define N16TH 16 +#define N32TH 32 +#define N64TH 64 #define NDOT2 3 // dotted #define NDOT4 7 #define NDOT8 9 -#define NDOT16 11 -#define NDOT32 13 -#define TRIP2 15 // triplets -#define TRIP4 17 -#define TRIP8 19 -#define TRIP16 21 -#define TRIP32 23 +#define NDOT16 11 +#define NDOT32 13 +#define TRIP2 3 // triplets +#define TRIP4 6 +#define TRIP8 12 +#define TRIP16 24 +#define TRIP32 48 +#define SYNC24 96 #define NRESET 0 // Gate Reset +//------------------------------------------------------------- +// Sequencer Macros + +#define STEP_INDICATOR_ADDRESS "/seqstep/" // touchOSC multi toggle(1x16(8)) for Current Step Indicator +#define RESET_COUNTER_ADDRESS "/reset" // touchOSC label for Sequencer reset count + +//------------------------------------------------------------- +// M185 Macros + +#define PULSE_COUNT_ADDRESS "/pulse" // /pulse1 ~ pulse8 M185 Pulse Count +#define GATE_MODE_ADDRESS "/gatemode" // /gatemode1 ~ gatemode8 M185 Gate Mode + +#define SINGLE 0 +#define MUTE 1 +#define MULTI 2 +#define HOLD 3 + +//------------------------------------------------------------- +// Euclidean Sequencer Macros + +#define READ_DELAY 10 // for debouncing +#define MAXCHANNELS 4 +#define MAXSTEPS 16 // max step length +#define TRIGGER_DURATION 2200 + +#define DISPLAY_UPDATE 2000 // how long active channel display is shown +#define MATRIX_ADDRESS "/matrix/" // touchOSC multi toggle(9x16) OSC address + + //------------------------------------------------------------- // Functions +void InitOSCCV(void); inline void NetPoll(void); -void InitOSCCV(void); +inline float MapFloat(float, float, float, float, float); inline void UpdateCV(int, int, const unsigned int*); -inline void CalibCV(void); -inline void SetSCV(void); -inline void SeqCV(int); -inline void Seq(void); -inline int UpdateGate(int, int, int, int, bool); -inline void UpdateSync(int, int, bool); -void CheckModeSW(void); -inline void CVMeter(int, const unsigned int*); -void LCD(); +inline void CalibrationCV(void); +inline void SetCV(void); +inline void ShiftCVSeq(int, bool); +inline void M185Seq(int, bool); +inline void SendCtrlState(uint8_t, uint8_t, uint8_t); +inline int GateSeq(int, int, int, int, bool, bool, bool); +inline int CheckBPM(void); +inline void CheckModeSW(void); +inline void LCD(); +inline void UpdateCVMeter(int, const unsigned int*); void WriteCustomChar(unsigned char, unsigned char*); int SetupEthNetIf(void); inline size_t strlength(const char *); inline void onUDPSocketEvent(UDPSocketEvent); +void EuclideanSeq(int, bool, bool); +unsigned int Euclid(int, int, int); +inline int BitRead(uint16_t, int); +uint16_t BitReadOffset(int, uint16_t, uint16_t); +unsigned int ConcatBin(unsigned int, unsigned int); +void Sync(int, bool); +int EncodeReadN(int); +int EncodeReadK(int); +int EncodeReadO(int); +inline char * SetMatrixAddress(int, int, bool); //------------------------------------------------------------- // Silentway Calibration Data Mapping // http://www.expert-sleepers.co.uk/silentway.html -// Chromatic Scale +// Chromatic Scale const float calibMap1[QUAN_RES1] = { -0.00331362, 0.01097947, 0.01864531, 0.02631116, 0.03397701, -0.04164285, 0.04930869, 0.05697454, 0.06464039, 0.07230624, -0.07997208, 0.08763793, 0.09530377, 0.10296962, 0.11063547, -0.11830132, 0.12590303, 0.13306051, 0.14021800, 0.14737549, -0.15453300, 0.16169049, 0.16884798, 0.17600547, 0.18316296, -0.19032045, 0.19747795, 0.20463544, 0.21179293, 0.21895042, -0.22610791, 0.23326540, 0.24042290, 0.24758039, 0.25476459, -0.26196238, 0.26916021, 0.27635801, 0.28355584, 0.29075363, -0.29795146, 0.30514926, 0.31234708, 0.31954488, 0.32674271, -0.33394051, 0.34113833, 0.34833613, 0.35553396, 0.36273175, -0.36992958, 0.37713069, 0.38433966, 0.39154866, 0.39875764, -0.40596664, 0.41317561, 0.42038459, 0.42759359, 0.43480256, -0.44201156, 0.44922054, 0.45642951, 0.46363851, 0.47084749, -0.47805649, 0.48526546, 0.49247447, 0.49968344, 0.50694764, -0.51421440, 0.52148110, 0.52874786, 0.53601462, 0.54328132, -0.55054808, 0.55781484, 0.56508154, 0.57234830, 0.57961506, -0.58688176, 0.59414852, 0.60141528, 0.60868198, 0.61594874, -0.62321550, 0.63052768, 0.63785475, 0.64518178, 0.65250880, -0.65983582, 0.66716284, 0.67448992, 0.68181694, 0.68914396, -0.69647098, 0.70379800, 0.71112502, 0.71845210, 0.72577912, -0.73310614, 0.74043316, 0.74776018, 0.75861782, 0.77102989, -0.78344196, 0.79585397, 0.80826604, 0.82067811, 0.83309019, -0.84550226, 0.85791427, 0.87032634, 0.90296346, 0.94781560 +0.00076928, 0.00900736, 0.01724544, 0.02548352, 0.03372160, +0.04195968, 0.05019776, 0.05843584, 0.06667392, 0.07491200, +0.08315008, 0.09138816, 0.09962624, 0.10786432, 0.11610240, +0.12434047, 0.13258974, 0.14083999, 0.14909023, 0.15734047, +0.16559070, 0.17384095, 0.18209119, 0.19034143, 0.19859168, +0.20684192, 0.21509215, 0.22334240, 0.23159264, 0.23984288, +0.24809311, 0.25634655, 0.26460093, 0.27285531, 0.28110969, +0.28936407, 0.29761845, 0.30587283, 0.31412721, 0.32238159, +0.33063596, 0.33889034, 0.34714472, 0.35539910, 0.36365348, +0.37190786, 0.38017464, 0.38844886, 0.39672306, 0.40499726, +0.41327149, 0.42154568, 0.42981988, 0.43809411, 0.44636831, +0.45464250, 0.46291673, 0.47119093, 0.47946513, 0.48773935, +0.49601355, 0.50430328, 0.51260746, 0.52091163, 0.52921581, +0.53751999, 0.54582411, 0.55412829, 0.56243247, 0.57073665, +0.57904083, 0.58734500, 0.59564912, 0.60395330, 0.61225748, +0.62056166, 0.62890279, 0.63728637, 0.64566994, 0.65405351, +0.66243708, 0.67082065, 0.67920423, 0.68758780, 0.69597137, +0.70435494, 0.71273851, 0.72112209, 0.72950566, 0.73788923, +0.74627280, 0.75476575, 0.76334614, 0.77192658, 0.78050703, +0.78908741, 0.79766786, 0.80624831, 0.81482869, 0.82340914, +0.83198959, 0.84056997, 0.84915042, 0.85773087, 0.86631125, +0.87489170, 0.88425636, 0.89363104, 0.90300572, 0.91238040, +0.92175508, 0.93112975, 0.94050443, 0.94987911, 0.95925385, +0.96862853 }; // Major Scale const float calibMap2[QUAN_RES2] = { -0.01097947, 0.02631116, 0.03397701, 0.04930869, 0.06464039, -0.07997208, 0.08763793, 0.10296962, 0.11830132, 0.12590303, -0.14021800, 0.15453300, 0.16884798, 0.17600547, 0.19032045, -0.20463544, 0.21179293, 0.22610791, 0.24042290, 0.25476459, -0.26196238, 0.27635801, 0.29075363, 0.29795146, 0.31234708, -0.32674271, 0.34113833, 0.34833613, 0.36273175, 0.37713069, -0.38433966, 0.39875764, 0.41317561, 0.42759359, 0.43480256, -0.44922054, 0.46363851, 0.47084749, 0.48526546, 0.49968344, -0.51421440, 0.52148110, 0.53601462, 0.55054808, 0.55781484, -0.57234830, 0.58688176, 0.60141528, 0.60868198, 0.62321550, -0.63785475, 0.64518178, 0.65983582, 0.67448992, 0.68914396, -0.69647098, 0.71112502, 0.72577912, 0.73310614, 0.74776018, -0.77102989, 0.79585397, 0.80826604, 0.83309019, 0.85791427, -0.87032634, 0.94781560 +calibMap1[0], calibMap1[2], calibMap1[4], calibMap1[5], calibMap1[7], +calibMap1[9], calibMap1[11], calibMap1[12], calibMap1[14], calibMap1[16], +calibMap1[17], calibMap1[19], calibMap1[21], calibMap1[23], calibMap1[24], +calibMap1[26], calibMap1[28], calibMap1[29], calibMap1[31], calibMap1[33], +calibMap1[35], calibMap1[36], calibMap1[38], calibMap1[40], calibMap1[41], +calibMap1[43], calibMap1[45], calibMap1[47], calibMap1[48], calibMap1[50], +calibMap1[52], calibMap1[53], calibMap1[55], calibMap1[57], calibMap1[59], +calibMap1[60], calibMap1[62], calibMap1[64], calibMap1[65], calibMap1[67], +calibMap1[69], calibMap1[71], calibMap1[72], calibMap1[74], calibMap1[76], +calibMap1[77], calibMap1[79], calibMap1[81], calibMap1[83], calibMap1[84], +calibMap1[86], calibMap1[88], calibMap1[89], calibMap1[91], calibMap1[93], +calibMap1[95], calibMap1[96], calibMap1[98], calibMap1[100], calibMap1[101], +calibMap1[103], calibMap1[105], calibMap1[107], calibMap1[108], calibMap1[110], +calibMap1[112], calibMap1[113], calibMap1[115] }; // M7(9) const float calibMap3[QUAN_RES3] = { -0.02631116, 0.04930869, 0.07997208, 0.08763793, 0.11830132, -0.14021800, 0.16884798, 0.17600547, 0.20463544, 0.22610791, -0.25476459, 0.26196238, 0.29075363, 0.31234708, 0.34113833, -0.34833613, 0.37713069, 0.39875764, 0.42759359, 0.43480256, -0.44922054, 0.46363851, 0.48526546, 0.51421440, 0.52148110, -0.55054808, 0.57234830, 0.60141528, 0.60868198, 0.62321550, -0.63785475, 0.65983582, 0.68914396, 0.69647098, 0.72577912, -0.74776018, 0.79585397, 0.85791427, 0.94781560 +calibMap1[0], calibMap1[4], calibMap1[7], calibMap1[11], calibMap1[12], +calibMap1[14], calibMap1[16], calibMap1[19], calibMap1[23], calibMap1[24], +calibMap1[26], calibMap1[28], calibMap1[31], calibMap1[35], calibMap1[36], +calibMap1[38], calibMap1[40], calibMap1[43], calibMap1[47], calibMap1[48], +calibMap1[50], calibMap1[52], calibMap1[55], calibMap1[59], calibMap1[60], +calibMap1[62], calibMap1[64], calibMap1[67], calibMap1[71], calibMap1[72], +calibMap1[76], calibMap1[79], calibMap1[83], calibMap1[84], calibMap1[86], +calibMap1[88], calibMap1[91], calibMap1[95], calibMap1[96], calibMap1[100], +calibMap1[103], calibMap1[107], calibMap1[108], calibMap1[110], calibMap1[112], +calibMap1[115] }; // m7(9) const float calibMap4[QUAN_RES4] = { -0.01097947, 0.01864531, 0.03397701, 0.04930869, 0.07230624, -0.08763793, 0.11063547, 0.14021800, 0.16169049, 0.17600547, -0.19747795, 0.22610791, 0.24042290, 0.24758039, 0.26196238, -0.29075363, 0.31234708, 0.33394051, 0.34833613, 0.36273175, -0.36992958, 0.38433966, 0.39875764, 0.41317561, 0.42038459, -0.43480256, 0.45642951, 0.48526546, 0.50694764, 0.52148110, -0.53601462, 0.55781484, 0.57234830, 0.59414852, 0.62321550, -0.63052768, 0.64518178, 0.65983582, 0.68181694, 0.69647098, -0.71845210, 0.74776018, 0.77102989, 0.78344196, 0.80826604, -0.83309019, 0.84550226, 0.94781560 +calibMap1[0], calibMap1[3], calibMap1[7], calibMap1[10], calibMap1[12], +calibMap1[15], calibMap1[19], calibMap1[22], calibMap1[26], calibMap1[27], +calibMap1[31], calibMap1[34], calibMap1[36], calibMap1[38], calibMap1[39], +calibMap1[43], calibMap1[46], calibMap1[50], calibMap1[53], calibMap1[55], +calibMap1[58], calibMap1[60], calibMap1[63], calibMap1[67], calibMap1[70], +calibMap1[72], calibMap1[74], calibMap1[75], calibMap1[79], calibMap1[82], +calibMap1[86], calibMap1[89], calibMap1[91], calibMap1[94], calibMap1[96], +calibMap1[99], calibMap1[103], calibMap1[106], calibMap1[110], calibMap1[113] }; // Dorian Scale const float calibMap5[QUAN_RES5] = { -0.01097947, 0.02631116, 0.04164285, 0.04930869, 0.06464039, -0.07997208, 0.08763793, 0.10296962, 0.11830132, 0.13306051, -0.14021800, 0.15453300, 0.16884798, 0.17600547, 0.19032045, -0.20463544, 0.21895042, 0.22610791, 0.24042290, 0.25476459, -0.26196238, 0.27635801, 0.29075363, 0.30514926, 0.31234708, -0.32674271, 0.34113833, 0.34833613, 0.36273175, 0.37713069, -0.39154866, 0.39875764, 0.41317561, 0.42759359, 0.43480256, -0.44922054, 0.46363851, 0.47805649, 0.48526546, 0.49968344, -0.51421440, 0.52148110, 0.53601462, 0.55054808, 0.56508154, -0.57234830, 0.58688176, 0.60141528, 0.60868198, 0.62321550, -0.63785475, 0.65250880, 0.65983582, 0.67448992, 0.68914396, -0.69647098, 0.71112502, 0.72577912, 0.74043316, 0.74776018, -0.77102989, 0.79585397, 0.80826604, 0.83309019, 0.85791427, -0.90296346, 0.94781560 +calibMap1[0], calibMap1[2], calibMap1[3], calibMap1[5], calibMap1[7], +calibMap1[9], calibMap1[10], calibMap1[12], calibMap1[14], calibMap1[15], +calibMap1[17], calibMap1[19], calibMap1[20], calibMap1[21], calibMap1[24], +calibMap1[26], calibMap1[27], calibMap1[29], calibMap1[31], calibMap1[33], +calibMap1[34], calibMap1[36], calibMap1[38], calibMap1[39], calibMap1[41], +calibMap1[43], calibMap1[45], calibMap1[46], calibMap1[48], calibMap1[50], +calibMap1[51], calibMap1[53], calibMap1[55], calibMap1[57], calibMap1[58], +calibMap1[60], calibMap1[62], calibMap1[63], calibMap1[65], calibMap1[67], +calibMap1[69], calibMap1[70], calibMap1[72], calibMap1[74], calibMap1[75], +calibMap1[77], calibMap1[79], calibMap1[81], calibMap1[82], calibMap1[84], +calibMap1[86], calibMap1[87], calibMap1[89], calibMap1[91], calibMap1[93], +calibMap1[94], calibMap1[96], calibMap1[98], calibMap1[99], calibMap1[101], +calibMap1[103], calibMap1[105], calibMap1[106], calibMap1[108], calibMap1[110], +calibMap1[111], calibMap1[113], calibMap1[115] }; // Minor Scale const float calibMap6[QUAN_RES6] = { -0.01097947, 0.01864531, 0.03397701, 0.04930869, 0.05697454, -0.07230624, 0.08763793, 0.10296962, 0.11063547, 0.12590303, -0.14021800, 0.14737549, 0.16169049, 0.17600547, 0.19032045, -0.19747795, 0.21179293, 0.22610791, 0.23326540, 0.24758039, -0.26196238, 0.27635801, 0.28355584, 0.29795146, 0.31234708, -0.31954488, 0.33394051, 0.34833613, 0.36273175, 0.36992958, -0.38433966, 0.39875764, 0.40596664, 0.42038459, 0.43480256, -0.44922054, 0.45642951, 0.47084749, 0.48526546, 0.49247447, -0.50694764, 0.52148110, 0.53601462, 0.54328132, 0.55781484, -0.57234830, 0.57961506, 0.59414852, 0.60868198, 0.62321550, -0.63052768, 0.64518178, 0.65983582, 0.66716284, 0.68181694, -0.69647098, 0.71112502, 0.71845210, 0.73310614, 0.74776018, -0.75861782, 0.78344196, 0.80826604, 0.83309019, 0.84550226, -0.87032634, 0.94781560 +calibMap1[0], calibMap1[2], calibMap1[3], calibMap1[5], calibMap1[7], +calibMap1[8], calibMap1[10], calibMap1[12], calibMap1[14], calibMap1[15], +calibMap1[17], calibMap1[19], calibMap1[20], calibMap1[22], calibMap1[24], +calibMap1[26], calibMap1[27], calibMap1[29], calibMap1[31], calibMap1[32], +calibMap1[34], calibMap1[36], calibMap1[38], calibMap1[39], calibMap1[41], +calibMap1[43], calibMap1[44], calibMap1[46], calibMap1[48], calibMap1[50], +calibMap1[51], calibMap1[53], calibMap1[55], calibMap1[56], calibMap1[58], +calibMap1[60], calibMap1[62], calibMap1[63], calibMap1[65], calibMap1[67], +calibMap1[68], calibMap1[70], calibMap1[72], calibMap1[74], calibMap1[75], +calibMap1[77], calibMap1[79], calibMap1[80], calibMap1[82], calibMap1[84], +calibMap1[86], calibMap1[87], calibMap1[89], calibMap1[91], calibMap1[92], +calibMap1[94], calibMap1[96], calibMap1[98], calibMap1[99], calibMap1[101], +calibMap1[103], calibMap1[104], calibMap1[106], calibMap1[108], calibMap1[110], +calibMap1[111], calibMap1[113], calibMap1[115] }; // 5th const float calibMap7[QUAN_RES7] = { -0.01097947, 0.06464039, 0.11830132, 0.16884798, 0.21895042, -0.26916021, 0.31954488, 0.36992958, 0.42038459, 0.47084749, -0.52148110, 0.57234830, 0.62321550, 0.67448992, 0.72577912, -0.79585397, 0.90296346 +calibMap1[0], calibMap1[7], calibMap1[14], calibMap1[21], calibMap1[28], +calibMap1[35], calibMap1[42], calibMap1[49], calibMap1[56], calibMap1[63], +calibMap1[70], calibMap1[77], calibMap1[84], calibMap1[91], calibMap1[98], +calibMap1[105] }; // Whole tone const float calibMap8[QUAN_RES8] = { -0.01097947, 0.02631116, 0.04164285, 0.05697454, 0.07230624, -0.08763793, 0.10296962, 0.11830132, 0.13306051, 0.14737549, -0.16169049, 0.17600547, 0.19032045, 0.20463544, 0.21895042, -0.23326540, 0.24758039, 0.26196238, 0.27635801, 0.29075363, -0.30514926, 0.31954488, 0.33394051, 0.34833613, 0.36273175, -0.37713069, 0.39154866, 0.40596664, 0.42038459, 0.43480256, -0.44922054, 0.46363851, 0.47805649, 0.49247447, 0.50694764, -0.52148110, 0.53601462, 0.55054808, 0.56508154, 0.57961506, -0.59414852, 0.60868198, 0.62321550, 0.63785475, 0.65250880, -0.66716284, 0.68181694, 0.69647098, 0.71112502, 0.72577912, -0.74043316, 0.75861782, 0.78344196, 0.80826604, 0.83309019, -0.85791427, 0.90296346 +calibMap1[0], calibMap1[1], calibMap1[2], calibMap1[6], calibMap1[8], +calibMap1[10], calibMap1[12], calibMap1[14], calibMap1[16], calibMap1[18], +calibMap1[20], calibMap1[22], calibMap1[24], calibMap1[26], calibMap1[28], +calibMap1[30], calibMap1[32], calibMap1[34], calibMap1[36], calibMap1[38], +calibMap1[40], calibMap1[42], calibMap1[44], calibMap1[46], calibMap1[48], +calibMap1[50], calibMap1[52], calibMap1[54], calibMap1[56], calibMap1[58], +calibMap1[60], calibMap1[62], calibMap1[64], calibMap1[66], calibMap1[68], +calibMap1[70], calibMap1[72], calibMap1[74], calibMap1[76], calibMap1[78], +calibMap1[80], calibMap1[82], calibMap1[84], calibMap1[86], calibMap1[88], +calibMap1[90], calibMap1[92], calibMap1[94], calibMap1[96], calibMap1[98], +calibMap1[100], calibMap1[102], calibMap1[104], calibMap1[106], calibMap1[108], +calibMap1[110], calibMap1[112], calibMap1[114] }; //------------------------------------------------------------- @@ -283,52 +352,127 @@ // Global Variables float gOSC_cv[8]; -float gSeq_cv1[8], gSeq_cv2[8]; +float gSeq_cv[16]; float gGlide; int gMode; // Variables for Control - -float gCtrl[6]; -bool gCtrlSW[6] = {false}; +/* +gCtrl[0] /ctrl1 BPM +gCtrl[1] /ctrl2 Quantize mode +gCtrl[3] /ctrl4 Glide +gCtrl[4] /ctrl5 M185 Reset Count + +gCtrlSW[0] /ctrlsw1 Sequencer STOP +gCtrlSW[1] /ctrlsw2 Euclidean Sequencer reset +gCtrlSW[2] /ctrlsw3 Sequencer Loop +gCtrlSW[3] /ctrlsw4 Euclid Seq ON + +float gPulseCount[8] = {0}; M185 Pulse Count +float gGateMode[8] = {0}; M185 Gate Mode +float gSlide[8]; M185 Slide + +gEucA[0] /euca1 Euclidean Pattern length (n) ch1 +gEucA[1] /euca2 Euclidean Pattern density (k) ch1 +gEucA[2] /euca3 Euclidean Pattern offset (o) ch1 +gEucA[3] ~ [5] /euca4 ~ /euca6 Euclidean Pattern nko ch2 +gEucB[0] ~ [5] /eucb1 ~ /eucb6 Euclidean Pattern nko ch3 ~ ch4 +*/ + +float gCtrl[8]; +bool gCtrlSW[8] = {false}; + +// Variables for Sequencer +float gPulseCount[8] = {0}; +float gGateMode[16] = {0}; +float gSlide[16]; + +// Euclidean SEQ Variables +float gEucA[6], gEucB[6]; +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; + +// Variables for Arduino +uint16_t gArdCV[4]; +uint16_t gArdCtrl[4]; +bool gArdSW[4] = {false}; //------------------------------------------------------------- // mbed Functions -TextLCD gLCD(p9, p10, p11, p12, p13, p14); // rs, e, d4-d7 - -SPI gSPI(p5,p6,p7); // SPI (p6 unconnected) -DigitalOut gSYNCMODE(p15); // SYNC DAC8568 -DigitalOut gLDAC(p16); // LDAC DAC8568 - -DigitalOut gGATES[4] = {p23, p24, p24, p25}; // GateOut -DigitalOut gLEDS[4] = {p18, p19, p20, p21}; // LED -DigitalOut gCLOCKOUT(p26); // ClockOut - -AnalogIn gAIN(p17); // Glide Potentiometer -InterruptIn gSW(p30); // Mode SW - -Timer gTimer; // Timer -Ticker gPoller; // Ticker Polling +TextLCD gLCD(p9, p10, p11, p12, p13, p14); // rs, e, d4-d7 + +BurstSPI gSPI(p5,p6,p7); // SPI (p6 unconnected) + +FastOut<p15> gSYNCMODE; // SYNC DAC8568 +FastOut<p16> gLDAC; // LDAC DAC8568 + +DigitalOut gGATES[4] = {p21, p22, p23, p24}; // GateOut +FastOut<p19> gSUBGATE; // SubGateOut +FastOut<p25> gCLOCKOUT; // ClockOut + +AnalogOut gAOUT(p18); + +AnalogIn gAIN(p17); +DebouncedInterrupt gSW(p30); // Mode SW + +// Serial for Arduino +MIDI midi(p28, p27); + +Timer gTimer; // Timer +Ticker gPoller; // Ticker for Polling // Ethernet -EthernetNetIf gEth; +EthernetNetIf gEth( + IpAddr(192,168,1,6), + IpAddr(255,255,255,0), + IpAddr(192,168,1,1), + IpAddr(192,168,1,1) + ); +/* static ip +EthernetNetIf gEth( + IpAddr(192,168,1,2), + IpAddr(255,255,255,0), + IpAddr(192,168,1,1), + IpAddr(192,168,1,1) + ); +*/ + UDPSocket gUdp; +// touchOSC Address +uint8_t touchOSCAddress[] = { 192, 168, 1, 7 }; +int touchOSCPort = 9000; + +OSCClass osc; +OSCMessage sendMes; + //------------------------------------------------------------- // main int main() { float pot, _pot; + int bpm; -//Clock Up 110Mhz ------------------------------------------------------------- +//Clock Up -------------------------------------------------------------------- LPC_SC->PLL0CON = 0x00; /* PLL0 Disable */ LPC_SC->PLL0FEED = 0xAA; LPC_SC->PLL0FEED = 0x55; LPC_SC->CCLKCFG = 0x00000003; /* Select Clock Divisor = 4 */ - LPC_SC->PLL0CFG = 0x00020037; /* configure PLL0 */ + LPC_SC->PLL0CFG = 0x00020038; /* configure PLL0 */ LPC_SC->PLL0FEED = 0xAA; /* divide by 3 then multiply by 50 */ LPC_SC->PLL0FEED = 0x55; /* PLL0 frequency = 400,000,000 */ @@ -344,18 +488,163 @@ SystemCoreClockUpdate(); //----------------------------------------------------------------------------- - - if(SetupEthNetIf() == -1) + + if (SetupEthNetIf() == -1) { - for(int i = 0; i < 4; i++) + for (int i = 0; i < 4; ++i) { - gLEDS[i] = 1; + gGATES[i] = true; wait(0.25); } return -1; } + InitOSCCV(); + + gCtrl[3] = _pot = pot = gMode = 0; + gGlide = gAIN.read(); + + LCD(); + gLCD.locate( 0, 1 ); + gLCD.printf("12345678 G>>%3.2f", gGlide); + +// Main loop + while (1) + { + LCD(); // Check Text LCD + + pot = gAIN.read(); // Update glide value + + if (!pot) // when glide pot value == 0 + { // use gCtrl[3] value + if (abs(gCtrl[3] - _pot) > 0.01f) + { + _pot = gGlide = gCtrl[3]; + + gLCD.locate( 9, 1 ); + gLCD.printf("G>>%3.2f", gGlide); + } + + } else if (abs(pot - _pot) > 0.01f) { + + _pot = gGlide = gAIN.read(); + + gLCD.locate( 9, 1 ); + gLCD.printf("G>>%3.2f", gGlide); + } + + switch (gMode) + { + case MODE_OSC: // OSCtoCV mode + + SetCV(); + break; + + case MODE_SEQ: // Shift Sequencer mode + + bpm = CheckBPM(); + + ShiftCVSeq(GateSeq(bpm, N16TH, GATE1, 3, NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0]); + GateSeq(bpm, N8TH, GATE2, 3, NON_INVERT, GATESOUT_ON, SYNC_OFF); + + if (gCtrlSW[3]) + { + EuclideanSeq(GateSeq(bpm, N16TH, SUBGATE, 1, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], GATESOUT_OFF); + } + break; + + case MODE_185: // M185 Sequencer mode + + bpm = CheckBPM(); + + M185Seq(GateSeq(bpm, N16TH, GATE1, 3, NON_INVERT, GATESOUT_OFF, SYNC_ON), gCtrlSW[0]); + GateSeq(bpm, N8TH, GATE2, 3, NON_INVERT, GATESOUT_ON, SYNC_OFF); + + if (gCtrlSW[3]) + { + EuclideanSeq(GateSeq(bpm, N16TH, SUBGATE, 1, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], GATESOUT_OFF); + } + break; + + case MODE_EUC: // Euclidean Sequencer mode + + bpm = CheckBPM(); + + ShiftCVSeq(GateSeq(bpm, N1ST, SUBGATE, 3, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0]); + EuclideanSeq(GateSeq(bpm, N16TH, GATE1, 1, NON_INVERT, GATESOUT_OFF, SYNC_OFF), gCtrlSW[0], GATESOUT_ON); + break; + + default: // CV Calibration mode + + CalibrationCV(); + break; + } + + } +} + +//------------------------------------------------------------- +// Initialize OSCtoCV + +void InitOSCCV() +{ + int i; +// Write custom char LCD CGRAM + WriteCustomChar(0x00, str1); + WriteCustomChar(0x01, str2); + WriteCustomChar(0x02, str3); + WriteCustomChar(0x03, str4); + WriteCustomChar(0x04, str5); + WriteCustomChar(0x05, str6); + WriteCustomChar(0x06, str7); + WriteCustomChar(0x07, str8); + +// Init SPI + gLDAC = _ENABLE; + gSPI.format(8,1); // Data word length 8bit, Mode=1 + gSPI.frequency(SPI_RATE); + + UpdateCV(CLR, 0, 0); // Ignore CLR Pin + +// 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 (i = 0; i < channels; ++i) + { + beat_holder[i] = Euclid(channelbeats[i][0], channelbeats[i][1], channelbeats[i][3]); + } + +// Init BPM + gCtrl[0] = 0.398f; + +// Init Sequence Data + for (i = 0; i < 16; ++i) + { + gSeq_cv[i] = calibMap1[69] * SCALING_N; + } + +// Init M185 Reset Count + gCtrl[4] = 1; + // mdns (Bonjour) HTTPServer svr; mDNSResponder mdns; @@ -364,57 +653,18 @@ svr.bind(INPUT_PORT); IpAddr ip = gEth.getIp(); mdns.announce(ip, "OSCtoCV", "_osc._udp", INPUT_PORT, "mbed(OSCtoCV)", (char *[]) {"path=/",NULL}); - - InitOSCCV(); - - _pot = pot = gMode = 0; - gGlide = gCtrl[3] = gAIN.read(); - - LCD(); - gLCD.locate( 0, 1 ); - gLCD.printf("12345678 G>>%3.2f", gGlide); + +// Set OSC message for sending + sendMes.setIp(touchOSCAddress); + sendMes.setPort(touchOSCPort); -// loop - while(1) - { - pot = gAIN.read(); // Glide Value - - if(pot == 0) - { - if(abs(gCtrl[3] - _pot) > 0.01f) - { - _pot = gGlide = gCtrl[3]; - - gLCD.locate( 0, 1 ); - gLCD.printf("12345678 G>>%3.2f", gGlide); - } - - } else if (abs(pot - _pot) > 0.01f) { - - gGlide = _pot = gAIN.read(); - - gLCD.locate( 0, 1 ); - gLCD.printf("12345678 G>>%3.2f", gGlide); - } - - switch(gMode) - { - case MODE_LIN: - - SetSCV(); - break; - - case MODE_SEQ: - - Seq(); - break; - - default: - - CalibCV(); - break; - } - } + gSW.attach(&CheckModeSW,IRQ_RISE, 30); // InterruptIn rising edge(ModeSW) + gPoller.attach_us(&NetPoll, POLLING_INTERVAL); // Ticker Polling + + wait(0.4); + + // Begin Serial for Arduino + //ardSerial.baud(115200); } //------------------------------------------------------------- @@ -426,34 +676,11 @@ } //------------------------------------------------------------- -// Initialize OSC-CV - -void InitOSCCV() +// Map Function + +inline float MapFloat(float x, float in_min, float in_max, float out_min, float out_max) { -// write custom char LCD CGRAM - WriteCustomChar(0x00, str1); - WriteCustomChar(0x01, str2); - WriteCustomChar(0x02, str3); - WriteCustomChar(0x03, str4); - WriteCustomChar(0x04, str5); - WriteCustomChar(0x05, str6); - WriteCustomChar(0x06, str7); - WriteCustomChar(0x07, str8); - -// Init. SPI - gLDAC = _ENABLE; - gSPI.format(8,1); // Data word length 8bit, Mode=1 - gSPI.frequency(SPI_RATE); - - UpdateCV(CLR, 0, 0); // Ignore CLR Pin - - gSW.mode(PullUp); // Use internal pullup for ModeSW - wait(.001); - - gSW.rise(&CheckModeSW); // InterruptIn rising edge(ModeSW) - gPoller.attach_us(&NetPoll, POLLING_INTERVAL); // Ticker Polling - - wait(0.2); + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } //------------------------------------------------------------- @@ -462,9 +689,8 @@ inline void UpdateCV(int control, int address, const unsigned int *data) { - __disable_irq(); - - switch(control) + + switch (control) { case WRITE_UPDATE_N: @@ -476,6 +702,7 @@ gSYNCMODE = _ENABLE; gLDAC = _DISABLE; gLDAC = _ENABLE; + break; case RESET: @@ -486,6 +713,7 @@ gSPI.write(00000000); gSPI.write(00000000); gSYNCMODE = _ENABLE; + break; case CLR: @@ -496,52 +724,54 @@ gSPI.write(00000000); gSPI.write(00000011); // Ignore CLR Pin gSYNCMODE = _ENABLE; + break; } - - __enable_irq(); } //------------------------------------------------------------- -// Calibrate Mode - -inline void CalibCV() +// Calibration Mode + +inline void CalibrationCV() { static int ch; unsigned int cv; - switch(gMode) + switch (gMode) { case MODE_Calb: - cv = (unsigned int)((calibMap1[68] + 0.0007) * SCALING_N); // A880.0Hz + cv = (unsigned int)(calibMap1[69] * SCALING_N); // A880.0Hz - gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = 1; - gLEDS[0] = gLEDS[1] = gLEDS[2] = gLEDS[3] = 1; + gSUBGATE = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = true; UpdateCV(WRITE_UPDATE_N, ch, &cv); + break; } - CVMeter(ch, &cv); + UpdateCVMeter(ch, &cv); - ch++; + ++ch; ch &= 0x07; } //------------------------------------------------------------- // Calculate CV -inline void SetSCV() +inline void SetCV() { - static int ch, quan, mode, mcount; + static int ch, qmode, amode, mcount; static float glidecv[8]; unsigned int cv; static float qcv; - mode = (gCtrl[1] * 8); - - switch(mode) + qmode = (gCtrl[1] * (SCALE_NUM - 1)); + amode = SCALE_AOUT * qmode; + + gAOUT.write_u16(amode); + + switch (qmode) { case Lin: @@ -549,402 +779,697 @@ cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); + break; case Chr: - - quan = (40616 / QUAN_RES1); - qcv = calibMap1[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv); - break; - - case Maj: - - quan = (40616 / QUAN_RES2); - qcv = calibMap2[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv); - break; - - case M7: - - quan = (40616 / QUAN_RES3); - qcv = calibMap3[(unsigned int)(gOSC_cv[ch] / quan)]; + + qcv = calibMap1[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES1 - 1))]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); + break; - case Min7: - - quan = (40616 / QUAN_RES4); - qcv = calibMap4[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv); - break; - - case Dor: - - quan = (40616 / QUAN_RES5); - qcv = calibMap5[(unsigned int)(gOSC_cv[ch] / quan)]; - + case Maj: + + qcv = calibMap2[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES2 - 1))]; + glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; - + UpdateCV(WRITE_UPDATE_N, ch, &cv); + break; - - case Min: - - quan = (40616 / QUAN_RES6); - qcv = calibMap6[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv); - break; + + case M7: - case S5th: - - quan = (40616 / QUAN_RES7); - qcv = calibMap7[(unsigned int)(gOSC_cv[ch] / quan)]; - - glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[ch]; - - UpdateCV(WRITE_UPDATE_N, ch, &cv); - break; - - case Wht: - - quan = (40616 / QUAN_RES8); - qcv = calibMap8[(unsigned int)(gOSC_cv[ch] / quan)]; + qcv = calibMap3[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES3 - 1))]; glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); cv = (unsigned int)glidecv[ch]; UpdateCV(WRITE_UPDATE_N, ch, &cv); + + break; + + case Min7: + + qcv = calibMap4[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES4 - 1))]; + + glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + cv = (unsigned int)glidecv[ch]; + + UpdateCV(WRITE_UPDATE_N, ch, &cv); + + break; + + case Dor: + + qcv = calibMap5[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES5 - 1))]; + + glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + cv = (unsigned int)glidecv[ch]; + + UpdateCV(WRITE_UPDATE_N, ch, &cv); + + break; + + case Min: + + qcv = calibMap6[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES6 - 1))]; + + glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + cv = (unsigned int)glidecv[ch]; + + UpdateCV(WRITE_UPDATE_N, ch, &cv); + + break; + + case S5th: + + qcv = calibMap7[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES7 - 1))]; + + glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + cv = (unsigned int)glidecv[ch]; + + UpdateCV(WRITE_UPDATE_N, ch, &cv); + + break; + + case Wht: + + qcv = calibMap8[(unsigned int)MapFloat(gOSC_cv[ch], 0, SCALING_N, 0, (QUAN_RES8 - 1))]; + + glidecv[ch] = glidecv[ch] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + cv = (unsigned int)glidecv[ch]; + + UpdateCV(WRITE_UPDATE_N, ch, &cv); + break; } - if(mcount % 16 == 0) + if (mcount == 0x1F) { - CVMeter(ch, &cv); + UpdateCVMeter(ch, &cv); } - ch++; + ++ch; - if(ch &= 0x07) + if (ch &= 0x07) { - mcount ++; + ++mcount; mcount &= 0x3F; } - } //------------------------------------------------------------- // Sequence & Shift Out CV -inline void SeqCV(int shift) +inline void ShiftCVSeq(int trigger, bool reset) { int i, j; - static int ch, quan, mode; + static bool triggerState = false; + static bool stepFoward = false; + static bool _reset = false; + static uint8_t currentStep; + static int _resetCount, resetCount; + static uint8_t gateMode; + static uint8_t _gateMode[16]; + static uint8_t ch, qmode, amode; static float glidecv[8], shiftcv[8]; unsigned int cv; static float qcv; - mode = (gCtrl[1] * 8); // Sequencer Quantize Mode (gCtrl[1]) + qmode = (gCtrl[1] * (SCALE_NUM - 1.0f)); // Sequencer Quantize Mode (gCtrl[1]) + amode = SCALE_AOUT * qmode; - switch(mode) + gAOUT.write_u16(amode); + + switch (qmode) { case Lin: - - if(ch < 8) - { - glidecv[0] = glidecv[0] * gGlide + gSeq_cv1[ch] * (1.0f - gGlide); - - } else { - - glidecv[0] = glidecv[0] * gGlide + gSeq_cv2[ch-8] * (1.0f - gGlide); - } - + + glidecv[0] = glidecv[0] * gSlide[currentStep] + gSeq_cv[currentStep] * (1.0f - gSlide[currentStep]); + + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Chr: + + qcv = calibMap1[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES1 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); cv = (unsigned int)glidecv[0]; - + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Maj: + + qcv = calibMap2[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES2 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + break; - - case Chr: + + case M7: + + qcv = calibMap3[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES3 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Min7: + + qcv = calibMap4[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES4 - 1))]; - quan = 40616 / QUAN_RES1; - - if(ch < 8) - { - qcv = calibMap1[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap1[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); cv = (unsigned int)glidecv[0]; - + UpdateCV(WRITE_UPDATE_N, 0, &cv); - break; - - case Maj: - - quan = 40616 / QUAN_RES2; - - if(ch < 8) - { - qcv = calibMap2[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap2[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[0]; - - UpdateCV(WRITE_UPDATE_N, 0, &cv); + break; - case M7: - - quan = 40616 / QUAN_RES3; - - if(ch < 8) - { - qcv = calibMap3[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap3[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + case Dor: + + qcv = calibMap5[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES5 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); cv = (unsigned int)glidecv[0]; - + UpdateCV(WRITE_UPDATE_N, 0, &cv); + break; - - case Min7: - - quan = 40616 / QUAN_RES4; - - if(ch < 8) - { - qcv = calibMap4[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap4[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + + case Min: + + qcv = calibMap6[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES6 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); cv = (unsigned int)glidecv[0]; - + UpdateCV(WRITE_UPDATE_N, 0, &cv); - break; - - case Dor: - - quan = 40616 / QUAN_RES5; - - if(ch < 8) - { - qcv = calibMap5[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap5[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[0]; - - UpdateCV(WRITE_UPDATE_N, 0, &cv); + break; - - case Min: - - quan = 40616 / QUAN_RES6; - - if(ch < 8) - { - qcv = calibMap6[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap6[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); - cv = (unsigned int)glidecv[0]; - - UpdateCV(WRITE_UPDATE_N, 0, &cv); - break; - + case S5th: - - quan = 40616 / QUAN_RES7; - - if(ch < 8) - { - qcv = calibMap7[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap7[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + + qcv = calibMap7[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES7 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); cv = (unsigned int)glidecv[0]; - + UpdateCV(WRITE_UPDATE_N, 0, &cv); + break; - + case Wht: - - quan = 40616 / QUAN_RES8; - - if(ch < 8) - { - qcv = calibMap8[(unsigned int)(gSeq_cv1[ch] / quan)]; - - } else { - - qcv = calibMap8[(unsigned int)(gSeq_cv2[ch-8] / quan)]; - } - - glidecv[0] = glidecv[0] * gGlide + (qcv * SCALING_N) * (1.0f - gGlide); + + qcv = calibMap8[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES8 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); cv = (unsigned int)glidecv[0]; - + UpdateCV(WRITE_UPDATE_N, 0, &cv); + break; } - - for(i = 1; i < 8; ++i) + + for (i = 1; i < 8; ++i) + { + glidecv[i] = glidecv[i] * gSlide[currentStep] + shiftcv[i] * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[i]; + + UpdateCV(WRITE_UPDATE_N, i, &cv); + } + + if (trigger && !triggerState) // trigger ON + { + stepFoward = triggerState = true; + + } else if (!trigger) { // trigger OFF + + if (gateMode != HOLD) { - glidecv[i] = glidecv[i] * gGlide + shiftcv[i] * (1.0f - gGlide); - cv = (unsigned int)glidecv[i]; - - UpdateCV(WRITE_UPDATE_N, i, &cv); + gGATES[0] = false; } - if(shift == 1) // GATE1 + triggerState = false; + } + +// check & update touchOSC ctrl parameter + if (_gateMode[ch] != (gGateMode[ch] * 3)) + { + _gateMode[ch] = (gGateMode[ch] * 3); + + if (_gateMode[ch] == MULTI) { - for(j = 1; j < 8; ++j) // Shift ch2~8 + _gateMode[ch] = HOLD; + } + + SendCtrlState(ch, _gateMode[ch], 8); + } + + if (reset && !_reset) // Stop & Reset + { + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + + currentStep = 0; + + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + _reset = true; + + } else if (!reset) { + + _reset = false; + } + + if (stepFoward) + { + if (gateMode != HOLD) // shift CV + { + for (j = 1; j < 8; ++j) { shiftcv[j] = glidecv[j-1]; } + } + + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + + ++currentStep; + + if (gCtrlSW[2]) + { + resetCount = 3; + + } else { + + resetCount = gCtrl[4] * 15; + } - ch++; - ch &= 0x0F; + if (_resetCount != resetCount) + { + sendMes.setTopAddress(RESET_COUNTER_ADDRESS); + sendMes.setArgs("i", (resetCount + 1)); + osc.sendOsc(&sendMes); + } + + if (currentStep > resetCount) // reset + { + currentStep = 0; } - - if(ch < 8) + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + if (currentStep < 8) { - CVMeter(ch, &cv); - + UpdateCVMeter(currentStep, &cv); + } else { - - CVMeter((ch-8), &cv); + + UpdateCVMeter((currentStep - 8), &cv); + } + + gateMode = (gGateMode[currentStep] * 3); + + if (gateMode == MULTI) // omit MULTI mode + { + gateMode = HOLD; } - + + if (gateMode != MUTE) + { + gGATES[0] = true; + } + + stepFoward = false; + } + + ++ch; + ch &= 0x0F; } //------------------------------------------------------------- -// Sequencer Mode - -inline void Seq() +// M185 Sequencer + +inline void M185Seq(int trigger, bool reset) { - static int bpm, _bpm; + int i, j; + static bool triggerState = false; + static bool stepFoward = false; + static bool _reset = false; + static uint8_t currentStep; + static int stepCount; + static int _resetCount, resetCount; + static uint8_t gateMode; + static uint8_t _gateMode[8]; + static uint8_t _pulseCount[8]; + static uint8_t ch, qmode, amode; + static float glidecv[8], shiftcv[8]; + unsigned int cv; + static float qcv; + + qmode = (gCtrl[1] * (SCALE_NUM - 1)); // Sequencer Quantize Mode (gCtrl[1]) + amode = SCALE_AOUT * qmode; + + gAOUT.write_u16(amode); + + switch (qmode) + { + case Lin: + + glidecv[0] = glidecv[0] * gSlide[currentStep] + gSeq_cv[currentStep] * (1.0f - gSlide[currentStep]); + + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Chr: + + qcv = calibMap1[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES1 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Maj: + + qcv = calibMap2[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES2 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case M7: + + qcv = calibMap3[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES3 - 1))]; - bpm = (gCtrl[0] * 300 + 10); // Set BPM (gCtrl[0]) + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Min7: + + qcv = calibMap4[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES4 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; - if(abs(bpm - _bpm) > 1) + case Dor: + + qcv = calibMap5[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES5 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Min: + + qcv = calibMap6[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES6 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case S5th: + + qcv = calibMap7[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES7 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + + case Wht: + + qcv = calibMap8[(unsigned int)MapFloat(gSeq_cv[currentStep], 0, SCALING_N, 0, (QUAN_RES8 - 1))]; + + glidecv[0] = glidecv[0] * gSlide[currentStep] + (qcv * SCALING_N) * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[0]; + + UpdateCV(WRITE_UPDATE_N, 0, &cv); + + break; + } + + for (i = 1; i < 8; ++i) { - UpdateGate(bpm, NRESET, GATEALL, 3, false); // Reset (if bpm change) - _bpm = bpm; - - } else if (gCtrlSW[0]) { // Stop (gCtrlSW[0]) - - bpm = 0; - } - - if(!gCtrlSW[2] && !gCtrlSW[3]) // Sequencer Mode1 - { - SeqCV((UpdateGate(bpm, N16TH, GATE1, 3, false))); // Shift Timming 16th note - UpdateGate(bpm, N8TH, GATE2, 3, 0); - UpdateGate(bpm, NDOT8, GATE3, 3, 0); - UpdateGate(bpm, TRIP4, GATE4, 3, 0); + glidecv[i] = glidecv[i] * gSlide[currentStep] + shiftcv[i] * (1.0f - gSlide[currentStep]); + cv = (unsigned int)glidecv[i]; + + UpdateCV(WRITE_UPDATE_N, i, &cv); } + if (trigger && !triggerState) // trigger ON + { + if (gateMode == MULTI) + { + gGATES[0] = true; + + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + } + + stepFoward = triggerState = true; + + } else if (!trigger) { // trigger OFF + + if (gateMode != HOLD) + { + gGATES[0] = false; + } + + if (gateMode == MULTI) + { + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + } + + triggerState = false; + } + +// check & update touchOSC ctrl parameter + if (_gateMode[ch] != gGateMode[ch] * 3 || _pulseCount[ch] != gPulseCount[ch] * 7) + { + _gateMode[ch] = (gGateMode[ch] * 3); + _pulseCount[ch] = (gPulseCount[ch] * 7); + + SendCtrlState(ch, _gateMode[ch], _pulseCount[ch]); + } + + if (reset && !_reset) // Stop & Reset + { + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + + currentStep = 0; + + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + _reset = true; + + } else if (!reset) { + + _reset = false; + } + + if (stepFoward) + { + if (gateMode != HOLD) // shift CV + { + for (j = 1; j < 8; ++j) + { + shiftcv[j] = glidecv[j-1]; + } + } + + --stepCount; + + if (stepCount == -1) + { + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + + ++currentStep; + + if (gCtrlSW[2]) + { + resetCount = 3; + + } else { + + resetCount = gCtrl[4] * 7; + } + + if (_resetCount != resetCount) + { + sendMes.setTopAddress(RESET_COUNTER_ADDRESS); + sendMes.setArgs("i", (resetCount + 1)); + osc.sendOsc(&sendMes); + } + + if (currentStep > resetCount) // reset + { + currentStep = 0; + } + + sendMes.setTopAddress(SetMatrixAddress(0, currentStep, false)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + UpdateCVMeter(currentStep, &cv); + + // check Pulse Count & Gate Mode + stepCount = (gPulseCount[currentStep] * 7); + + gateMode = (gGateMode[currentStep] * 3); + + if (gateMode != MUTE) + { + gGATES[0] = true; + } + + } + + stepFoward = false; + } + + ++ch; + ch &= 0x07; } //------------------------------------------------------------- -// Check SW - -void CheckModeSW() -{ - wait(0.05); +// Send M185 Sequencer Status to touchOSC + +inline void SendCtrlState(uint8_t step, uint8_t gateMode, uint8_t stepCount) +{ + char pulseAddress[10] = PULSE_COUNT_ADDRESS; + char gateModeAddress[10] = GATE_MODE_ADDRESS; + char currentStep[2]; - if(gMode < MODE_NUM - 1) - { - gMode++; - - } else { - - gMode = 0; + sprintf(currentStep, "%d", step + 1); + + strcat(gateModeAddress, currentStep); + + if(stepCount != 8) + { + strcat(pulseAddress, currentStep); + sendMes.setTopAddress(pulseAddress); + sendMes.setArgs("i", (stepCount + 1)); + osc.sendOsc(&sendMes); } - - gCLOCKOUT = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = 0; - gLEDS[0] = gLEDS[1] = gLEDS[2] = gLEDS[3] = 0; - - if(gMode == MODE_SEQ) - { - gTimer.start(); // Sequencer Timer Start + + sendMes.setTopAddress(gateModeAddress); - } else { + switch (gateMode) + { + case SINGLE: + + sendMes.setArgs("s", "|"); + + break; + + case MUTE: - gTimer.stop(); // Sequencer Timer Stop - } - - LCD(); + sendMes.setArgs("s", "O"); + + break; + + case MULTI: + + sendMes.setArgs("s", "||"); + + break; + + case HOLD: + + sendMes.setArgs("s", "|-"); + + break; + } + + osc.sendOsc(&sendMes); } //------------------------------------------------------------- -// GateOutSequence beat(Note values) length(Gate time) invert(invert Gate) - -inline int UpdateGate(int bpm, int beat, int ch, int length, bool invert) +// Gate Sequencer beat(Note values) length(Gate time) invert(invert Gate) + +inline int GateSeq(int bpm, int beat, int ch, int length, bool invert, bool gatesoff, bool syncoff) { int i; - static int gatetime[4], oldgatetime[4]; - static int bar, sync24, oldsynctime; + static int gatetime[GATE_TOTAL], oldgatetime[GATE_TOTAL]; + static int _bpm, bar, sync24, oldsynctime; int time = gTimer.read_us(); - bar = (60.0f / bpm) * 4000000; - sync24 = (bar / 4) / 24; // sync24 not tested + if (_bpm != bpm) + { + if (!bpm) + { + beat = NRESET; + + } else { + + bar = (60.0f / bpm) * 4000000; + //sync24 = (bar / 4) / 24; // sync24 not tested + + _bpm = bpm; + } + } - switch(beat) // Calculate Note values + switch (beat) // Calculate Note values { case NDOT2: @@ -972,58 +1497,100 @@ break; case NRESET: + + gTimer.reset(); - for(i = 0; i < GATEALL; ++i) // Reset + for (i = 0; i < GATE_TOTAL; ++i) // Reset { - gTimer.reset(); oldsynctime = oldgatetime[i] = gatetime[i] = NRESET; } - break; - + + return 0; + default: gatetime[ch] = bar / beat; + sync24 = bar / 16; + break; } - if(time > oldsynctime + sync24) // sync24 not tested + if (time > oldsynctime + sync24) // sync24 not tested + { + if (!syncoff) { oldsynctime = time; - gCLOCKOUT = 1; + gCLOCKOUT = true; - } else if (time > sync24 - (sync24 - 2)) { + midi.sendRealTime(Clock); // MIDI Clock + } - gCLOCKOUT = 0; + } else if (time > oldsynctime - (sync24 - 2)) { + + if (!syncoff) + { + gCLOCKOUT = false; } - - if (ch == GATEALL) + } + + if (ch == GATE_TOTAL) { return -1; } else if (time > oldgatetime[ch] + gatetime[ch] && !invert) { oldgatetime[ch] = time; - gLEDS[ch] = gGATES[ch] = 1; - return ch + 1; + if (!gatesoff) + { + gGATES[ch] = true; + + } else if (ch == SUBGATE) { + + gSUBGATE = true; + } + + return 1; } else if (time > oldgatetime[ch] + gatetime[ch] && invert) { oldgatetime[ch] = time; - gLEDS[ch] = gGATES[ch] = 0; + + if (!gatesoff) + { + gGATES[ch] = false; + + } else if (ch == SUBGATE) { + + gSUBGATE = false; + } return 0; } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && !invert) { - gLEDS[ch] = gGATES[ch] = 0; + if (!gatesoff) + { + gGATES[ch] = false; + + } else if (ch == SUBGATE) { + + gSUBGATE = false; + } return 0; } else if (time > oldgatetime[ch] + (gatetime[ch] - gatetime[ch] / length) && invert) { - gLEDS[ch] = gGATES[ch] = 1; + if (!gatesoff) + { + gGATES[ch] = true; + + } else if (ch == SUBGATE) { + + gSUBGATE = true; + } - return ch + 1; + return 1; } else { @@ -1031,93 +1598,264 @@ } } + //------------------------------------------------------------- -// SyncOut Sequence beat(Note values) invert(invert Gate) - -inline void UpdateSync(int bpm, int beat, bool invert) -{ - static int bar, synctime, oldsynctime; +// Check BPM + +inline int CheckBPM() +{ + static int _bpm = -1; + int bpm; - int time = gTimer.read_us(); - - bar = (60.0f / bpm) * 4000000; - - synctime = bar / beat; - - if(beat == NRESET) + if (gCtrlSW[0]) { - bar = synctime = oldsynctime = gCLOCKOUT = 0; + bpm = 0; + + return bpm; } - if((time > oldsynctime + synctime) && !invert) + if (!gCtrl[0]) { - oldsynctime = time; - gCLOCKOUT = 1; - - } else if ((time > synctime - (synctime / 2)) && !invert) { + bpm = gArdCtrl[0] * 0.25f + 5; + + if (abs(bpm - _bpm) > 1) + { + _bpm = bpm; + + sendMes.setTopAddress("/bpm"); + sendMes.setArgs("i", bpm); + osc.sendOsc(&sendMes); + } - gCLOCKOUT = 0; + } else if (gCtrl[0]) { + + bpm = (gCtrl[0] * 240 + 5); + + if (abs(bpm - _bpm) > 1) + { + _bpm = bpm; + + sendMes.setTopAddress("/bpm"); + sendMes.setArgs("i", bpm); + osc.sendOsc(&sendMes); + } + } + + return bpm; +} + +//------------------------------------------------------------- +// Check Mode SW + +inline void CheckModeSW() +{ + if (gMode < MODE_TOTAL - 1) + { + ++gMode; + + } else { + + gMode = 0; + } + + gCLOCKOUT = gGATES[0] = gGATES[1] = gGATES[2] = gGATES[3] = false; + + if (gMode == MODE_SEQ || gMode == MODE_185 || gMode == MODE_EUC) + { + gTimer.start(); // Sequencer Timer Start + midi.begin(1); - } else if((time > oldsynctime + synctime) && invert) { - - oldsynctime = time; - gCLOCKOUT = 0; - - } else if ((time > synctime - (synctime / 2)) && invert) { - - gCLOCKOUT = 1; + } else { + + gTimer.stop(); // Sequencer Timer Stop } } //------------------------------------------------------------- -// CV meter - -inline void CVMeter(int ch, const unsigned int *level) -{ - gLCD.locate ( ch, 0 ); - gLCD.putc(*level * 0.000205729); // put custom char +// Print LCD Mode Status + +inline void LCD() +{ + static int _mode = -1; + static int _qmode = -1; + static int qmode; + + if (_mode != gMode) + { + sendMes.setTopAddress("/mode"); + + switch (gMode) + { + case MODE_Calb: + gLCD.locate( 9, 0 ); + gLCD.printf("CLB|880"); + + sendMes.setArgs("s", "Calibration"); + osc.sendOsc(&sendMes); + + sendMes.setTopAddress("/scale"); + sendMes.setArgs("s", "880Hz"); + + _qmode = -1; + + break; + + case MODE_OSC: + gLCD.locate( 9, 0 ); + gLCD.printf("OSC|"); + + sendMes.setArgs("s", "OSCtoCV"); + + break; + + case MODE_SEQ: + gLCD.locate( 9, 0 ); + gLCD.printf("ASR|"); + + sendMes.setArgs("s", "ASR SEQ"); + + break; + + case MODE_185: + gLCD.locate( 9, 0 ); + gLCD.printf("185|"); + + sendMes.setArgs("s", "M185 SEQ"); + + break; + + case MODE_EUC: + gLCD.locate( 9, 0 ); + gLCD.printf("EUC|"); + + sendMes.setArgs("s", "Euclidean SEQ"); + + break; + + default: + break; + } + + osc.sendOsc(&sendMes); + _mode = gMode; + } + + qmode = (gCtrl[1] * (SCALE_NUM - 1)); + + if ((_qmode != qmode) && gMode) + { + sendMes.setTopAddress("/scale"); + + switch (qmode) + { + case Lin: + gLCD.locate( 13, 0 ); + gLCD.printf("lin"); + + sendMes.setArgs("s", "Linear"); + + break; + + case Chr: + gLCD.locate( 13, 0 ); + gLCD.printf("chr"); + + sendMes.setArgs("s", "Chromatic"); + + break; + + case Maj: + gLCD.locate( 13, 0 ); + gLCD.printf("maj"); + + sendMes.setArgs("s", "Major"); + + break; + + case M7: + gLCD.locate( 13, 0 ); + gLCD.printf("ma7"); + + sendMes.setArgs("s", "Major7"); + + break; + + case Min7: + gLCD.locate( 13, 0 ); + gLCD.printf("mi7"); + + sendMes.setArgs("s", "Minor7"); + + break; + + case Dor: + gLCD.locate( 13, 0 ); + gLCD.printf("dor"); + + sendMes.setArgs("s", "Dorian"); + + break; + + case Min: + gLCD.locate( 13, 0 ); + gLCD.printf("min"); + + sendMes.setTopAddress("/scale"); + sendMes.setArgs("s", "Minor"); + + break; + + case S5th: + gLCD.locate( 13, 0 ); + gLCD.printf("5th"); + + sendMes.setArgs("s", "5th"); + + break; + + case Wht: + gLCD.locate( 13, 0 ); + gLCD.printf("wht"); + + sendMes.setArgs("s", "Whole Tone"); + break; + + default: + break; + } + + osc.sendOsc(&sendMes); + _qmode = qmode; + } + } //------------------------------------------------------------- -// Print LCD Mode Status - -void LCD() -{ - switch(gMode) - { - case MODE_Calb: - gLCD.locate( 9, 0 ); - gLCD.printf("Calibr "); - break; - - case MODE_LIN: - gLCD.locate( 9, 0 ); - gLCD.printf("OSC-CV "); - break; - - case MODE_SEQ: - gLCD.locate( 9, 0 ); - gLCD.printf("SHIFTCV"); - break; - } +// CV Meter + +inline void UpdateCVMeter(int ch, const unsigned int *level) +{ + gLCD.locate ( ch, 0 ); + gLCD.putc(*level * 0.0002192f); // put custom char } + //------------------------------------------------------------- -// Write command Custom Char LCD CGRAM(CV Meter) +// Write command Custom Char LCD CGRAM for CV Meter) void WriteCustomChar(unsigned char addr, unsigned char *c) { char cnt = 0; addr = ((addr << 3) | 0x40); - while(cnt < 0x08) + while (cnt < 0x08) { gLCD.writeCommand(addr | cnt); gLCD.writeData(*c); - cnt++; - c++; + ++cnt; + ++c; } } @@ -1131,7 +1869,7 @@ // printf("Setting up...\r\n"); EthernetErr ethErr = gEth.setup(); - if(ethErr) + if (ethErr) { gLCD.locate( 0, 1 ); gLCD.printf("Error in setup."); @@ -1147,6 +1885,7 @@ gLCD.locate( 0, 1 ); gLCD.printf("%03d.%03d.%03d.%03d", gEth.getIp()[0], gEth.getIp()[1], gEth.getIp()[2], gEth.getIp()[3]); + wait(1.0); return 0; @@ -1159,40 +1898,40 @@ { size_t len = 0; - for(;;) + for (;;) { unsigned x = *(unsigned*)s; - if((x & 0xFF) == 0) return len; - if((x & 0xFF00) == 0) return len + 1; - if((x & 0xFF0000) == 0) return len + 2; - if((x & 0xFF000000) == 0) return len + 3; + if ((x & 0xFF) == 0) return len; + if ((x & 0xFF00) == 0) return len + 1; + if ((x & 0xFF0000) == 0) return len + 2; + if ((x & 0xFF000000) == 0) return len + 3; s += 4, len += 4; } } //------------------------------------------------------------- -// Handller receive UDP Packet +// Handller receive OSC UDP Packet inline void onUDPSocketEvent(UDPSocketEvent e) { - union OSCarg msg[10]; - char buf[768] = {0}; - int num, len; - int recvlen; + static union OSCarg msg[10]; + static char buf[896] = {0}; + static int recvlen; + static int num, len, offset; int messagepos = 0; bool bundleflag = false; Host host; - recvlen = gUdp.recvfrom(buf, 768, &host); // packet length - - switch(e) + switch (e) { case UDPSOCKET_READABLE: // The only event for now - - if(recvlen <= 0) break; + + recvlen = gUdp.recvfrom(buf, 896, &host); // packet length - if(buf[0] == '#') // #bundle + if (recvlen <= 0) break; + + if (!bundleflag && buf[0] == '#') // #bundle { messagepos += 16; // skip #bundle & timetag recvlen -= 16; @@ -1201,117 +1940,960 @@ } do { - if(bundleflag) + if (bundleflag) { messagepos += 4; recvlen -= 4; - - if(recvlen <= 0) + + if (recvlen <= 8) { bundleflag = false; break; } } - if(getOSCmsg(buf + messagepos, msg) == -1) continue; + if (getOSCmsg(buf + messagepos, msg) == -1) continue; - len = strlen(msg[0].address); + len = strlength(msg[0].address); - if(isdigit(msg[0].address[len-1])) + if (isdigit(msg[0].address[len-1])) { num = msg[0].address[len-1] - '0' - 1; - + + offset = 1; + + if (isdigit(msg[0].address[len-2])) + { + offset = 2; + num += 10; + } + } else { num = -1; } // address pattern SYNC & GATE (Type Tag int, float) - if(!strncmp(msg[0].address+(len-1)-4, "sync", 4)) + if (!strncmp(msg[0].address+(len-offset)-4, "sync", 4)) { - if(msg[2].i != 0) gCLOCKOUT = 1; - else gCLOCKOUT = 0; + if (msg[2].i != 0) gCLOCKOUT = true; + else gCLOCKOUT = false; continue; - } else if (!strncmp(msg[0].address+(len-1)-4, "gate", 4) && (num != -1)) { - if(num > 3) continue; - if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; + } else if (!strncmp(msg[0].address+(len-offset)-4, "gate", 4) && (num != -1)) { + if (num > 3) continue; + if (msg[2].i != 0) gGATES[num] = true; + else gGATES[num] = false; continue; // (touchOSC Control push, toggle) - } else if (!strncmp(msg[0].address+(len-1)-4, "push", 4) && (num != -1)) { - if(num > 4) continue; - if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; - continue; - - } else if (!strncmp(msg[0].address+(len-1)-6, "toggle", 6) && (num != -1)) { - if(num > 4) continue; - if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; - continue; - - } else if (!strncmp(msg[0].address,"/1/multipush",12) && (num != -1)) { - if(num > 4) continue; - if(msg[2].i != 0) gLEDS[num] = gGATES[num] = 1; - else gLEDS[num] = gGATES[num] = 0; - continue; - // address pattern CV (Type Tag float) - } else if(!strncmp(msg[0].address+(len-1)-2, "cv", 2) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); + } else if (!strncmp(msg[0].address+(len-offset)-5, "fader", 5) && (num != -1)) { + if (num > 7) continue; + gOSC_cv[num] = msg[2].f * (SCALING_N); continue; - // (touchOSC Control fader, rotary, xy, multixy, multifader) - } else if (!strncmp(msg[0].address+(len-1)-5, "fader", 5) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - continue; - - } else if (!strncmp(msg[0].address+(len-1)-6, "rotary", 6) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - continue; - - } else if (!strncmp(msg[0].address+(len-1)-2, "xy", 2) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - if(msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N); - continue; - - } else if (!strncmp(msg[0].address+(len-1)-9, "multixy1/", 9) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); - if(msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N); + + } else if (!strncmp(msg[0].address+(len-offset)-9, "multixy1/", 9) && (num != -1)) { + if (num > 7) continue; + if (msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); + if (msg[1].typeTag[1] == 'f') gOSC_cv[++num] = msg[3].f * (SCALING_N); continue; - } else if (!strncmp(msg[0].address+(len-1)-12, "multifader1/", 12) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); + } else if (!strncmp(msg[0].address+(len-offset)-12, "multifader1/", 12) && (num != -1)) { + if (num > 7) continue; + if (msg[1].typeTag[1] == 'f') gOSC_cv[num] = msg[2].f * (SCALING_N); continue; - // (touchOSC multifader for Sequencer Mode) - } else if (!strncmp(msg[0].address+(len-1)-11, "sequencer1/", 11) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gSeq_cv1[num] = msg[2].f * (SCALING_N); + + } else if (!strncmp(msg[0].address+(len-offset)-10, "sequencer/", 10) && (num != -1)) { + + if (num > 15) continue; + gSeq_cv[num] = msg[2].f * (SCALING_N); continue; - } else if (!strncmp(msg[0].address+(len-1)-11, "sequencer2/", 11) && (num != -1)) { - if(num > 7) continue; - if(msg[1].typeTag[1] == 'f') gSeq_cv2[num] = msg[2].f * (SCALING_N); - continue; - // address pattern for control - } else if (!strncmp(msg[0].address+(len-1)-6, "ctrlsw", 6) && (num != -1)) { - if(num > 5) continue; - if(msg[2].i != 0) gCtrlSW[num] = true; + } else if (!strncmp(msg[0].address+(len-offset)-6, "ctrlsw", 6) && (num != -1)) { + if (num > 7) continue; + if (msg[2].i != 0) gCtrlSW[num] = true; else gCtrlSW[num] = false; continue; - } else if (!strncmp(msg[0].address+(len-1)-4, "ctrl", 4) && (num != -1)) { - if(num > 5) continue; - if(msg[1].typeTag[1] == 'f') gCtrl[num] = msg[2].f; + } else if (!strncmp(msg[0].address+(len-offset)-4, "ctrl", 4) && (num != -1)) { + if (num > 7) continue; + gCtrl[num] = msg[2].f; + continue; + + } else if (!strncmp(msg[0].address+(len-offset)-9, "pulsecnt/", 9) && (num != -1)) { + if (num > 7) continue; + gPulseCount[num] = msg[2].f; + continue; + + } else if (!strncmp(msg[0].address+(len-offset)-9, "gatemode/", 9) && (num != -1)) { + if (num > 15) continue; + gGateMode[num] = msg[2].f; + continue; + + } else if (!strncmp(msg[0].address+(len-offset)-6, "slide/", 6) && (num != -1)) { + if (num > 15) continue; + gSlide[num] = msg[2].f; + continue; + + } else if (!strncmp(msg[0].address+(len-offset)-4, "euca", 4) && (num != -1)) { + if (num > 5) continue; + gEucA[num] = msg[2].f; + continue; + + } else if (!strncmp(msg[0].address+(len-offset)-4, "eucb", 4) && (num != -1)) { + if (num > 5) continue; + gEucB[num] = msg[2].f; + continue; + + } else { continue; } - } while(bundleflag); + } while (bundleflag); + } +} + +//------------------------------------------------------------- +// Euclidean Sequencer + +void EuclideanSeq(int trigger, bool reset, bool gatesoff) { + /* + 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 + */ + + static uint8_t nn, kk, oo; + 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]; + + // 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, true)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + } else { + + sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, true)); + 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, true)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + } else { + + sendMes.setTopAddress(SetMatrixAddress(active_channel * 2, i, true)); + 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; + + } 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; + } + } + + // Stop & Reset (gCtrlSW[0]) + if (reset) { + + for (ch = 0; ch < channels; ++ch) { + + channelbeats[ch][2] = 0; + + for (i = 0; i < MAXSTEPS; ++i) { + + sendMes.setTopAddress(SetMatrixAddress(ch * 2 + 1, i, true)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + } + + } + + } + + // 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, true)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + + sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 5, true)); + 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); +} + +//------------------------------------------------------------- +// 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 + +inline 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; + static int masterclock; + + if (masterclock % 2 == 0) { + sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 7, true)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + } else { + + sendMes.setTopAddress(SetMatrixAddress((MAXCHANNELS * 2), 7, true)); + 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, true)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + } else { + + sendMes.setTopAddress(SetMatrixAddress(ch * 2, i, true)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + } + + } + } + } + + if (channelbeats[ch][2]) { + + if (!masterclock) { + + erase = MAXSTEPS - 1; + + } else { + + erase = masterclock - 1; + } + + sendMes.setTopAddress(SetMatrixAddress((ch * 2) + 1, erase, true)); + sendMes.setArgs("i", 0); + osc.sendOsc(&sendMes); + + sendMes.setTopAddress(SetMatrixAddress((ch * 2) + 1, masterclock, true)); + 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, true)); + sendMes.setArgs("i", 1); + osc.sendOsc(&sendMes); + + lights_active = pulses_active = true; + + if (!ch || (ch == 2)) { + + rand_vel = 127 - (rand() / (RAND_MAX / 40)); // random velocity ch1, ch3 + + } else { + + rand_vel = 95 - (rand() / (RAND_MAX / 70)); // random velocity ch2, ch4 + } + + rand_len = 127 - (rand() / (RAND_MAX / 110)); // 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, true)); + 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; +} + +inline char * SetMatrixAddress(int row, int column, bool euclid) { + static char address[32]; + char col[2]; + char ch[2]; + + if(euclid) + { + strcpy(address, MATRIX_ADDRESS); + + } else { + + strcpy(address, STEP_INDICATOR_ADDRESS); + } + + sprintf(col, "%d", column + 1); + strcat(address, col); + + if(euclid) + { + strcat(address, "/"); + + sprintf(ch, "%d", row + 1); + strcat(address, ch); + + } else { + + strcat(address, "/1"); + } + + return address; +} +
--- a/mbed-rpc.lib Thu Oct 16 14:14:25 2014 +0000 +++ b/mbed-rpc.lib Sun Aug 02 10:01:07 2015 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/teams/mbed-official/code/mbed-rpc/#2a26fd6a2b36 +http://mbed.org/teams/mbed-official/code/mbed-rpc/#d3e03663a6f4
--- a/mbed.bld Thu Oct 16 14:14:25 2014 +0000 +++ b/mbed.bld Sun Aug 02 10:01:07 2015 +0000 @@ -1,1 +1,1 @@ -http://mbed.org/users/mbed_official/code/mbed/builds/552587b429a1 \ No newline at end of file +http://mbed.org/users/mbed_official/code/mbed/builds/bad568076d81 \ No newline at end of file