12-polyphonic "chiptune" MIDI synthesizer for LPC1768 (Standalone version)
Dependencies: ClockControl PowerControl mbed
main.cpp@2:ca10e33bde0a, 2014-11-12 (annotated)
- Committer:
- kayekss
- Date:
- Wed Nov 12 23:46:31 2014 +0000
- Revision:
- 2:ca10e33bde0a
- Parent:
- 1:5f0c89bffec1
- Child:
- 3:cf57d7031c12
GeminiCore: Deallocate finished notes at sampling
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
kayekss | 0:727737138ac5 | 1 | #include "mbed.h" |
kayekss | 0:727737138ac5 | 2 | #include "ClockControl.h" |
kayekss | 0:727737138ac5 | 3 | #include "EthernetPowerControl.h" |
kayekss | 0:727737138ac5 | 4 | #include "PowerControl.h" |
kayekss | 0:727737138ac5 | 5 | #include "defs.h" |
kayekss | 0:727737138ac5 | 6 | #include "Channels.h" |
kayekss | 0:727737138ac5 | 7 | #include "GeminiCore.h" |
kayekss | 0:727737138ac5 | 8 | #include "RingBuffer.h" |
kayekss | 0:727737138ac5 | 9 | #include "debug.h" |
kayekss | 0:727737138ac5 | 10 | #include "events.h" |
kayekss | 0:727737138ac5 | 11 | #include "note.h" |
kayekss | 0:727737138ac5 | 12 | #include "parser.h" |
kayekss | 0:727737138ac5 | 13 | |
kayekss | 0:727737138ac5 | 14 | Serial pc(/*Tx*/ USBTX, /*Rx*/ USBRX); |
kayekss | 1:5f0c89bffec1 | 15 | Serial midiIn(/*Tx*/ p13, /*Rx*/ p14); |
kayekss | 1:5f0c89bffec1 | 16 | Serial console(/*Tx*/ p28, /*Rx*/ p27); |
kayekss | 2:ca10e33bde0a | 17 | DigitalIn swSerialSelect(p12); |
kayekss | 0:727737138ac5 | 18 | DigitalIn swPanic(p15); |
kayekss | 0:727737138ac5 | 19 | BusOut led(/*Left*/ LED1, LED2, LED3, LED4 /*Right*/); |
kayekss | 0:727737138ac5 | 20 | BusOut ledBar(p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p29, p30); |
kayekss | 0:727737138ac5 | 21 | SPI spi(/*MOSI*/ p5, /*MISO*/ p6, /*SCK*/ p7); |
kayekss | 0:727737138ac5 | 22 | DigitalOut dacCs(p8); |
kayekss | 0:727737138ac5 | 23 | Ticker t1ms; |
kayekss | 0:727737138ac5 | 24 | Ticker tSample; |
kayekss | 0:727737138ac5 | 25 | volatile uint32_t __countMs; |
kayekss | 0:727737138ac5 | 26 | bool serSource; |
kayekss | 0:727737138ac5 | 27 | GeminiCore gemCore(NUM_INSTRUMENT_IN_PERFORMER); |
kayekss | 0:727737138ac5 | 28 | RingBuffer<char> buffer(BUFFER_LENGTH); |
kayekss | 0:727737138ac5 | 29 | Channels ch; |
kayekss | 0:727737138ac5 | 30 | note_t noteSent[NUM_INSTRUMENT]; |
kayekss | 0:727737138ac5 | 31 | uint32_t receivedBytes; |
kayekss | 0:727737138ac5 | 32 | dumpmode_t dumpMode; |
kayekss | 0:727737138ac5 | 33 | |
kayekss | 0:727737138ac5 | 34 | void sampleOut() { |
kayekss | 0:727737138ac5 | 35 | dacCs = 0; |
kayekss | 2:ca10e33bde0a | 36 | spi.write(0x3000 | gemCore.makeSample(noteSent) >> 4); |
kayekss | 0:727737138ac5 | 37 | dacCs = 1; |
kayekss | 0:727737138ac5 | 38 | } |
kayekss | 0:727737138ac5 | 39 | |
kayekss | 0:727737138ac5 | 40 | void count1ms() { |
kayekss | 0:727737138ac5 | 41 | __countMs++; |
kayekss | 0:727737138ac5 | 42 | } |
kayekss | 0:727737138ac5 | 43 | |
kayekss | 0:727737138ac5 | 44 | void readMidiIn() { |
kayekss | 0:727737138ac5 | 45 | char c; |
kayekss | 0:727737138ac5 | 46 | |
kayekss | 0:727737138ac5 | 47 | // Put a MIDI input byte into buffer if available |
kayekss | 0:727737138ac5 | 48 | if ((serSource ? midiIn : pc).readable()) { |
kayekss | 0:727737138ac5 | 49 | c = (serSource ? midiIn : pc).getc(); |
kayekss | 0:727737138ac5 | 50 | receivedBytes++; |
kayekss | 0:727737138ac5 | 51 | |
kayekss | 0:727737138ac5 | 52 | // Discard if input byte is an active sensing message |
kayekss | 0:727737138ac5 | 53 | if (c != 0xfe) { |
kayekss | 0:727737138ac5 | 54 | buffer.write(c); |
kayekss | 0:727737138ac5 | 55 | } |
kayekss | 0:727737138ac5 | 56 | } |
kayekss | 0:727737138ac5 | 57 | } |
kayekss | 0:727737138ac5 | 58 | |
kayekss | 0:727737138ac5 | 59 | void setup() { |
kayekss | 0:727737138ac5 | 60 | #ifdef POWER_SAVE |
kayekss | 0:727737138ac5 | 61 | // Power down Ethernet PHY chip |
kayekss | 0:727737138ac5 | 62 | PHY_PowerDown(); |
kayekss | 0:727737138ac5 | 63 | |
kayekss | 0:727737138ac5 | 64 | // Power down unused peripherals |
kayekss | 0:727737138ac5 | 65 | Peripheral_PowerDown(0x40067200); |
kayekss | 0:727737138ac5 | 66 | #endif |
kayekss | 0:727737138ac5 | 67 | |
kayekss | 0:727737138ac5 | 68 | #if defined(POWER_SAVE) && defined(CLOCKUP) |
kayekss | 0:727737138ac5 | 69 | // Change clock speed to 120 MHz |
kayekss | 0:727737138ac5 | 70 | setSystemFrequency(0x03, 0x01, 15, 1); |
kayekss | 0:727737138ac5 | 71 | #endif |
kayekss | 0:727737138ac5 | 72 | |
kayekss | 0:727737138ac5 | 73 | // Enable pull-up at switch inputs |
kayekss | 2:ca10e33bde0a | 74 | swSerialSelect.mode(PullDown); |
kayekss | 0:727737138ac5 | 75 | swPanic.mode(PullUp); |
kayekss | 0:727737138ac5 | 76 | wait(0.2); // Wait a moment for stability |
kayekss | 0:727737138ac5 | 77 | |
kayekss | 0:727737138ac5 | 78 | // Read serial selector switch |
kayekss | 1:5f0c89bffec1 | 79 | serSource = swSerialSelect; |
kayekss | 0:727737138ac5 | 80 | |
kayekss | 0:727737138ac5 | 81 | // Open selected port |
kayekss | 0:727737138ac5 | 82 | if (serSource) { |
kayekss | 0:727737138ac5 | 83 | // Use MIDI port when high |
kayekss | 1:5f0c89bffec1 | 84 | midiIn.baud(31250); |
kayekss | 0:727737138ac5 | 85 | midiIn.format(8, Serial::None, 1); |
kayekss | 0:727737138ac5 | 86 | midiIn.attach(readMidiIn, Serial::RxIrq); |
kayekss | 0:727737138ac5 | 87 | } else { |
kayekss | 0:727737138ac5 | 88 | // Use serial MIDI when low |
kayekss | 0:727737138ac5 | 89 | pc.baud(38400); |
kayekss | 0:727737138ac5 | 90 | pc.format(8, Serial::None, 1); |
kayekss | 0:727737138ac5 | 91 | pc.attach(readMidiIn, Serial::RxIrq); |
kayekss | 0:727737138ac5 | 92 | } |
kayekss | 0:727737138ac5 | 93 | receivedBytes = 0; |
kayekss | 0:727737138ac5 | 94 | |
kayekss | 0:727737138ac5 | 95 | // Setup console |
kayekss | 0:727737138ac5 | 96 | console.baud(115200); |
kayekss | 0:727737138ac5 | 97 | console.format(8, Serial::None, 1); |
kayekss | 0:727737138ac5 | 98 | dumpMode = DUMP_NOTHING; |
kayekss | 0:727737138ac5 | 99 | |
kayekss | 0:727737138ac5 | 100 | // Setup SPI |
kayekss | 0:727737138ac5 | 101 | spi.format(16, 0); |
kayekss | 0:727737138ac5 | 102 | spi.frequency(12000000); |
kayekss | 0:727737138ac5 | 103 | dacCs = 1; |
kayekss | 0:727737138ac5 | 104 | |
kayekss | 0:727737138ac5 | 105 | // Initialize channels |
kayekss | 0:727737138ac5 | 106 | ch.initializeAll(); |
kayekss | 0:727737138ac5 | 107 | |
kayekss | 0:727737138ac5 | 108 | // Initialize note status |
kayekss | 0:727737138ac5 | 109 | for (uint16_t i = 0; i < NUM_INSTRUMENT; i++) { |
kayekss | 0:727737138ac5 | 110 | noteSent[i].noteOnMs = 0; |
kayekss | 0:727737138ac5 | 111 | noteSent[i].channel = 0; |
kayekss | 0:727737138ac5 | 112 | noteSent[i].noteNumber = 0; |
kayekss | 0:727737138ac5 | 113 | noteSent[i].velocity = 0; |
kayekss | 0:727737138ac5 | 114 | } |
kayekss | 0:727737138ac5 | 115 | |
kayekss | 0:727737138ac5 | 116 | // Start Timer |
kayekss | 0:727737138ac5 | 117 | __countMs = 0; |
kayekss | 0:727737138ac5 | 118 | t1ms.attach_us(&count1ms, 1000); |
kayekss | 0:727737138ac5 | 119 | |
kayekss | 0:727737138ac5 | 120 | // Start playback & attach interrupt |
kayekss | 2:ca10e33bde0a | 121 | float clockUpRatio = SystemCoreClock / 96000000.0; |
kayekss | 2:ca10e33bde0a | 122 | tSample.attach_us(&sampleOut, 1000000 * clockUpRatio / GeminiCore::samplingRate); |
kayekss | 0:727737138ac5 | 123 | } |
kayekss | 0:727737138ac5 | 124 | |
kayekss | 0:727737138ac5 | 125 | void consoleOperations(uint8_t c) { |
kayekss | 0:727737138ac5 | 126 | switch (c) { |
kayekss | 0:727737138ac5 | 127 | case 'b': |
kayekss | 0:727737138ac5 | 128 | checkBuffer(); |
kayekss | 0:727737138ac5 | 129 | break; |
kayekss | 0:727737138ac5 | 130 | case 'e': |
kayekss | 0:727737138ac5 | 131 | if (dumpMode != DUMP_EVENTS) { |
kayekss | 0:727737138ac5 | 132 | dumpMode = DUMP_EVENTS; |
kayekss | 0:727737138ac5 | 133 | } else { |
kayekss | 0:727737138ac5 | 134 | dumpMode = DUMP_NOTHING; |
kayekss | 0:727737138ac5 | 135 | } |
kayekss | 0:727737138ac5 | 136 | break; |
kayekss | 0:727737138ac5 | 137 | case 'f': |
kayekss | 0:727737138ac5 | 138 | buffer.flush(); |
kayekss | 0:727737138ac5 | 139 | console.printf("* Buffer flushed.\r\n"); |
kayekss | 0:727737138ac5 | 140 | break; |
kayekss | 0:727737138ac5 | 141 | case 'i': |
kayekss | 0:727737138ac5 | 142 | if (dumpMode == DUMP_INST) { |
kayekss | 0:727737138ac5 | 143 | dumpMode = DUMP_INST_DETAIL; |
kayekss | 0:727737138ac5 | 144 | } else if (dumpMode == DUMP_INST_DETAIL) { |
kayekss | 0:727737138ac5 | 145 | dumpMode = DUMP_NOTHING; |
kayekss | 0:727737138ac5 | 146 | } else { |
kayekss | 0:727737138ac5 | 147 | dumpMode = DUMP_INST; |
kayekss | 0:727737138ac5 | 148 | } |
kayekss | 0:727737138ac5 | 149 | break; |
kayekss | 0:727737138ac5 | 150 | case 'p': |
kayekss | 0:727737138ac5 | 151 | // Panic |
kayekss | 0:727737138ac5 | 152 | for (uint8_t i = 0; i < NUM_INSTRUMENT_IN_PERFORMER; i++) { |
kayekss | 0:727737138ac5 | 153 | gemCore.noteOff(i); |
kayekss | 0:727737138ac5 | 154 | noteSent[i].noteOnMs = 0; |
kayekss | 0:727737138ac5 | 155 | noteSent[i].channel = 0; |
kayekss | 0:727737138ac5 | 156 | noteSent[i].noteNumber = 0; |
kayekss | 0:727737138ac5 | 157 | noteSent[i].velocity = 0; |
kayekss | 0:727737138ac5 | 158 | } |
kayekss | 0:727737138ac5 | 159 | break; |
kayekss | 0:727737138ac5 | 160 | case 'r': |
kayekss | 0:727737138ac5 | 161 | console.printf("* Received MIDI bytes: %u\r\n", receivedBytes); |
kayekss | 0:727737138ac5 | 162 | break; |
kayekss | 0:727737138ac5 | 163 | default: break; |
kayekss | 0:727737138ac5 | 164 | } |
kayekss | 0:727737138ac5 | 165 | } |
kayekss | 0:727737138ac5 | 166 | |
kayekss | 0:727737138ac5 | 167 | void loop() { |
kayekss | 0:727737138ac5 | 168 | static uint32_t lastPollSwitchMs = __countMs; |
kayekss | 0:727737138ac5 | 169 | static bool prevstatePanic = 0; |
kayekss | 0:727737138ac5 | 170 | bool statePanic; |
kayekss | 0:727737138ac5 | 171 | |
kayekss | 0:727737138ac5 | 172 | // Serial console |
kayekss | 0:727737138ac5 | 173 | if (console.readable()) { |
kayekss | 0:727737138ac5 | 174 | consoleOperations(console.getc()); |
kayekss | 0:727737138ac5 | 175 | } |
kayekss | 0:727737138ac5 | 176 | |
kayekss | 0:727737138ac5 | 177 | // Poll switches |
kayekss | 0:727737138ac5 | 178 | if (__countMs > lastPollSwitchMs + 20) { |
kayekss | 0:727737138ac5 | 179 | lastPollSwitchMs = __countMs; |
kayekss | 0:727737138ac5 | 180 | |
kayekss | 0:727737138ac5 | 181 | statePanic = swPanic; |
kayekss | 0:727737138ac5 | 182 | |
kayekss | 0:727737138ac5 | 183 | // Panic (all note off and flush buffer) |
kayekss | 0:727737138ac5 | 184 | if (!statePanic && prevstatePanic) { |
kayekss | 0:727737138ac5 | 185 | buffer.flush(); |
kayekss | 0:727737138ac5 | 186 | for (uint8_t i = 0; i < NUM_INSTRUMENT_IN_PERFORMER; i++) { |
kayekss | 0:727737138ac5 | 187 | gemCore.noteOff(i); |
kayekss | 0:727737138ac5 | 188 | noteSent[i].noteOnMs = 0; |
kayekss | 0:727737138ac5 | 189 | noteSent[i].channel = 0; |
kayekss | 0:727737138ac5 | 190 | noteSent[i].noteNumber = 0; |
kayekss | 0:727737138ac5 | 191 | noteSent[i].velocity = 0; |
kayekss | 0:727737138ac5 | 192 | } |
kayekss | 0:727737138ac5 | 193 | } |
kayekss | 0:727737138ac5 | 194 | |
kayekss | 0:727737138ac5 | 195 | // Preserve this time's switch states |
kayekss | 0:727737138ac5 | 196 | prevstatePanic = statePanic; |
kayekss | 0:727737138ac5 | 197 | } |
kayekss | 0:727737138ac5 | 198 | |
kayekss | 0:727737138ac5 | 199 | // Parse MIDI messages |
kayekss | 0:727737138ac5 | 200 | parseMessage(buffer); |
kayekss | 0:727737138ac5 | 201 | |
kayekss | 0:727737138ac5 | 202 | // LEDs |
kayekss | 0:727737138ac5 | 203 | uint8_t busyCount = 0; |
kayekss | 0:727737138ac5 | 204 | for (uint8_t i = 0; i < NUM_INSTRUMENT_IN_PERFORMER; i++) { |
kayekss | 0:727737138ac5 | 205 | if (noteSent[i].noteOnMs) { |
kayekss | 0:727737138ac5 | 206 | busyCount++; |
kayekss | 0:727737138ac5 | 207 | } |
kayekss | 0:727737138ac5 | 208 | } |
kayekss | 0:727737138ac5 | 209 | ledBar = (1 << busyCount) - 1; |
kayekss | 0:727737138ac5 | 210 | } |
kayekss | 0:727737138ac5 | 211 | |
kayekss | 0:727737138ac5 | 212 | int main() { |
kayekss | 0:727737138ac5 | 213 | setup(); |
kayekss | 0:727737138ac5 | 214 | |
kayekss | 0:727737138ac5 | 215 | while (1) { |
kayekss | 0:727737138ac5 | 216 | loop(); |
kayekss | 0:727737138ac5 | 217 | } |
kayekss | 0:727737138ac5 | 218 | } |