Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed USBDevice PinDetect
Synthesizer.cpp
00001 00002 #include "Synthesizer.h" 00003 00004 const float TWO_PI = 6.28318530717959; 00005 00006 /** 00007 * A function that acts as an individual synthesizer. 00008 * It's job is to process the next sample at the current index 00009 * based on the current state of the overall synthesizer. 00010 * Output should be in the range of [-1.0, 1.0] and saved back into the buffer. 00011 */ 00012 typedef void (Synthesizer::*processorFunction)(); 00013 const int numSynths = 5; 00014 00015 // Array of pointers to all synthesizer functions. 00016 processorFunction processors[] = { 00017 &Synthesizer::processKarplusStrong, 00018 &Synthesizer::processSine, 00019 &Synthesizer::processTriangle, 00020 &Synthesizer::processSquare, 00021 &Synthesizer::processSaw, 00022 }; 00023 00024 int64_t Synthesizer::nextVoiceIndex = 0; 00025 00026 Synthesizer::Synthesizer() { 00027 bufferIndex = 0; 00028 currentState = OFF; 00029 nextBufferSize = -1; 00030 voiceIndex = -1; 00031 processorIndex = 0; 00032 } 00033 00034 void Synthesizer::midiNoteOn(int key, int velocity) { 00035 float freq = 440.0 * std::pow(2.0, float(key - 69) / 12.0); 00036 float velocityFloat = float(velocity) / 127.0; 00037 00038 // Make sure we are in bounds. 00039 if (freq < C::MIN_FREQUENCY) { 00040 #ifdef DEBUG 00041 printf("Error: Note is below minimum frequency"); 00042 #endif 00043 return; 00044 } 00045 00046 currentKey = key; 00047 int size = int((float(C::SAMPLE_RATE) / freq) + 0.5); 00048 00049 if (currentState == OFF) { 00050 // We can immediately play the new note. 00051 bufferSize = size; 00052 this->velocity = velocityFloat; 00053 00054 voiceIndex = Synthesizer::nextVoiceIndex; 00055 ++Synthesizer::nextVoiceIndex; 00056 fromDisabled = true; 00057 currentState = FILL; 00058 } else { 00059 // Put the values in the queue for later. 00060 nextBufferSize = size; 00061 nextVelocity = velocityFloat; 00062 } 00063 00064 // Signal the Karplus Strong processor to calculate a new note. 00065 karplusStrong.midiNoteOn(key, velocityFloat); 00066 } 00067 00068 void Synthesizer::midiNoteOff() { 00069 // Begin release of current note. 00070 currentState = RELEASE; 00071 00072 // Clear the queue. 00073 nextBufferSize = -1; 00074 } 00075 00076 float Synthesizer::getSample() { 00077 float outputSample; 00078 if (currentState == FILL && fromDisabled) { 00079 // The buffer may contain the release of the previous note so just return 0.0 00080 outputSample = 0.0; 00081 } else { 00082 // Simply return the next sample. Do not increment. 00083 outputSample = buffer[bufferIndex]; 00084 } 00085 00086 // Process the next period. 00087 // Use the current processor to process the buffer. 00088 (this->*processors[processorIndex])(); 00089 00090 // Return the sample. 00091 return outputSample; 00092 } 00093 00094 bool Synthesizer::isPlaying() { 00095 return currentState != OFF; 00096 } 00097 00098 int64_t Synthesizer::getVoiceIndex() { 00099 return voiceIndex; 00100 } 00101 00102 int Synthesizer::nextSynth(int direction) { 00103 // Rotate to the next synth. 00104 processorIndex += direction; 00105 if (processorIndex >= numSynths) { 00106 processorIndex -= numSynths; 00107 } else if (processorIndex < 0) { 00108 processorIndex += numSynths; 00109 } 00110 00111 // If we are playing, restart the buffer. 00112 if (isPlaying()) { 00113 fromDisabled = true; 00114 bufferIndex = 0; 00115 currentState = FILL; 00116 } 00117 00118 return processorIndex; 00119 } 00120 00121 int Synthesizer::getCurrentKey() { 00122 return currentKey; 00123 } 00124 00125 // Processor Functions. 00126 00127 void Synthesizer::processKarplusStrong() { 00128 if (currentState == FILL) { 00129 buffer[bufferIndex] = karplusStrong.fillBuffer(bufferIndex); 00130 ++bufferIndex; 00131 00132 checkFillBounds(); 00133 } else { 00134 // Process for sustain or release. 00135 float inputSample = buffer[bufferIndex]; 00136 buffer[bufferIndex] = karplusStrong.processBuffer(inputSample); 00137 // Check transition logic. 00138 identityProcess(); 00139 } 00140 } 00141 00142 void Synthesizer::processSine() { 00143 if (currentState == FILL) { 00144 // Create the sine wave. 00145 buffer[bufferIndex] = velocity * sin(TWO_PI * float(bufferIndex) / float(bufferSize)); 00146 ++bufferIndex; 00147 00148 checkFillBounds(); 00149 } else { 00150 identityProcess(); 00151 } 00152 } 00153 00154 void Synthesizer::processTriangle() { 00155 if (currentState == FILL) { 00156 // Create the triangle wave. 00157 // Rotate pi/2 to remove phase offset. 00158 int index = (bufferIndex + (bufferSize >> 2)) % bufferSize; 00159 // Calculate linear function from -1 to 3 00160 int sample = -1.0 + (4.0 * float(index) / float(bufferSize)); 00161 // Redirect second half of the line. 00162 if (sample > 1.0) { 00163 sample = -sample + 2.0; 00164 } 00165 buffer[bufferIndex] = velocity * sample; 00166 ++bufferIndex; 00167 00168 checkFillBounds(); 00169 } else { 00170 identityProcess(); 00171 } 00172 } 00173 00174 void Synthesizer::processSquare() { 00175 if (currentState == FILL) { 00176 // Create the square wave. 00177 buffer[bufferIndex] = bufferIndex < (bufferSize >> 1) ? -velocity : velocity; 00178 ++bufferIndex; 00179 00180 checkFillBounds(); 00181 } else { 00182 identityProcess(); 00183 } 00184 } 00185 00186 void Synthesizer::processSaw() { 00187 if (currentState == FILL) { 00188 // Create the saw wave. 00189 buffer[bufferIndex] = velocity * (1.0 - 2.0 * float(bufferIndex) / float(bufferSize)); 00190 ++bufferIndex; 00191 00192 checkFillBounds(); 00193 } else { 00194 identityProcess(); 00195 } 00196 } 00197 00198 void Synthesizer::identityProcess() { 00199 if (currentState == RELEASE) { 00200 // Attenuate the current buffer. 00201 buffer[bufferIndex] *= -(float(bufferIndex) / float(bufferSize)) + 1.0; 00202 } 00203 00204 ++bufferIndex; 00205 00206 // Check if we have reached the end of the buffer. 00207 if (bufferIndex == bufferSize) { 00208 bufferIndex = 0; 00209 00210 // Check the queue to see if we have a new note waiting. 00211 if (nextBufferSize != -1) { 00212 if (currentState == SUSTAIN) { 00213 currentState = RELEASE; 00214 } else { 00215 bufferSize = nextBufferSize; 00216 velocity = nextVelocity; 00217 nextBufferSize = -1; 00218 fromDisabled = false; 00219 currentState = FILL; 00220 } 00221 } else if (currentState == RELEASE) { 00222 // Disable the synthesizer. 00223 currentState = OFF; 00224 voiceIndex = -1; 00225 } 00226 } 00227 } 00228 00229 void Synthesizer::checkFillBounds() { 00230 // Check if we have reached the end of the buffer. 00231 if (bufferIndex == bufferSize) { 00232 bufferIndex = 0; 00233 00234 // Check if there are new notes waiting in the queue. 00235 if (nextBufferSize != -1) { 00236 currentState = RELEASE; 00237 } else { 00238 currentState = SUSTAIN; 00239 } 00240 } 00241 }
Generated on Thu Aug 11 2022 16:09:57 by
1.7.2