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

Dependencies:   ClockControl PowerControl mbed

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?

UserRevisionLine numberNew 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 }