CVtoOSC Converter for Nucleo F303K8
Dependencies: DebouncedInterrupt MIDI mbed osc-cnmat BufferedSerial
OSC to CV Converter
http://gtbts.tumblr.com/post/142840140501/cvtoosc-converter-for-modular-synthesizer
main.cpp
- Committer:
- casiotone401
- Date:
- 2016-02-20
- Revision:
- 2:7997fb939580
- Parent:
- 1:0a963a78f2bd
File content as of revision 2:7997fb939580:
/*
CVtoOSC&MIDI Converter for Nucleo F303K8
https://developer.mbed.org/platforms/ST-Nucleo-F303K8/
*/
#pragma O3
#pragma Otime
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <string>
#include "mbed.h"
#include "BufferedSerial.h"
#include "DebouncedInterrupt.h"
#include "MIDI.h"
#include "OSCBundle.h"
//-------------------------------------------------------------
// Macros
#define MIDI_OFFSET 4
#define MAP_OFFSET 0
#define CALIB_OFFSET 37
#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 Lin 0 // Linear LinearCV
#define Chr 1 // Chromatic
#define Maj 2 // Major
#define M7 3 // Major7
#define Min7 4 // Minor7
#define Dor 5 // Dorian
#define Min 6 // Minor
#define S5th 7 // 5th
#define Wht 8 // Wholetone
#define SCALE_TOTAL 9
#define SEND_BUFF_SIZE 1024 // OSC send buffer size
#define WAIT_SEND 20 // wait time(ms) for esp8266 transmission complete
#define MIDI_CHANNEL 1 // MIDI channel
//-------------------------------------------------------------
// Global Variables
// Silentway Calibration Data Mapping
// http://www.expert-sleepers.co.uk/silentway.html
// Chromatic Scale
const float calibMap1[QUAN_RES1] = {
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] = {
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] = {
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] = {
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] = {
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] = {
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] = {
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] = {
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]
};
// Major Scale
const uint8_t calibMapMidi2[QUAN_RES2] = {
0, 2, 4, 5, 7, 9, 11,
12, 14, 16, 17, 19, 21, 23,
24, 26, 28, 29, 31, 33, 35,
36, 38, 40, 41, 43, 45, 47,
48, 50, 52, 53, 55, 57, 59,
60, 62, 64, 65, 67, 69, 71,
72, 74, 76, 77, 79, 81, 83,
84, 86, 88, 89, 91, 93, 95,
96, 98, 100, 101, 103, 105, 107,
108, 110, 112, 113, 115
};
// M7(9)
const uint8_t calibMapMidi3[QUAN_RES3] = {
0, 4, 7, 11,
12, 14, 16, 19, 23,
24, 26, 28, 31, 35,
36, 38, 40, 43, 47,
48, 50, 52, 55, 59,
60, 62, 64, 67, 71,
72, 76, 79, 83,
84, 86, 88, 91, 95,
96, 100, 103, 107,
108, 110, 112, 115
};
// m7(9)
const uint8_t calibMapMidi4[QUAN_RES4] = {
0, 3, 7, 10,
12, 15, 19, 22,
26, 27, 31, 34,
36, 38, 39, 43, 46,
50, 53, 55, 58,
60, 63, 67, 70,
72, 74, 75, 79, 82,
86, 89, 91, 94,
96, 99, 103, 106, 110, 113
};
// Dorian Scale
const uint8_t calibMapMidi5[QUAN_RES5] = {
0, 2, 3, 5, 7, 9, 10,
12, 14, 15, 17, 19, 20, 21,
24, 26, 27, 29, 31, 33, 34,
36, 38, 39, 41, 43, 45, 46,
48, 50, 51, 53, 55, 57, 58,
60, 62, 63, 65, 67, 69, 70,
72, 74, 75, 77, 79, 81, 82,
84, 86, 87, 89, 91, 93, 94,
96, 98, 99, 101, 103, 105, 106,
108, 110, 111, 113, 115
};
// Minor Scale
const uint8_t calibMapMidi6[QUAN_RES6] = {
0, 2, 3, 5, 7, 8, 10,
12, 14, 15, 17, 19, 20, 22,
24, 26, 27, 29, 31, 32, 34,
36, 38, 39, 41, 43, 44, 46,
48, 50, 51, 53, 55, 56, 58,
60, 62, 63, 65, 67, 68, 70,
72, 74, 75, 77, 79, 80, 82,
84, 86, 87, 89, 91, 92, 94,
96, 98, 99, 101, 103, 104, 106,
108, 110, 111, 113, 115
};
// 5th
const uint8_t calibMapMidi7[QUAN_RES7] = {
0, 7, 14, 21, 28, 35,
42, 49, 56, 63, 70, 77,
84, 91, 98, 105
};
// Whole tone
const uint8_t calibMapMidi8[QUAN_RES8] = {
0, 1, 2, 6, 8, 10,
12, 14, 16, 18,20, 22,
24, 26, 28, 30, 32, 34,
36, 38, 40, 42, 44, 46,
48, 50, 52, 54, 56, 58,
60, 62, 64, 66, 68, 70,
72, 74, 76, 78, 80, 82,
84, 86, 88, 90, 92, 94,
96, 98, 100, 102, 104, 106,
108, 110, 112, 114
};
volatile bool changeFlag = false;
//-------------------------------------------------------------
// mbed Functions
/*
//Nucleo F303K8 //MCP3204
CS : pin 10 -- pin 8 (CS/SHDN)
MOSI: pin 11 -- pin 9 (D in)
MISO: pin 12 -- pin 10(D out)
SCK : pin 13 -- pin 11(CLK)
*/
SPI spi(D11, D12, D13);
DigitalOut csPin(D10);
AnalogIn scalePin(A0); // Scale Pin
AnalogIn potPin1(A1); // Pot1~2
AnalogIn potPin2(D6);
DebouncedInterrupt switch1(D8); // SW1
DebouncedInterrupt switch2(D9); // SW2
// esp8266 wi-fi settings
#define SSID "SSID"
#define PASSWORD "PASSWORD"
#define REMOTE_ADDRESS "192.168.1.2"
#define REMOTE_PORT "8000"
#define STATIC_IP // if you use DHCP comment out this line
#define LOCAL_ADDRESS "192.168.1.8"
#define LOCAL_PORT "9000"
// Serial for esp8266 (tx, rx)
BufferedSerial esp8266Serial(D1, D0);
// Serial for debug (tx, rx)
Serial pc(USBTX, USBRX);
// MIDI (tx, rx)
MIDI midi(A7, NC);
// declare the OSC bundle
OSCBundle bndl;
// Timer
Timer timer;
//-------------------------------------------------------------
// Functions
int map(int, int, int, int, int);
uint16_t adcRead(uint8_t);
void interruptSW1();
void interruptSW2();
void getESP8266Response();
void connectWifi();
//-------------------------------------------------------------
// Remaps value from one range to another range.
inline int map(int x, int in_min, int in_max, int out_min, int out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
//-------------------------------------------------------------
// Read MCP3208 AD Converter
uint16_t adcRead(uint8_t ch) {
uint8_t b1, b2;
uint8_t address = 0B01100000 | ((ch & 0B11) << 2);
csPin = 0; // CS pin Low
spi.write(address);
b1 = spi.write(0x00);
b2 = spi.write(0x00);
csPin = 1; // CS pin Hi
return (b1 << 4) | (b2 >> 4);
}
//-------------------------------------------------------------
// Check SW Status
void interruptSW1() {
volatile static uint8_t sw1State;
if (!sw1State) {
sw1State = 1;
} else {
sw1State = 0;
}
bndl.add("/sw1").add(sw1State);
changeFlag = true;
}
void interruptSW2() {
volatile static uint8_t sw2State;
if (!sw2State) {
sw2State = 1;
} else {
sw2State = 0;
}
bndl.add("/sw2").add(sw2State);
changeFlag = true;
}
//-------------------------------------------------------------
// get & print esp8266 response
void getESP8266Response(int timeout)
{
char resBuff[256] = {0};
timer.start();
uint8_t i = 0;
while (!(timer.read() > timeout)) {
if (esp8266Serial.readable()) {
resBuff[i++] = esp8266Serial.getc();
}
}
pc.printf(resBuff);
timer.stop();
timer.reset();
}
//-------------------------------------------------------------
// Setup esp8266 wi-fi module
void connectWifi() {
pc.printf("\n---------- Starting ESP8266 Config ----------\r\n");
wait(2);
// set station mode
pc.printf("\n---------- Set Station Mode ----------\r\n");
esp8266Serial.printf("AT+CWMODE=1\r\n");
getESP8266Response(1);
wait(1);
// restart
pc.printf("\n---------- Reset ESP8266 ----------\r\n");
esp8266Serial.printf("AT+RST\r\n");
getESP8266Response(2);
wait(1);
#ifdef STATIC_IP
// set static IP
pc.printf("\n---------- Setting Static IP ----------\r\n");
esp8266Serial.printf("AT+CIPSTA=\"");
esp8266Serial.printf(LOCAL_ADDRESS);
esp8266Serial.printf("\"\r\n");
getESP8266Response(3);
wait(1);
#endif
// connect wifi
pc.printf("\n---------- Wi-fi Connect ----------\r\n");
esp8266Serial.printf("AT+CWJAP=\"");
esp8266Serial.printf(SSID);
esp8266Serial.printf("\",\"");
esp8266Serial.printf(PASSWORD);
esp8266Serial.printf("\"\r\n");
getESP8266Response(3);
wait(2);
// single connection
pc.printf("\n---------- Setting Connection Mode ----------\r\n");
esp8266Serial.printf("AT+CIPMUX=0\r\n");
getESP8266Response(1);
wait(1);
// set UDP connection
pc.printf("\n---------- Setting UDP Connection ----------\r\n");
esp8266Serial.printf("AT+CIPSTART=");
esp8266Serial.printf("\"UDP\",\"");
esp8266Serial.printf(REMOTE_ADDRESS);
esp8266Serial.printf("\",");
esp8266Serial.printf(REMOTE_PORT);
esp8266Serial.printf(",");
esp8266Serial.printf(LOCAL_PORT);
esp8266Serial.printf(",");
esp8266Serial.printf("0\r\n");
getESP8266Response(3);
wait(1);
// set data transmission mode
pc.printf("\n---------- Setting Data Transmission Mode ----------\r\n");
esp8266Serial.printf("AT+CIPMODE=1\r\n");
getESP8266Response(1);
wait(1);
// change Baud Rate
pc.printf("\n---------- Change Baud Rate 4Mbps ----------\r\n");
esp8266Serial.printf("AT+UART_CUR=4000000,8,1,0,0\r\n");
getESP8266Response(3);
esp8266Serial.baud(4000000);
wait(1);
// ready to send data
pc.printf("\n---------- Ready to Send Data ----------\r\n");
esp8266Serial.printf("AT+CIPSEND\r\n");
getESP8266Response(2);
wait(1);
}
//-------------------------------------------------------------
// Main
int main() {
uint8_t i, idx;
uint8_t oscBuff[SEND_BUFF_SIZE] = {0};
static uint8_t scale;
uint8_t note[4] = {0};
static uint8_t _note[4];
uint16_t adc[4] = {0};
static uint16_t _adc[4];
float pot[2] = {0};
static float _pot[2] = {potPin1.read(), potPin2.read()};
// Init SPI (4MHz clock)
spi.format(8, 0);
spi.frequency(4000000);
csPin = 1;
// setup esp8266 wi-fi
esp8266Serial.baud(115200);
connectWifi();
// start MIDI (ch1)
midi.begin(MIDI_CHANNEL);
// start InterruptIn rising edge
switch1.attach(&interruptSW1, IRQ_RISE, 10);
switch2.attach(&interruptSW2, IRQ_RISE, 10);
// start timer (wait untile esp8266 transmission completed)
timer.start();
while (1) {
scale = map(scalePin.read_u16(), 0, 51890, 0, (SCALE_TOTAL - 1));
for (i = 0; i < 4; ++i) {
// read ADC
adc[i] = adcRead(i);
if (abs(adc[i] - _adc[i]) > 10) {
changeFlag = true;
switch (i) {
case 0:
bndl.add("/acv1").add(adc[i]);
break;
case 1:
bndl.add("/acv2").add(adc[i]);
break;
case 2:
bndl.add("/acv3").add(adc[i]);
break;
case 3:
bndl.add("/acv4").add(adc[i]);
break;
}
}
if (abs(adc[i] - _adc[i]) > 31) {
// MIDI quantize
switch (scale) {
case Lin:
case Chr:
note[i] = map(adc[i], 825, 3757, 0, (84 - MAP_OFFSET)) + CALIB_OFFSET; // C0(12) ~ C7(96)
break;
case Maj:
note[i] = calibMapMidi2[map(adc[i], 0, 4095, 0, QUAN_RES2 - 1)] + MIDI_OFFSET;
break;
case M7:
note[i] = calibMapMidi3[map(adc[i], 0, 4095, 0, QUAN_RES3 - 1)] + MIDI_OFFSET;
break;
case Min7:
note[i] = calibMapMidi4[map(adc[i], 0, 4095, 0, QUAN_RES4 - 1)] + MIDI_OFFSET;
break;
case Dor:
note[i] = calibMapMidi5[map(adc[i], 0, 4095, 0, QUAN_RES5 - 1)] + MIDI_OFFSET;
break;
case Min:
note[i] = calibMapMidi6[map(adc[i], 0, 4095, 0, QUAN_RES6 - 1)] + MIDI_OFFSET;
break;
case S5th:
note[i] = calibMapMidi7[map(adc[i], 0, 4095, 0, QUAN_RES7 - 1)] + MIDI_OFFSET;
break;
case Wht:
note[i] = calibMapMidi8[map(adc[i], 0, 4095, 0, QUAN_RES8 - 1)] + MIDI_OFFSET;
break;
}
if (_note[i] != note[i]) {
midi.sendNoteOff(_note[i], 0, MIDI_CHANNEL);
midi.sendNoteOn(note[i], 100, MIDI_CHANNEL);
_note[i] = note[i];
}
}
_adc[i] = adc[i];
}
// check potentiometer value
pot[0] = potPin1.read();
pot[1] = potPin2.read();
if (fabs(pot[0] - _pot[0]) > 0.02f) {
bndl.add("/pot1").add(pot[0] * 1023.0f);
midi.sendControlChange(0x16, map(potPin1.read_u16(), 0, 65535, 0, 127), MIDI_CHANNEL); // microKorg Noise Level
_pot[0] = pot[0];
changeFlag = true;
} else if (fabs(pot[1] - _pot[1]) > 0.02f) {
bndl.add("/pot2").add(pot[1] * 1023.0f);
midi.sendControlChange(0x5E, map(potPin2.read_u16(), 0, 65535, 0, 127), MIDI_CHANNEL); // microKorg Delay Level
_pot[1] = pot[1];
changeFlag = true;
}
if (changeFlag && timer.read_ms() > WAIT_SEND) {
idx = 0;
int len = bndl.send(oscBuff);
while (len--) {
// send OSC to esp8266 wifi
esp8266Serial.putc(oscBuff[idx++]);
}
changeFlag = false;
bndl.empty(); // empty the bundle to free room for a new one
timer.reset();
}
}
}
casiotone 401