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

Dependencies:   ClockControl PowerControl mbed

Revision:
0:727737138ac5
Child:
2:ca10e33bde0a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GeminiCore.cpp	Sun Nov 09 08:00:33 2014 +0000
@@ -0,0 +1,229 @@
+#include "mbed.h"
+#include "GeminiCore.h"
+
+uint16_t const GeminiCore::samplingRate = 32000u;
+
+/** Constructor of class GeminiCore */
+GeminiCore::GeminiCore(uint8_t numInstruments) {
+    this->numInstruments = numInstruments;
+    
+    // Instantiate instrument list
+    this->instrumentList = new Instrument[numInstruments];
+    for (uint8_t i = 0; i < numInstruments; i++) {
+        this->instrumentList[i].enable();
+        this->instrumentList[i].setSamplingRate(GeminiCore::samplingRate);
+        this->instrumentList[i].setWave(Wavetable::waveDefList[4]);
+    }
+    
+    // Allocate bytes to preserve previous samples
+    prevSample = new uint8_t[numInstruments];
+    
+    // Initialize random seeds
+    this->x8 = 77u;
+    this->x16 = 5501u;
+}
+
+/** Destructor of class GeminiCore */
+GeminiCore::~GeminiCore() {
+    delete[] this->instrumentList;
+    delete[] this->prevSample;
+}
+
+/** Make a sample - should be called periodically depending on the sampling rate */
+uint16_t GeminiCore::makeSample() {
+    Instrument* iThInst;
+    Wavetable::wave_t iThWave;
+    int32_t     sample;
+    int32_t     iThSample;
+    uint16_t    phasePrev;
+    uint32_t    duration;
+    uint8_t     decayRatio;
+    
+    sample = 0;
+    for (uint8_t i = 0; i < numInstruments; i++) {
+        iThInst = &instrumentList[i];
+        iThWave = iThInst->getWave();
+        
+        // Do nothing if the instrument is disabled or not sounding
+        if (!iThInst->isEnable() || iThInst->getFrequency() == 0) {
+            continue;
+        }
+        
+        duration = iThInst->getDuration();
+        if (duration >> iThWave.decaySpeed >= 255 - iThWave.sustainLevel) {
+            decayRatio = iThWave.sustainLevel;
+        } else {
+            decayRatio = 256 - (duration >> iThWave.decaySpeed);
+        }
+        
+        switch (iThWave.wavetype) {
+        case Wavetable::Noise:
+            phasePrev = iThInst->getPhase();
+            iThInst->advancePhase();
+            
+            // If necessary, generate new random value
+            if ((iThInst->getPhase() >> 8) - (phasePrev >> 8) > 0) {
+                prevSample[i] = rand16() >> 8;
+            }
+            iThSample = prevSample[i];
+            break;
+        case Wavetable::LowPeriodNoise:
+            phasePrev = iThInst->getPhase();
+            iThInst->advancePhase();
+            
+            // If necessary, generate new random value
+            if ((iThInst->getPhase() >> 8) - (phasePrev >> 8) > 0) {
+                prevSample[i] = rand8();
+            }
+            iThSample = prevSample[i];
+            break;
+        default:
+            iThInst->advancePhase();
+            iThSample = Wavetable::waveTableList[iThWave.wavetype][iThInst->getPhase() >> 8] - 128;
+        }
+        sample += iThSample * iThInst->getMasterVolume() * decayRatio;
+    }
+    sample >>= 10;
+    if (sample >  32767) sample =  32767;
+    if (sample < -32768) sample = -32768;
+    return (uint16_t) (sample + 32768);
+}
+
+/** Enable i-th Instrument */
+bool GeminiCore::enable(uint8_t i) {
+    Instrument* iThInst = NULL;
+    
+    if (i >= numInstruments || instrumentList == NULL) {
+        return false;
+    }
+    iThInst = &instrumentList[i];
+    if (iThInst == NULL) {
+        return false;
+    }
+    
+    iThInst->enable();
+    return true;
+}
+
+/** Disable i-th Instrument */
+bool GeminiCore::disable(uint8_t i) {
+    Instrument* iThInst = NULL;
+    
+    if (i >= numInstruments || instrumentList == NULL) {
+        return false;
+    }
+    iThInst = &instrumentList[i];
+    if (iThInst == NULL) {
+        return false;
+    }
+    
+    iThInst->disable();
+    return true;
+}
+
+/** Note on i-th Instrument */
+bool GeminiCore::noteOn(uint8_t i, uint16_t frequency, uint8_t velocity) {
+    Instrument* iThInst = NULL;
+    
+    if (i >= numInstruments || instrumentList == NULL) {
+        return false;
+    }
+    iThInst = &instrumentList[i];
+    if (iThInst == NULL) {
+        return false;
+    }
+    
+    iThInst->setFrequency(frequency);  // @TODO pitch bend correction needed
+    iThInst->setVelocity(velocity);
+    return true;
+}
+
+/** Note off i-th Instrument */
+bool GeminiCore::noteOff(uint8_t i) {
+    Instrument* iThInst = NULL;
+    
+    if (i >= numInstruments || instrumentList == NULL) {
+        return false;
+    }
+    iThInst = &instrumentList[i];
+    if (iThInst == NULL) {
+        return false;
+    }
+    
+    iThInst->setFrequency(0);
+    return true;
+}
+
+/** Set volume (0..127) to i-th Instrument */
+bool GeminiCore::volume(uint8_t i, uint8_t vo) {
+    Instrument* iThInst = NULL;
+    
+    if (i >= numInstruments || instrumentList == NULL) {
+        return false;
+    }
+    iThInst = &instrumentList[i];
+    if (iThInst == NULL) {
+        return false;
+    }
+    
+    iThInst->setVolume(vo << 1);  // 0..127 => 0..254
+    return true;
+}
+
+/** Set expression (0..127) to i-th Instrument */
+bool GeminiCore::expression(uint8_t i, uint8_t ex) {
+    Instrument* iThInst = NULL;
+    
+    if (i >= numInstruments || instrumentList == NULL) {
+        return false;
+    }
+    iThInst = &instrumentList[i];
+    if (iThInst == NULL) {
+        return false;
+    }
+    
+    iThInst->setExpression(ex << 1);  // 0..127 => 0..254
+    return true;
+}
+
+bool GeminiCore::pitchBend(uint8_t i, int16_t pb) {
+    // @TODO
+    return true;
+}
+
+/** Set wave parameters to i-th Instrument */
+bool GeminiCore::setWave(uint8_t i, Wavetable::wave_t w) {
+    Instrument* iThInst = NULL;
+    
+    if (i >= numInstruments || instrumentList == NULL) {
+        return false;
+    }
+    iThInst = &instrumentList[i];
+    if (iThInst == NULL) {
+        return false;
+    }
+    
+    iThInst->setWave(w);
+    return true;
+}
+
+/** Get instrument list */
+Instrument* GeminiCore::getInstrumentList() {
+    return this->instrumentList;
+}
+
+/** Generate an 8-bit random number */
+uint8_t GeminiCore::rand8() {
+    x8 ^= x8 << 7;
+    x8 ^= x8 >> 5;
+    x8 ^= x8 << 3;
+    return x8;
+}
+
+/** Generate a 16-bit random number */
+uint16_t GeminiCore::rand16() {
+    x16 ^= x16 << 13;
+    x16 ^= x16 >> 9;
+    x16 ^= x16 << 7;
+    return x16;
+}