Dependencies:   mbed USBDevice PinDetect

Audio/KarplusStrong.cpp

Committer:
asuszek
Date:
2016-04-17
Revision:
13:bb0ec927e458
Child:
15:aa5a4c350251

File content as of revision 13:bb0ec927e458:


#include "KarplusStrong.h"

static float noiseSeed[(C::SAMPLE_RATE / C::MIN_FREQUENCY) + 1];

KarplusStrong::KarplusStrong() {
    initializeNoiseSeed();
    
    // These values will be overwritten under normal control flow, but give them values in case of runtime errors.
    lastOutput = 0.0;
    filterCoefficient = 0.6;
    nextFilterCoefficient = filterCoefficient;
}

void KarplusStrong::midiNoteOn(int key, float velocity) {
    // Save the velocity for later.
    this->velocity = velocity;
    
    // Calculate the smoothing filter coefficient for this note.
    float noteIndex = float(key - 24) / 52.0; // normalize the lower two octaves.
    // Clip to 1.0
    if (noteIndex > 1.0) {
        noteIndex = 1.0;
    }
    
    nextFilterCoefficient = C::STRING_DAMPING // Initial damping.
            + 0.5 * (1.0 - C::STRING_DAMPING) * sqrt(noteIndex) // Keyboard tracking
            + C::STRING_DAMPING_VARIATION * (1.0 - C::STRING_DAMPING) * getRand(); // Random variation
}

float KarplusStrong::fillBuffer(const int bufferIndex) {
    // Copy over the calculated filter coefficient.
    filterCoefficient = nextFilterCoefficient;
    
    // Get the noise sample from the static noise seed.
    lastOutput = noiseSeed[bufferIndex] * velocity;
    return lastOutput;
}

float KarplusStrong::processBuffer(const float inputSample) {
    // Put the sample from the last period through the lowpass filter.
    lastOutput = lowpassFilter(lastOutput, inputSample, filterCoefficient);
    return lastOutput;
}

void KarplusStrong::initializeNoiseSeed() {
    // Initialize the random function with a static seed.
    srand(time(NULL));

    int seedLength = (C::SAMPLE_RATE / C::MIN_FREQUENCY) + 1;
    for (int i = 0; i < seedLength; i++) {
        // Create a random number in [-1.0, 1.0]
        noiseSeed[i] = 1.0 - 2.0 * getRand();   
    } 
}

float KarplusStrong::lowpassFilter(const float output, const float input, const float smoothingFactor) {
    // Simple single pole recursive IIR lowpass filter.
    return input * smoothingFactor + output * (1.0 - smoothingFactor);   
}