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

Dependencies:   mbed USBDevice PinDetect

Committer:
asuszek
Date:
Wed Apr 13 19:46:28 2016 +0000
Revision:
9:1e012f67470c
Parent:
AudioEngine.cpp@6:688698f814c0
Child:
13:bb0ec927e458
Moved Audio into it's own folder

Who changed what in which revision?

UserRevisionLine numberNew contents of line
asuszek 6:688698f814c0 1 /*
asuszek 6:688698f814c0 2 * The interface for all audio input and output.
asuszek 6:688698f814c0 3 * This class acts as a container for individual voices.
asuszek 6:688698f814c0 4 * It takes in MIDI events and handles processing and output.
asuszek 6:688698f814c0 5 *
asuszek 6:688698f814c0 6 * @author Austin Suszek
asuszek 6:688698f814c0 7 */
asuszek 6:688698f814c0 8
asuszek 6:688698f814c0 9 #include "AudioEngine.h"
asuszek 6:688698f814c0 10
asuszek 6:688698f814c0 11 #if USE_PWM
asuszek 6:688698f814c0 12 PwmOut audioOut(p21);
asuszek 6:688698f814c0 13 #else
asuszek 6:688698f814c0 14 AnalogOut audioOut(p18);
asuszek 6:688698f814c0 15 #endif
asuszek 6:688698f814c0 16
asuszek 6:688698f814c0 17 AudioEngine::AudioEngine() {
asuszek 6:688698f814c0 18 // Initialize the synthesizers.
asuszek 6:688698f814c0 19 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 20 synthesizers[i] = Synthesizer();
asuszek 6:688698f814c0 21 }
asuszek 6:688698f814c0 22
asuszek 6:688698f814c0 23 #if USE_PWM
asuszek 6:688698f814c0 24 audioOut.period(1.0/200000.0);
asuszek 6:688698f814c0 25 #endif
asuszek 6:688698f814c0 26
asuszek 6:688698f814c0 27 // Set up the sampler.
asuszek 6:688698f814c0 28 samplePeriod.attach(this, &AudioEngine::outputAudio, 1.0 / float(C::SAMPLE_RATE));
asuszek 6:688698f814c0 29 }
asuszek 6:688698f814c0 30
asuszek 6:688698f814c0 31 void AudioEngine::midiNoteOn(const int key, const int velocity) {
asuszek 6:688698f814c0 32 // Find the firt disabled voice or the one that has been playing longest.
asuszek 6:688698f814c0 33 int64_t min = synthesizers[0].getVoiceIndex();
asuszek 6:688698f814c0 34 int minIndex = 0;
asuszek 6:688698f814c0 35 for (int i = 1; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 36 int64_t voiceIndex = synthesizers[i].getVoiceIndex();
asuszek 6:688698f814c0 37 if (voiceIndex < min) {
asuszek 6:688698f814c0 38 min = voiceIndex;
asuszek 6:688698f814c0 39 minIndex = i;
asuszek 6:688698f814c0 40 }
asuszek 6:688698f814c0 41 }
asuszek 6:688698f814c0 42
asuszek 6:688698f814c0 43 // Send the note to the minimum voice.
asuszek 6:688698f814c0 44 synthesizers[minIndex].midiNoteOn(key, velocity);
asuszek 6:688698f814c0 45 }
asuszek 6:688698f814c0 46
asuszek 6:688698f814c0 47 void AudioEngine::midiNoteOff(const int key) {
asuszek 6:688698f814c0 48 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 49 if (synthesizers[i].isPlaying() && synthesizers[i].getCurrentKey() == key) {
asuszek 6:688698f814c0 50 synthesizers[i].midiNoteOff();
asuszek 6:688698f814c0 51 break;
asuszek 6:688698f814c0 52 }
asuszek 6:688698f814c0 53 }
asuszek 6:688698f814c0 54 }
asuszek 6:688698f814c0 55
asuszek 6:688698f814c0 56 void AudioEngine::nextSynth(int direction) {
asuszek 6:688698f814c0 57 // Hand the command down to the synthesizers.
asuszek 6:688698f814c0 58 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 59 synthesizers[i].nextSynth(direction);
asuszek 6:688698f814c0 60 }
asuszek 6:688698f814c0 61 }
asuszek 6:688698f814c0 62
asuszek 6:688698f814c0 63 void AudioEngine::outputAudio() {
asuszek 6:688698f814c0 64 float output = 0.0;
asuszek 6:688698f814c0 65
asuszek 6:688698f814c0 66 // Poll all of the synthesizers.
asuszek 6:688698f814c0 67 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 68 if (synthesizers[i].isPlaying()) {
asuszek 6:688698f814c0 69 output += synthesizers[i].getSample();
asuszek 6:688698f814c0 70 }
asuszek 6:688698f814c0 71 }
asuszek 6:688698f814c0 72
asuszek 6:688698f814c0 73 // Scale the output by the number of voices.
asuszek 6:688698f814c0 74 output /= float(C::MAX_POLYPHONY);
asuszek 6:688698f814c0 75 // Check that we do not clip.
asuszek 6:688698f814c0 76 if (output > 1.0) {
asuszek 6:688698f814c0 77 output = 1.0;
asuszek 6:688698f814c0 78 }
asuszek 6:688698f814c0 79 if (output < -1.0) {
asuszek 6:688698f814c0 80 output = -1.0;
asuszek 6:688698f814c0 81 }
asuszek 6:688698f814c0 82 // Map [-1, 1] range to [0, 1] range.
asuszek 6:688698f814c0 83 audioOut = (output + 1.0) / 2.0;
asuszek 6:688698f814c0 84
asuszek 6:688698f814c0 85 // Go back and process the next sample on all voices.
asuszek 6:688698f814c0 86 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 87 if (synthesizers[i].isPlaying()) {
asuszek 6:688698f814c0 88 synthesizers[i].processBuffer();
asuszek 6:688698f814c0 89 }
asuszek 6:688698f814c0 90 }
asuszek 6:688698f814c0 91 }