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

Dependencies:   ClockControl PowerControl mbed

Committer:
kayekss
Date:
Sun Nov 09 08:00:33 2014 +0000
Revision:
0:727737138ac5
Child:
2:ca10e33bde0a
12-polyphonic "chiptune" MIDI synthesizer for mbed LPC1768 (Standalone version)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
kayekss 0:727737138ac5 1 #include "mbed.h"
kayekss 0:727737138ac5 2 #include "GeminiCore.h"
kayekss 0:727737138ac5 3
kayekss 0:727737138ac5 4 uint16_t const GeminiCore::samplingRate = 32000u;
kayekss 0:727737138ac5 5
kayekss 0:727737138ac5 6 /** Constructor of class GeminiCore */
kayekss 0:727737138ac5 7 GeminiCore::GeminiCore(uint8_t numInstruments) {
kayekss 0:727737138ac5 8 this->numInstruments = numInstruments;
kayekss 0:727737138ac5 9
kayekss 0:727737138ac5 10 // Instantiate instrument list
kayekss 0:727737138ac5 11 this->instrumentList = new Instrument[numInstruments];
kayekss 0:727737138ac5 12 for (uint8_t i = 0; i < numInstruments; i++) {
kayekss 0:727737138ac5 13 this->instrumentList[i].enable();
kayekss 0:727737138ac5 14 this->instrumentList[i].setSamplingRate(GeminiCore::samplingRate);
kayekss 0:727737138ac5 15 this->instrumentList[i].setWave(Wavetable::waveDefList[4]);
kayekss 0:727737138ac5 16 }
kayekss 0:727737138ac5 17
kayekss 0:727737138ac5 18 // Allocate bytes to preserve previous samples
kayekss 0:727737138ac5 19 prevSample = new uint8_t[numInstruments];
kayekss 0:727737138ac5 20
kayekss 0:727737138ac5 21 // Initialize random seeds
kayekss 0:727737138ac5 22 this->x8 = 77u;
kayekss 0:727737138ac5 23 this->x16 = 5501u;
kayekss 0:727737138ac5 24 }
kayekss 0:727737138ac5 25
kayekss 0:727737138ac5 26 /** Destructor of class GeminiCore */
kayekss 0:727737138ac5 27 GeminiCore::~GeminiCore() {
kayekss 0:727737138ac5 28 delete[] this->instrumentList;
kayekss 0:727737138ac5 29 delete[] this->prevSample;
kayekss 0:727737138ac5 30 }
kayekss 0:727737138ac5 31
kayekss 0:727737138ac5 32 /** Make a sample - should be called periodically depending on the sampling rate */
kayekss 0:727737138ac5 33 uint16_t GeminiCore::makeSample() {
kayekss 0:727737138ac5 34 Instrument* iThInst;
kayekss 0:727737138ac5 35 Wavetable::wave_t iThWave;
kayekss 0:727737138ac5 36 int32_t sample;
kayekss 0:727737138ac5 37 int32_t iThSample;
kayekss 0:727737138ac5 38 uint16_t phasePrev;
kayekss 0:727737138ac5 39 uint32_t duration;
kayekss 0:727737138ac5 40 uint8_t decayRatio;
kayekss 0:727737138ac5 41
kayekss 0:727737138ac5 42 sample = 0;
kayekss 0:727737138ac5 43 for (uint8_t i = 0; i < numInstruments; i++) {
kayekss 0:727737138ac5 44 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 45 iThWave = iThInst->getWave();
kayekss 0:727737138ac5 46
kayekss 0:727737138ac5 47 // Do nothing if the instrument is disabled or not sounding
kayekss 0:727737138ac5 48 if (!iThInst->isEnable() || iThInst->getFrequency() == 0) {
kayekss 0:727737138ac5 49 continue;
kayekss 0:727737138ac5 50 }
kayekss 0:727737138ac5 51
kayekss 0:727737138ac5 52 duration = iThInst->getDuration();
kayekss 0:727737138ac5 53 if (duration >> iThWave.decaySpeed >= 255 - iThWave.sustainLevel) {
kayekss 0:727737138ac5 54 decayRatio = iThWave.sustainLevel;
kayekss 0:727737138ac5 55 } else {
kayekss 0:727737138ac5 56 decayRatio = 256 - (duration >> iThWave.decaySpeed);
kayekss 0:727737138ac5 57 }
kayekss 0:727737138ac5 58
kayekss 0:727737138ac5 59 switch (iThWave.wavetype) {
kayekss 0:727737138ac5 60 case Wavetable::Noise:
kayekss 0:727737138ac5 61 phasePrev = iThInst->getPhase();
kayekss 0:727737138ac5 62 iThInst->advancePhase();
kayekss 0:727737138ac5 63
kayekss 0:727737138ac5 64 // If necessary, generate new random value
kayekss 0:727737138ac5 65 if ((iThInst->getPhase() >> 8) - (phasePrev >> 8) > 0) {
kayekss 0:727737138ac5 66 prevSample[i] = rand16() >> 8;
kayekss 0:727737138ac5 67 }
kayekss 0:727737138ac5 68 iThSample = prevSample[i];
kayekss 0:727737138ac5 69 break;
kayekss 0:727737138ac5 70 case Wavetable::LowPeriodNoise:
kayekss 0:727737138ac5 71 phasePrev = iThInst->getPhase();
kayekss 0:727737138ac5 72 iThInst->advancePhase();
kayekss 0:727737138ac5 73
kayekss 0:727737138ac5 74 // If necessary, generate new random value
kayekss 0:727737138ac5 75 if ((iThInst->getPhase() >> 8) - (phasePrev >> 8) > 0) {
kayekss 0:727737138ac5 76 prevSample[i] = rand8();
kayekss 0:727737138ac5 77 }
kayekss 0:727737138ac5 78 iThSample = prevSample[i];
kayekss 0:727737138ac5 79 break;
kayekss 0:727737138ac5 80 default:
kayekss 0:727737138ac5 81 iThInst->advancePhase();
kayekss 0:727737138ac5 82 iThSample = Wavetable::waveTableList[iThWave.wavetype][iThInst->getPhase() >> 8] - 128;
kayekss 0:727737138ac5 83 }
kayekss 0:727737138ac5 84 sample += iThSample * iThInst->getMasterVolume() * decayRatio;
kayekss 0:727737138ac5 85 }
kayekss 0:727737138ac5 86 sample >>= 10;
kayekss 0:727737138ac5 87 if (sample > 32767) sample = 32767;
kayekss 0:727737138ac5 88 if (sample < -32768) sample = -32768;
kayekss 0:727737138ac5 89 return (uint16_t) (sample + 32768);
kayekss 0:727737138ac5 90 }
kayekss 0:727737138ac5 91
kayekss 0:727737138ac5 92 /** Enable i-th Instrument */
kayekss 0:727737138ac5 93 bool GeminiCore::enable(uint8_t i) {
kayekss 0:727737138ac5 94 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 95
kayekss 0:727737138ac5 96 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 97 return false;
kayekss 0:727737138ac5 98 }
kayekss 0:727737138ac5 99 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 100 if (iThInst == NULL) {
kayekss 0:727737138ac5 101 return false;
kayekss 0:727737138ac5 102 }
kayekss 0:727737138ac5 103
kayekss 0:727737138ac5 104 iThInst->enable();
kayekss 0:727737138ac5 105 return true;
kayekss 0:727737138ac5 106 }
kayekss 0:727737138ac5 107
kayekss 0:727737138ac5 108 /** Disable i-th Instrument */
kayekss 0:727737138ac5 109 bool GeminiCore::disable(uint8_t i) {
kayekss 0:727737138ac5 110 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 111
kayekss 0:727737138ac5 112 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 113 return false;
kayekss 0:727737138ac5 114 }
kayekss 0:727737138ac5 115 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 116 if (iThInst == NULL) {
kayekss 0:727737138ac5 117 return false;
kayekss 0:727737138ac5 118 }
kayekss 0:727737138ac5 119
kayekss 0:727737138ac5 120 iThInst->disable();
kayekss 0:727737138ac5 121 return true;
kayekss 0:727737138ac5 122 }
kayekss 0:727737138ac5 123
kayekss 0:727737138ac5 124 /** Note on i-th Instrument */
kayekss 0:727737138ac5 125 bool GeminiCore::noteOn(uint8_t i, uint16_t frequency, uint8_t velocity) {
kayekss 0:727737138ac5 126 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 127
kayekss 0:727737138ac5 128 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 129 return false;
kayekss 0:727737138ac5 130 }
kayekss 0:727737138ac5 131 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 132 if (iThInst == NULL) {
kayekss 0:727737138ac5 133 return false;
kayekss 0:727737138ac5 134 }
kayekss 0:727737138ac5 135
kayekss 0:727737138ac5 136 iThInst->setFrequency(frequency); // @TODO pitch bend correction needed
kayekss 0:727737138ac5 137 iThInst->setVelocity(velocity);
kayekss 0:727737138ac5 138 return true;
kayekss 0:727737138ac5 139 }
kayekss 0:727737138ac5 140
kayekss 0:727737138ac5 141 /** Note off i-th Instrument */
kayekss 0:727737138ac5 142 bool GeminiCore::noteOff(uint8_t i) {
kayekss 0:727737138ac5 143 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 144
kayekss 0:727737138ac5 145 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 146 return false;
kayekss 0:727737138ac5 147 }
kayekss 0:727737138ac5 148 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 149 if (iThInst == NULL) {
kayekss 0:727737138ac5 150 return false;
kayekss 0:727737138ac5 151 }
kayekss 0:727737138ac5 152
kayekss 0:727737138ac5 153 iThInst->setFrequency(0);
kayekss 0:727737138ac5 154 return true;
kayekss 0:727737138ac5 155 }
kayekss 0:727737138ac5 156
kayekss 0:727737138ac5 157 /** Set volume (0..127) to i-th Instrument */
kayekss 0:727737138ac5 158 bool GeminiCore::volume(uint8_t i, uint8_t vo) {
kayekss 0:727737138ac5 159 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 160
kayekss 0:727737138ac5 161 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 162 return false;
kayekss 0:727737138ac5 163 }
kayekss 0:727737138ac5 164 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 165 if (iThInst == NULL) {
kayekss 0:727737138ac5 166 return false;
kayekss 0:727737138ac5 167 }
kayekss 0:727737138ac5 168
kayekss 0:727737138ac5 169 iThInst->setVolume(vo << 1); // 0..127 => 0..254
kayekss 0:727737138ac5 170 return true;
kayekss 0:727737138ac5 171 }
kayekss 0:727737138ac5 172
kayekss 0:727737138ac5 173 /** Set expression (0..127) to i-th Instrument */
kayekss 0:727737138ac5 174 bool GeminiCore::expression(uint8_t i, uint8_t ex) {
kayekss 0:727737138ac5 175 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 176
kayekss 0:727737138ac5 177 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 178 return false;
kayekss 0:727737138ac5 179 }
kayekss 0:727737138ac5 180 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 181 if (iThInst == NULL) {
kayekss 0:727737138ac5 182 return false;
kayekss 0:727737138ac5 183 }
kayekss 0:727737138ac5 184
kayekss 0:727737138ac5 185 iThInst->setExpression(ex << 1); // 0..127 => 0..254
kayekss 0:727737138ac5 186 return true;
kayekss 0:727737138ac5 187 }
kayekss 0:727737138ac5 188
kayekss 0:727737138ac5 189 bool GeminiCore::pitchBend(uint8_t i, int16_t pb) {
kayekss 0:727737138ac5 190 // @TODO
kayekss 0:727737138ac5 191 return true;
kayekss 0:727737138ac5 192 }
kayekss 0:727737138ac5 193
kayekss 0:727737138ac5 194 /** Set wave parameters to i-th Instrument */
kayekss 0:727737138ac5 195 bool GeminiCore::setWave(uint8_t i, Wavetable::wave_t w) {
kayekss 0:727737138ac5 196 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 197
kayekss 0:727737138ac5 198 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 199 return false;
kayekss 0:727737138ac5 200 }
kayekss 0:727737138ac5 201 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 202 if (iThInst == NULL) {
kayekss 0:727737138ac5 203 return false;
kayekss 0:727737138ac5 204 }
kayekss 0:727737138ac5 205
kayekss 0:727737138ac5 206 iThInst->setWave(w);
kayekss 0:727737138ac5 207 return true;
kayekss 0:727737138ac5 208 }
kayekss 0:727737138ac5 209
kayekss 0:727737138ac5 210 /** Get instrument list */
kayekss 0:727737138ac5 211 Instrument* GeminiCore::getInstrumentList() {
kayekss 0:727737138ac5 212 return this->instrumentList;
kayekss 0:727737138ac5 213 }
kayekss 0:727737138ac5 214
kayekss 0:727737138ac5 215 /** Generate an 8-bit random number */
kayekss 0:727737138ac5 216 uint8_t GeminiCore::rand8() {
kayekss 0:727737138ac5 217 x8 ^= x8 << 7;
kayekss 0:727737138ac5 218 x8 ^= x8 >> 5;
kayekss 0:727737138ac5 219 x8 ^= x8 << 3;
kayekss 0:727737138ac5 220 return x8;
kayekss 0:727737138ac5 221 }
kayekss 0:727737138ac5 222
kayekss 0:727737138ac5 223 /** Generate a 16-bit random number */
kayekss 0:727737138ac5 224 uint16_t GeminiCore::rand16() {
kayekss 0:727737138ac5 225 x16 ^= x16 << 13;
kayekss 0:727737138ac5 226 x16 ^= x16 >> 9;
kayekss 0:727737138ac5 227 x16 ^= x16 << 7;
kayekss 0:727737138ac5 228 return x16;
kayekss 0:727737138ac5 229 }