12-polyphonic "chiptune" MIDI synthesizer for LPC1768 (Standalone version)
Dependencies: ClockControl PowerControl mbed
Diff: GeminiCore.cpp
- Revision:
- 0:727737138ac5
- Child:
- 2:ca10e33bde0a
diff -r 000000000000 -r 727737138ac5 GeminiCore.cpp --- /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; +}