Dependencies:   mbed USBDevice PinDetect

Committer:
asuszek
Date:
Sun Apr 17 21:35:23 2016 +0000
Revision:
13:bb0ec927e458
Child:
15:aa5a4c350251
Implemented basic Karplus Strong. The sample rate had to be halved in order to process the algorithm for each sample without crashing.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
asuszek 13:bb0ec927e458 1
asuszek 13:bb0ec927e458 2 #include "KarplusStrong.h"
asuszek 13:bb0ec927e458 3
asuszek 13:bb0ec927e458 4 static float noiseSeed[(C::SAMPLE_RATE / C::MIN_FREQUENCY) + 1];
asuszek 13:bb0ec927e458 5
asuszek 13:bb0ec927e458 6 KarplusStrong::KarplusStrong() {
asuszek 13:bb0ec927e458 7 initializeNoiseSeed();
asuszek 13:bb0ec927e458 8
asuszek 13:bb0ec927e458 9 // These values will be overwritten under normal control flow, but give them values in case of runtime errors.
asuszek 13:bb0ec927e458 10 lastOutput = 0.0;
asuszek 13:bb0ec927e458 11 filterCoefficient = 0.6;
asuszek 13:bb0ec927e458 12 nextFilterCoefficient = filterCoefficient;
asuszek 13:bb0ec927e458 13 }
asuszek 13:bb0ec927e458 14
asuszek 13:bb0ec927e458 15 void KarplusStrong::midiNoteOn(int key, float velocity) {
asuszek 13:bb0ec927e458 16 // Save the velocity for later.
asuszek 13:bb0ec927e458 17 this->velocity = velocity;
asuszek 13:bb0ec927e458 18
asuszek 13:bb0ec927e458 19 // Calculate the smoothing filter coefficient for this note.
asuszek 13:bb0ec927e458 20 float noteIndex = float(key - 24) / 52.0; // normalize the lower two octaves.
asuszek 13:bb0ec927e458 21 // Clip to 1.0
asuszek 13:bb0ec927e458 22 if (noteIndex > 1.0) {
asuszek 13:bb0ec927e458 23 noteIndex = 1.0;
asuszek 13:bb0ec927e458 24 }
asuszek 13:bb0ec927e458 25
asuszek 13:bb0ec927e458 26 nextFilterCoefficient = C::STRING_DAMPING // Initial damping.
asuszek 13:bb0ec927e458 27 + 0.5 * (1.0 - C::STRING_DAMPING) * sqrt(noteIndex) // Keyboard tracking
asuszek 13:bb0ec927e458 28 + C::STRING_DAMPING_VARIATION * (1.0 - C::STRING_DAMPING) * getRand(); // Random variation
asuszek 13:bb0ec927e458 29 }
asuszek 13:bb0ec927e458 30
asuszek 13:bb0ec927e458 31 float KarplusStrong::fillBuffer(const int bufferIndex) {
asuszek 13:bb0ec927e458 32 // Copy over the calculated filter coefficient.
asuszek 13:bb0ec927e458 33 filterCoefficient = nextFilterCoefficient;
asuszek 13:bb0ec927e458 34
asuszek 13:bb0ec927e458 35 // Get the noise sample from the static noise seed.
asuszek 13:bb0ec927e458 36 lastOutput = noiseSeed[bufferIndex] * velocity;
asuszek 13:bb0ec927e458 37 return lastOutput;
asuszek 13:bb0ec927e458 38 }
asuszek 13:bb0ec927e458 39
asuszek 13:bb0ec927e458 40 float KarplusStrong::processBuffer(const float inputSample) {
asuszek 13:bb0ec927e458 41 // Put the sample from the last period through the lowpass filter.
asuszek 13:bb0ec927e458 42 lastOutput = lowpassFilter(lastOutput, inputSample, filterCoefficient);
asuszek 13:bb0ec927e458 43 return lastOutput;
asuszek 13:bb0ec927e458 44 }
asuszek 13:bb0ec927e458 45
asuszek 13:bb0ec927e458 46 void KarplusStrong::initializeNoiseSeed() {
asuszek 13:bb0ec927e458 47 // Initialize the random function with a static seed.
asuszek 13:bb0ec927e458 48 srand(time(NULL));
asuszek 13:bb0ec927e458 49
asuszek 13:bb0ec927e458 50 int seedLength = (C::SAMPLE_RATE / C::MIN_FREQUENCY) + 1;
asuszek 13:bb0ec927e458 51 for (int i = 0; i < seedLength; i++) {
asuszek 13:bb0ec927e458 52 // Create a random number in [-1.0, 1.0]
asuszek 13:bb0ec927e458 53 noiseSeed[i] = 1.0 - 2.0 * getRand();
asuszek 13:bb0ec927e458 54 }
asuszek 13:bb0ec927e458 55 }
asuszek 13:bb0ec927e458 56
asuszek 13:bb0ec927e458 57 float KarplusStrong::lowpassFilter(const float output, const float input, const float smoothingFactor) {
asuszek 13:bb0ec927e458 58 // Simple single pole recursive IIR lowpass filter.
asuszek 13:bb0ec927e458 59 return input * smoothingFactor + output * (1.0 - smoothingFactor);
asuszek 13:bb0ec927e458 60 }