Uses *spark d-fuser controller hardware as a USB-DMX interface. Developed for visualising Laurel Pardue’s augmented violin with lights.
Dependencies: DMX mbed spk_oled_ssd1305
main.cpp
- Committer:
- tobyspark
- Date:
- 2016-06-17
- Revision:
- 7:7f3140672370
- Parent:
- 6:cd5846520ea6
File content as of revision 7:7f3140672370:
#include "mbed.h" #include "DMX.h" #include "spk_oled_ssd1305.h" #include "spk_oled_gfx.h" // https://developer.mbed.org/forum/mbed/post/4526/ // 110, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 57600, 115200, 230400, 460800, 921600 #define kUSB_BAUD 57600 // MBED PINS #define kMBED_AIN_XFADE p20 #define kMBED_AIN_FADEUP p19 #define kMBED_DIN_TAP_L p24 #define kMBED_DIN_TAP_R p23 #define kMBED_ENC_SW p15 #define kMBED_ENC_A p16 #define kMBED_ENC_B p17 #define kMBED_RS232_TTLTX p13 #define kMBED_RS232_TTLRX p14 #define kMBED_OLED_MOSI p5 #define kMBED_OLED_SCK p7 #define kMBED_OLED_CS p8 #define kMBED_OLED_RES p9 #define kMBED_OLED_DC p10 #define kMBED_DIN_ETHLO_DMXHI p30 #define kMBED_DOUT_RS485_TXHI_RXLO p29 #define kMBED_RS485_TTLTX p28 #define kMBED_RS485_TTLRX p27 // DMX Fixtures #define kDMX_PARCAN_1 8 - 1 #define kDMX_PARCAN_2 12 - 1 #define kDMX_PARCAN_3 16 - 1 #define kDMX_PARCAN_4 20 - 1 #define kDMX_PARCAN_LUMA 0 #define kDMX_PARCAN_R 1 #define kDMX_PARCAN_G 2 #define kDMX_PARCAN_B 3 #define kDMX_SPOT_DIMMER 32 - 1 #define kDMX_PAN 36 - 1 #define kDMX_TILT_MSB 37 - 1 #define kDMX_TILT_LSB 38 - 1 #define kDMX_HAZER_HAZE 128 #define kDMX_HAZER_FAN 129 // MISC Defines #define kStringBufferLength 30 #define kUSBSerialBufferLength 256 //// USB Serial Serial usbSerial(USBTX, USBRX); //// DMX DigitalIn rj45ModeDIN(kMBED_DIN_ETHLO_DMXHI); DigitalOut dmxDirectionDOUT(kMBED_DOUT_RS485_TXHI_RXLO); enum { rj45Ethernet = 0, rj45DMX = 1}; // These values from circuit DMX dmx(kMBED_RS485_TTLTX, kMBED_RS485_TTLRX); //// Display // SPKDisplay(PinName mosi, PinName clk, PinName cs, PinName dc, PinName res, Serial *debugSerial = NULL); SPKDisplay screen(kMBED_OLED_MOSI, kMBED_OLED_SCK, kMBED_OLED_CS, kMBED_OLED_DC, kMBED_OLED_RES, NULL); //// mbed input DigitalIn button(kMBED_DIN_TAP_L); DigitalIn buttonR(kMBED_DIN_TAP_R); bool buttonLastState; char usbSerialBuffer[kUSBSerialBufferLength]; int usbSerialBufferPosition = 0; bool newStringData = false; bool newBowData = false; //// LAUREL VIOLIN DATA // [T: A, B] - T = timestamp. A is the time count (in minutes or something. Not presently very useful), B is sample count. I can change what is creating the stamp. Also, as I'm using sample count, this is only useful/changes when I record. int TA, TB; // [P: A, B] - P = pitch. A is hardware estimate- i.e the pitch estimate that is determined solely from the fingerboard data. B is the combined hardware + audio data (more accurate, slightly slower). -1 = no data/not confident enough to estimate float P1A, P1B, P2A, P2B, P3A, P3B, P4A, P4B; // [S: A] = signal strength. A is RMS of audio signal in the buffer. float S1, S2, S3, S4; // [F: A, B, C, D] = finger on string raw data. generally ranges 1 (no contact) to like .4, 1 being no string down, .9 being low pitch near nut, .4 higher up in pitch closer to the bridge. A is G string (i think) float F1, F2, F3, F4; // [B: A, B, C, D] = raw bow data, A is sensor closest to frog, D closest to tip. float B1, B2, B3, B4; // [E: A, B, C] = bow Estimate. (currently broken) This should be A - pos estimate (0 to 1 normalized frog to tip), B- pressure (0 -400?) and C- on string/off (0, 1 if B is > 40) 0 for A/B means it isn't ready to estimate. -1 means bow off string. float EA, EB; int EC; // TOBY VIOLIN EXTRAS float sMaxFixed = 0.1; float sMultiplier = 255.0/sMaxFixed; float eMaxFixed = 400; float eMultiplier = 255.0/eMaxFixed; void testDMX() { static char state = 1; if (state == 5) { dmx.put(kDMX_SPOT_DIMMER, 255); } else { dmx.put(kDMX_SPOT_DIMMER, 0); int address; switch (state) { case 1: address = kDMX_PARCAN_1; break; case 2: address = kDMX_PARCAN_2; break; case 3: address = kDMX_PARCAN_3; break; case 4: address = kDMX_PARCAN_4; break; } unsigned char parCanData[4]; parCanData[kDMX_PARCAN_R] = 255; parCanData[kDMX_PARCAN_G] = 255; parCanData[kDMX_PARCAN_B] = 255; parCanData[kDMX_PARCAN_LUMA] = 0; dmx.put(parCanData, kDMX_PARCAN_1, 4); dmx.put(parCanData, kDMX_PARCAN_2, 4); dmx.put(parCanData, kDMX_PARCAN_3, 4); dmx.put(parCanData, kDMX_PARCAN_4, 4); parCanData[kDMX_PARCAN_LUMA] = 255; dmx.put(parCanData, address, 4); } if (++state > 5) state = 1; } inline void processData() { float sMax = S1; if (sMax < S2) sMax = S2; if (sMax < S3) sMax = S3; if (sMax < S4) sMax = S4; float threshold = sMax * 0.7; if (S1 < threshold) S1 = 0; if (S2 < threshold) S2 = 0; if (S3 < threshold) S3 = 0; if (S4 < threshold) S4 = 0; } void usbSerialReceive(void) { char receivedChar; //if data is ready in the buffer while (usbSerial.readable()) { receivedChar = usbSerial.getc(); // Is end of line? if (receivedChar == '\n' || receivedChar == '\r') { // [T: 352, 16896000],[P: 196, -1, 196, -1, 196, -1, 196, -1],[S: 0, 0, 0, 0],[F: 1, 1, 1, 1],[B: 0.5346, 0.5781, 0.9043, 0.9029],[E: 0, 0, 0] int scanCount; // scanCount = sscanf( // usbSerialString.c_str(), // "[T: %d, %d],[P: %f, %f, %f, %f, %f, %f, %f, %f],[S: %f, %f, %f, %f],[F: %f, %f, %f, %f],[B: %f, %f, %f, %f],[E: %f, %f, %d]", // &TA, &TB, &P1A, &P1B, &P2A, &P2B, &P3A, &P3B, &P4A, &P4B, &S1, &S2, &S3, &S4, &F1, &F2, &F3, &F4, &B1, &B2, &B3, &B4, &EA, &EB, &EC // ); // if (scanCount == 25) scanCount = sscanf( usbSerialBuffer, "[S: %f, %f, %f, %f],[E: %f, %f, %d]", &S1, &S2, &S3, &S4, &EA, &EB, &EC ); if (scanCount == 7) { newStringData = true; newBowData = true; processData(); } else if (scanCount == 4) { newStringData = true; processData(); } else { screen.textToBuffer("Read vars failed", 6); } // Clear to start again usbSerialBufferPosition = 0; } else if (usbSerialBufferPosition < kUSBSerialBufferLength) { // Build string up usbSerialBuffer[usbSerialBufferPosition++] = receivedChar; usbSerialBuffer[usbSerialBufferPosition] = 0; screen.textToBuffer(usbSerialBuffer,4); } } } //// M A I N int main() { // Set display font screen.fontStartCharacter = &characterBytesStartChar; screen.fontEndCharacter = &characterBytesEndChar; screen.fontCharacters = characterBytes; // Splash screen screen.imageToBuffer(spkDisplayLogo); screen.textToBuffer("SPK:DMXer",0); screen.textToBuffer("FRATRES 2015",1); screen.textToBuffer("SW v01",2); screen.sendBuffer(); if (rj45ModeDIN == rj45DMX) screen.textToBuffer("RJ45: DMX Mode", 3); else screen.textToBuffer("RJ45: Ethernet Mode", 3); screen.sendBuffer(); dmxDirectionDOUT = 1; dmx.start(); dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_R, 255); dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_G, 255); dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_B, 255); dmx.put(kDMX_PARCAN_1+kDMX_PARCAN_LUMA, 0); dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_R, 255); dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_G, 255); dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_B, 255); dmx.put(kDMX_PARCAN_2+kDMX_PARCAN_LUMA, 0); dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_R, 255); dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_G, 255); dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_B, 255); dmx.put(kDMX_PARCAN_3+kDMX_PARCAN_LUMA, 0); dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_R, 255); dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_G, 255); dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_B, 255); dmx.put(kDMX_PARCAN_4+kDMX_PARCAN_LUMA, 0); dmx.put(kDMX_PAN, 50); //// Serial usbSerial.baud(kUSB_BAUD); usbSerial.attach(usbSerialReceive); //// TASK: Prime button change detection buttonLastState = button; //// TASK: GO! // We've finished setting up, now loop this forever... while (true) { if (newStringData) { char S1DMX = S1 * sMultiplier; char S2DMX = S2 * sMultiplier; char S3DMX = S3 * sMultiplier; char S4DMX = S4 * sMultiplier; unsigned char parCanData[4]; parCanData[kDMX_PARCAN_R] = 255; parCanData[kDMX_PARCAN_G] = 255; parCanData[kDMX_PARCAN_B] = 255; parCanData[kDMX_PARCAN_LUMA] = S1DMX; dmx.put(parCanData, kDMX_PARCAN_1, 4); parCanData[kDMX_PARCAN_LUMA] = S2DMX; dmx.put(parCanData, kDMX_PARCAN_2, 4); parCanData[kDMX_PARCAN_LUMA] = S3DMX; dmx.put(parCanData, kDMX_PARCAN_3, 4); parCanData[kDMX_PARCAN_LUMA] = S4DMX; dmx.put(parCanData, kDMX_PARCAN_4, 4); char dmxSummary[kStringBufferLength]; snprintf(dmxSummary, kStringBufferLength, "S %03u %03u %03u %03u", S1DMX, S2DMX, S3DMX, S4DMX); screen.textToBuffer(dmxSummary,6); newStringData = false; } if (newBowData) { // EA = Position, EB = Pressure, EC = On string if (EB < 0) EB = 0; char bowDMX = EB * eMultiplier; if (EC) { dmx.put(kDMX_SPOT_DIMMER, bowDMX); } else { dmx.put(kDMX_SPOT_DIMMER, 0); } dmx.put(kDMX_TILT_MSB, 15 + EA * 50); } // Has the button changed? if (button != buttonLastState) { // If so, lets update the lastState variable and then send an OSC message buttonLastState = button; if (button) { testDMX(); screen.textToBuffer("Sent: /mbed/button 1",5); //dmx.put(kDMX_HAZER_HAZE, 128); //dmx.put(kDMX_HAZER_FAN, 255); } else { screen.textToBuffer("Sent: /mbed/button 0",5); dmx.put(kDMX_HAZER_HAZE, 0); dmx.put(kDMX_HAZER_FAN, 0); } } screen.sendBuffer(); } }