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:
0:727737138ac5
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 "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 2:ca10e33bde0a 33 uint16_t GeminiCore::makeSample(note_t* noteSent) {
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 2:ca10e33bde0a 56 decayRatio = 255 - (duration >> iThWave.decaySpeed);
kayekss 2:ca10e33bde0a 57 }
kayekss 2:ca10e33bde0a 58 // Skip/deallocate note when it is completely decayed
kayekss 2:ca10e33bde0a 59 if (decayRatio == 0) {
kayekss 2:ca10e33bde0a 60 noteSent[i].noteOnMs = 0;
kayekss 2:ca10e33bde0a 61 noteSent[i].channel = 0;
kayekss 2:ca10e33bde0a 62 noteSent[i].noteNumber = 0;
kayekss 2:ca10e33bde0a 63 noteSent[i].velocity = 0;
kayekss 2:ca10e33bde0a 64 iThInst->setFrequency(0);
kayekss 2:ca10e33bde0a 65 continue;
kayekss 0:727737138ac5 66 }
kayekss 0:727737138ac5 67
kayekss 0:727737138ac5 68 switch (iThWave.wavetype) {
kayekss 0:727737138ac5 69 case Wavetable::Noise:
kayekss 0:727737138ac5 70 phasePrev = iThInst->getPhase();
kayekss 0:727737138ac5 71 iThInst->advancePhase();
kayekss 0:727737138ac5 72
kayekss 0:727737138ac5 73 // If necessary, generate new random value
kayekss 0:727737138ac5 74 if ((iThInst->getPhase() >> 8) - (phasePrev >> 8) > 0) {
kayekss 0:727737138ac5 75 prevSample[i] = rand16() >> 8;
kayekss 0:727737138ac5 76 }
kayekss 0:727737138ac5 77 iThSample = prevSample[i];
kayekss 0:727737138ac5 78 break;
kayekss 0:727737138ac5 79 case Wavetable::LowPeriodNoise:
kayekss 0:727737138ac5 80 phasePrev = iThInst->getPhase();
kayekss 0:727737138ac5 81 iThInst->advancePhase();
kayekss 0:727737138ac5 82
kayekss 0:727737138ac5 83 // If necessary, generate new random value
kayekss 0:727737138ac5 84 if ((iThInst->getPhase() >> 8) - (phasePrev >> 8) > 0) {
kayekss 0:727737138ac5 85 prevSample[i] = rand8();
kayekss 0:727737138ac5 86 }
kayekss 0:727737138ac5 87 iThSample = prevSample[i];
kayekss 0:727737138ac5 88 break;
kayekss 0:727737138ac5 89 default:
kayekss 0:727737138ac5 90 iThInst->advancePhase();
kayekss 0:727737138ac5 91 iThSample = Wavetable::waveTableList[iThWave.wavetype][iThInst->getPhase() >> 8] - 128;
kayekss 0:727737138ac5 92 }
kayekss 0:727737138ac5 93 sample += iThSample * iThInst->getMasterVolume() * decayRatio;
kayekss 0:727737138ac5 94 }
kayekss 0:727737138ac5 95 sample >>= 10;
kayekss 0:727737138ac5 96 if (sample > 32767) sample = 32767;
kayekss 0:727737138ac5 97 if (sample < -32768) sample = -32768;
kayekss 0:727737138ac5 98 return (uint16_t) (sample + 32768);
kayekss 0:727737138ac5 99 }
kayekss 0:727737138ac5 100
kayekss 0:727737138ac5 101 /** Enable i-th Instrument */
kayekss 0:727737138ac5 102 bool GeminiCore::enable(uint8_t i) {
kayekss 0:727737138ac5 103 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 104
kayekss 0:727737138ac5 105 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 106 return false;
kayekss 0:727737138ac5 107 }
kayekss 0:727737138ac5 108 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 109 if (iThInst == NULL) {
kayekss 0:727737138ac5 110 return false;
kayekss 0:727737138ac5 111 }
kayekss 0:727737138ac5 112
kayekss 0:727737138ac5 113 iThInst->enable();
kayekss 0:727737138ac5 114 return true;
kayekss 0:727737138ac5 115 }
kayekss 0:727737138ac5 116
kayekss 0:727737138ac5 117 /** Disable i-th Instrument */
kayekss 0:727737138ac5 118 bool GeminiCore::disable(uint8_t i) {
kayekss 0:727737138ac5 119 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 120
kayekss 0:727737138ac5 121 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 122 return false;
kayekss 0:727737138ac5 123 }
kayekss 0:727737138ac5 124 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 125 if (iThInst == NULL) {
kayekss 0:727737138ac5 126 return false;
kayekss 0:727737138ac5 127 }
kayekss 0:727737138ac5 128
kayekss 0:727737138ac5 129 iThInst->disable();
kayekss 0:727737138ac5 130 return true;
kayekss 0:727737138ac5 131 }
kayekss 0:727737138ac5 132
kayekss 0:727737138ac5 133 /** Note on i-th Instrument */
kayekss 0:727737138ac5 134 bool GeminiCore::noteOn(uint8_t i, uint16_t frequency, uint8_t velocity) {
kayekss 0:727737138ac5 135 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 136
kayekss 0:727737138ac5 137 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 138 return false;
kayekss 0:727737138ac5 139 }
kayekss 0:727737138ac5 140 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 141 if (iThInst == NULL) {
kayekss 0:727737138ac5 142 return false;
kayekss 0:727737138ac5 143 }
kayekss 0:727737138ac5 144
kayekss 0:727737138ac5 145 iThInst->setFrequency(frequency); // @TODO pitch bend correction needed
kayekss 0:727737138ac5 146 iThInst->setVelocity(velocity);
kayekss 0:727737138ac5 147 return true;
kayekss 0:727737138ac5 148 }
kayekss 0:727737138ac5 149
kayekss 0:727737138ac5 150 /** Note off i-th Instrument */
kayekss 0:727737138ac5 151 bool GeminiCore::noteOff(uint8_t i) {
kayekss 0:727737138ac5 152 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 153
kayekss 0:727737138ac5 154 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 155 return false;
kayekss 0:727737138ac5 156 }
kayekss 0:727737138ac5 157 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 158 if (iThInst == NULL) {
kayekss 0:727737138ac5 159 return false;
kayekss 0:727737138ac5 160 }
kayekss 0:727737138ac5 161
kayekss 0:727737138ac5 162 iThInst->setFrequency(0);
kayekss 0:727737138ac5 163 return true;
kayekss 0:727737138ac5 164 }
kayekss 0:727737138ac5 165
kayekss 0:727737138ac5 166 /** Set volume (0..127) to i-th Instrument */
kayekss 0:727737138ac5 167 bool GeminiCore::volume(uint8_t i, uint8_t vo) {
kayekss 0:727737138ac5 168 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 169
kayekss 0:727737138ac5 170 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 171 return false;
kayekss 0:727737138ac5 172 }
kayekss 0:727737138ac5 173 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 174 if (iThInst == NULL) {
kayekss 0:727737138ac5 175 return false;
kayekss 0:727737138ac5 176 }
kayekss 0:727737138ac5 177
kayekss 0:727737138ac5 178 iThInst->setVolume(vo << 1); // 0..127 => 0..254
kayekss 0:727737138ac5 179 return true;
kayekss 0:727737138ac5 180 }
kayekss 0:727737138ac5 181
kayekss 0:727737138ac5 182 /** Set expression (0..127) to i-th Instrument */
kayekss 0:727737138ac5 183 bool GeminiCore::expression(uint8_t i, uint8_t ex) {
kayekss 0:727737138ac5 184 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 185
kayekss 0:727737138ac5 186 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 187 return false;
kayekss 0:727737138ac5 188 }
kayekss 0:727737138ac5 189 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 190 if (iThInst == NULL) {
kayekss 0:727737138ac5 191 return false;
kayekss 0:727737138ac5 192 }
kayekss 0:727737138ac5 193
kayekss 0:727737138ac5 194 iThInst->setExpression(ex << 1); // 0..127 => 0..254
kayekss 0:727737138ac5 195 return true;
kayekss 0:727737138ac5 196 }
kayekss 0:727737138ac5 197
kayekss 0:727737138ac5 198 bool GeminiCore::pitchBend(uint8_t i, int16_t pb) {
kayekss 0:727737138ac5 199 // @TODO
kayekss 0:727737138ac5 200 return true;
kayekss 0:727737138ac5 201 }
kayekss 0:727737138ac5 202
kayekss 0:727737138ac5 203 /** Set wave parameters to i-th Instrument */
kayekss 0:727737138ac5 204 bool GeminiCore::setWave(uint8_t i, Wavetable::wave_t w) {
kayekss 0:727737138ac5 205 Instrument* iThInst = NULL;
kayekss 0:727737138ac5 206
kayekss 0:727737138ac5 207 if (i >= numInstruments || instrumentList == NULL) {
kayekss 0:727737138ac5 208 return false;
kayekss 0:727737138ac5 209 }
kayekss 0:727737138ac5 210 iThInst = &instrumentList[i];
kayekss 0:727737138ac5 211 if (iThInst == NULL) {
kayekss 0:727737138ac5 212 return false;
kayekss 0:727737138ac5 213 }
kayekss 0:727737138ac5 214
kayekss 0:727737138ac5 215 iThInst->setWave(w);
kayekss 0:727737138ac5 216 return true;
kayekss 0:727737138ac5 217 }
kayekss 0:727737138ac5 218
kayekss 0:727737138ac5 219 /** Get instrument list */
kayekss 0:727737138ac5 220 Instrument* GeminiCore::getInstrumentList() {
kayekss 0:727737138ac5 221 return this->instrumentList;
kayekss 0:727737138ac5 222 }
kayekss 0:727737138ac5 223
kayekss 0:727737138ac5 224 /** Generate an 8-bit random number */
kayekss 0:727737138ac5 225 uint8_t GeminiCore::rand8() {
kayekss 0:727737138ac5 226 x8 ^= x8 << 7;
kayekss 0:727737138ac5 227 x8 ^= x8 >> 5;
kayekss 0:727737138ac5 228 x8 ^= x8 << 3;
kayekss 0:727737138ac5 229 return x8;
kayekss 0:727737138ac5 230 }
kayekss 0:727737138ac5 231
kayekss 0:727737138ac5 232 /** Generate a 16-bit random number */
kayekss 0:727737138ac5 233 uint16_t GeminiCore::rand16() {
kayekss 0:727737138ac5 234 x16 ^= x16 << 13;
kayekss 0:727737138ac5 235 x16 ^= x16 >> 9;
kayekss 0:727737138ac5 236 x16 ^= x16 << 7;
kayekss 0:727737138ac5 237 return x16;
kayekss 0:727737138ac5 238 }