12-polyphonic "chiptune" MIDI synthesizer for LPC1768 (Standalone version)

Dependencies:   ClockControl PowerControl mbed

Revision:
0:727737138ac5
Child:
1:5f0c89bffec1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Nov 09 08:00:33 2014 +0000
@@ -0,0 +1,222 @@
+#include "mbed.h"
+#include "ClockControl.h"
+#include "EthernetPowerControl.h"
+#include "PowerControl.h"
+#include "defs.h"
+#include "Channels.h"
+#include "GeminiCore.h"
+#include "RingBuffer.h"
+#include "debug.h"
+#include "events.h"
+#include "note.h"
+#include "parser.h"
+
+Serial            pc(/*Tx*/ USBTX, /*Rx*/ USBRX);
+Serial            midiIn(/*Tx*/ p28, /*Rx*/ p27);  // @TODO final: p13, p14
+Serial            console(/*Tx*/ p13, /*Rx*/ p14);  // @TODO final: p28, p27
+DigitalIn         swSerialSelect();
+DigitalIn         swPanic(p15);
+BusOut            led(/*Left*/ LED1, LED2, LED3, LED4 /*Right*/);
+BusOut            ledBar(p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p29, p30);
+SPI               spi(/*MOSI*/ p5, /*MISO*/ p6, /*SCK*/ p7);
+DigitalOut        dacCs(p8);
+Ticker            t1ms;
+Ticker            tSample;
+volatile uint32_t __countMs;
+bool              serSource;
+GeminiCore        gemCore(NUM_INSTRUMENT_IN_PERFORMER);
+RingBuffer<char>  buffer(BUFFER_LENGTH);
+Channels          ch;
+note_t            noteSent[NUM_INSTRUMENT];
+uint32_t          receivedBytes;
+dumpmode_t        dumpMode;
+
+void sampleOut() {
+    // soundOut.write(gemCore.makeSample() / 65536.0);
+    dacCs = 0;
+    spi.write(0x3000 | gemCore.makeSample() >> 4);
+    dacCs = 1;
+}
+
+void count1ms() {
+    __countMs++;
+}
+
+void readMidiIn() {
+    char c;
+    
+    // Put a MIDI input byte into buffer if available
+    if ((serSource ? midiIn : pc).readable()) {
+        c = (serSource ? midiIn : pc).getc();
+        receivedBytes++;
+
+        // Discard if input byte is an active sensing message
+        if (c != 0xfe) {
+            buffer.write(c);
+        }
+    }
+}
+
+void setup() {
+#ifdef POWER_SAVE
+    // Power down Ethernet PHY chip
+    PHY_PowerDown();
+    
+    // Power down unused peripherals
+    Peripheral_PowerDown(0x40067200);
+#endif
+
+#if defined(POWER_SAVE) && defined(CLOCKUP)
+    // Change clock speed to 120 MHz
+    setSystemFrequency(0x03, 0x01, 15, 1);
+#endif
+    
+    // Enable pull-up at switch inputs
+    // swSerialSelect.mode(PullUp);
+    swPanic.mode(PullUp);
+    wait(0.2);                  // Wait a moment for stability
+    
+    // Read serial selector switch
+    serSource = 1;              // @TODO final: serSource = swSerialSelect;
+    
+    // Open selected port
+    if (serSource) {
+        // Use MIDI port when high
+        midiIn.baud(38400);     // @TODO final: midiIn.baud(31250);
+        midiIn.format(8, Serial::None, 1);
+        midiIn.attach(readMidiIn, Serial::RxIrq);
+    } else {
+        // Use serial MIDI when low
+        pc.baud(38400);
+        pc.format(8, Serial::None, 1);
+        pc.attach(readMidiIn, Serial::RxIrq);
+    }
+    receivedBytes = 0;
+    
+    // Setup console
+    console.baud(115200);
+    console.format(8, Serial::None, 1);
+    dumpMode = DUMP_NOTHING;
+    
+    // Setup SPI
+    spi.format(16, 0);
+    spi.frequency(12000000);
+    dacCs = 1;
+    
+    // Initialize channels
+    ch.initializeAll();
+    
+    // Initialize note status
+    for (uint16_t i = 0; i < NUM_INSTRUMENT; i++) {
+        noteSent[i].noteOnMs = 0;
+        noteSent[i].channel = 0;
+        noteSent[i].noteNumber = 0;
+        noteSent[i].velocity = 0;
+    }
+    
+    // Start Timer
+    __countMs = 0;
+    t1ms.attach_us(&count1ms, 1000);
+    
+    // Start playback & attach interrupt
+#if defined(POWER_SAVE) && defined(CLOCKUP)
+    tSample.attach_us(&sampleOut, 1250000 / GeminiCore::samplingRate);
+#else
+    tSample.attach_us(&sampleOut, 1000000 / GeminiCore::samplingRate);
+#endif
+}
+
+void consoleOperations(uint8_t c) {
+    switch (c) {
+    case 'b':
+        checkBuffer();
+        break;
+    case 'e':
+        if (dumpMode != DUMP_EVENTS) {
+            dumpMode = DUMP_EVENTS;
+        } else {
+            dumpMode = DUMP_NOTHING;
+        }
+        break;
+    case 'f':
+        buffer.flush();
+        console.printf("* Buffer flushed.\r\n");
+        break;
+    case 'i':
+        if (dumpMode == DUMP_INST) {
+            dumpMode = DUMP_INST_DETAIL;
+        } else if (dumpMode == DUMP_INST_DETAIL) {
+            dumpMode = DUMP_NOTHING;
+        } else {
+            dumpMode = DUMP_INST;
+        }
+        break;
+    case 'p':
+        // Panic
+        for (uint8_t i = 0; i < NUM_INSTRUMENT_IN_PERFORMER; i++) {
+            gemCore.noteOff(i);
+            noteSent[i].noteOnMs = 0;
+            noteSent[i].channel = 0;
+            noteSent[i].noteNumber = 0;
+            noteSent[i].velocity = 0;
+        }
+        break;
+    case 'r':
+        console.printf("* Received MIDI bytes: %u\r\n", receivedBytes);
+        break;
+    default: break;
+    }
+}
+
+void loop() {
+    static uint32_t lastPollSwitchMs = __countMs;
+    static bool     prevstatePanic = 0;
+    bool            statePanic;
+    
+    // Serial console
+    if (console.readable()) {
+        consoleOperations(console.getc());
+    }
+
+    // Poll switches
+    if (__countMs > lastPollSwitchMs + 20) {
+        lastPollSwitchMs = __countMs;
+        
+        statePanic = swPanic;
+        
+        // Panic (all note off and flush buffer)
+        if (!statePanic && prevstatePanic) {
+            buffer.flush();
+            for (uint8_t i = 0; i < NUM_INSTRUMENT_IN_PERFORMER; i++) {
+                gemCore.noteOff(i);
+                noteSent[i].noteOnMs = 0;
+                noteSent[i].channel = 0;
+                noteSent[i].noteNumber = 0;
+                noteSent[i].velocity = 0;
+            }
+        }
+        
+        // Preserve this time's switch states
+        prevstatePanic = statePanic;
+    }
+    
+    // Parse MIDI messages
+    parseMessage(buffer);
+
+    // LEDs
+    uint8_t busyCount = 0;
+    for (uint8_t i = 0; i < NUM_INSTRUMENT_IN_PERFORMER; i++) {
+        if (noteSent[i].noteOnMs) {
+            busyCount++;
+        }
+    }
+    ledBar = (1 << busyCount) - 1;
+}
+
+int main() {
+    setup();
+    
+    while (1) {
+        loop();
+    }
+}