
A MIDI piano synthesizer that implements the Karplus Strong physical modeling algorithm.
Dependencies: mbed USBDevice PinDetect
Diff: Audio/Synthesizer.cpp
- Revision:
- 13:bb0ec927e458
- Parent:
- 9:1e012f67470c
- Child:
- 18:26d93c5b9bb6
--- a/Audio/Synthesizer.cpp Wed Apr 13 19:48:15 2016 +0000 +++ b/Audio/Synthesizer.cpp Sun Apr 17 21:35:23 2016 +0000 @@ -10,10 +10,11 @@ * Output should be in the range of [-1.0, 1.0] and saved back into the buffer. */ typedef void (Synthesizer::*processorFunction)(); -const int numSynths = 4; +const int numSynths = 5; // Array of pointers to all synthesizer functions. processorFunction processors[] = { + &Synthesizer::processKarplusStrong, &Synthesizer::processSine, &Synthesizer::processTriangle, &Synthesizer::processSquare, @@ -32,6 +33,7 @@ void Synthesizer::midiNoteOn(int key, int velocity) { float freq = 440.0 * std::pow(2.0, float(key - 69) / 12.0); + float velocityFloat = float(velocity) / 127.0; // Make sure we are in bounds. if (freq < C::MIN_FREQUENCY) { @@ -47,7 +49,7 @@ if (currentState == OFF) { // We can immediately play the new note. bufferSize = size; - this->velocity = float(velocity) / 127.0; + this->velocity = velocityFloat; voiceIndex = Synthesizer::nextVoiceIndex; ++Synthesizer::nextVoiceIndex; @@ -56,8 +58,11 @@ } else { // Put the values in the queue for later. nextBufferSize = size; - nextVelocity = float(velocity) / 127.0; + nextVelocity = velocityFloat; } + + // Signal the Karplus Strong processor to calculate a new note. + karplusStrong.midiNoteOn(key, velocityFloat); } void Synthesizer::midiNoteOff() { @@ -69,26 +74,21 @@ } float Synthesizer::getSample() { + float outputSample; if (currentState == FILL && fromDisabled) { // The buffer may contain the release of the previous note so just return 0.0 - return 0.0; + outputSample = 0.0; + } else { + // Simply return the next sample. Do not increment. + outputSample = buffer[bufferIndex]; } - // Simply return the next sample. Do not increment. - return buffer[bufferIndex]; -} - -void Synthesizer::processBuffer() { - // Assert that we are playing. - if (currentState == OFF) { - #ifdef DEBUG - printf("Error: Attempting to process a disabled synthesizer."); - #endif - return; - } - + // Process the next period. // Use the current processor to process the buffer. (this->*processors[processorIndex])(); + + // Return the sample. + return outputSample; } bool Synthesizer::isPlaying() { @@ -122,23 +122,28 @@ // Processor Functions. +void Synthesizer::processKarplusStrong() { + if (currentState == FILL) { + buffer[bufferIndex] = karplusStrong.fillBuffer(bufferIndex); + ++bufferIndex; + + checkFillBounds(); + } else { + // Process for sustain or release. + float inputSample = buffer[bufferIndex]; + buffer[bufferIndex] = karplusStrong.processBuffer(inputSample); + // Check transition logic. + identityProcess(); + } +} + void Synthesizer::processSine() { if (currentState == FILL) { // Create the sine wave. buffer[bufferIndex] = velocity * sin(TWO_PI * float(bufferIndex) / float(bufferSize)); ++bufferIndex; - // Check if we have reached the end of the buffer. - if (bufferIndex == bufferSize) { - bufferIndex = 0; - - // Check if there are new notes waiting in the queue. - if (nextBufferSize != -1) { - currentState = RELEASE; - } else { - currentState = SUSTAIN; - } - } + checkFillBounds(); } else { identityProcess(); } @@ -158,17 +163,7 @@ buffer[bufferIndex] = velocity * sample; ++bufferIndex; - // Check if we have reached the end of the buffer. - if (bufferIndex == bufferSize) { - bufferIndex = 0; - - // Check if there are new notes waiting in the queue. - if (nextBufferSize != -1) { - currentState = RELEASE; - } else { - currentState = SUSTAIN; - } - } + checkFillBounds(); } else { identityProcess(); } @@ -180,17 +175,7 @@ buffer[bufferIndex] = bufferIndex < (bufferSize >> 1) ? -velocity : velocity; ++bufferIndex; - // Check if we have reached the end of the buffer. - if (bufferIndex == bufferSize) { - bufferIndex = 0; - - // Check if there are new notes waiting in the queue. - if (nextBufferSize != -1) { - currentState = RELEASE; - } else { - currentState = SUSTAIN; - } - } + checkFillBounds(); } else { identityProcess(); } @@ -202,17 +187,7 @@ buffer[bufferIndex] = velocity * (1.0 - 2.0 * float(bufferIndex) / float(bufferSize)); ++bufferIndex; - // Check if we have reached the end of the buffer. - if (bufferIndex == bufferSize) { - bufferIndex = 0; - - // Check if there are new notes waiting in the queue. - if (nextBufferSize != -1) { - currentState = RELEASE; - } else { - currentState = SUSTAIN; - } - } + checkFillBounds(); } else { identityProcess(); } @@ -247,4 +222,18 @@ voiceIndex = -1; } } +} + +void Synthesizer::checkFillBounds() { + // Check if we have reached the end of the buffer. + if (bufferIndex == bufferSize) { + bufferIndex = 0; + + // Check if there are new notes waiting in the queue. + if (nextBufferSize != -1) { + currentState = RELEASE; + } else { + currentState = SUSTAIN; + } + } } \ No newline at end of file