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

Dependencies:   ClockControl PowerControl mbed

Committer:
kayekss
Date:
Tue Dec 09 15:04:13 2014 +0000
Revision:
4:b2423ad4b248
Parent:
3:cf57d7031c12
Supports pitch bend messages (pitch bend sensitivity is currently fixed to 2)

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