A MIDI piano synthesizer that implements the Karplus Strong physical modeling algorithm.

Dependencies:   mbed USBDevice PinDetect

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