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

Dependencies:   mbed USBDevice PinDetect

Committer:
asuszek
Date:
Mon Apr 25 23:58:15 2016 +0000
Revision:
22:b800e1766647
Parent:
18:26d93c5b9bb6
Fixed LED bug

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 13:bb0ec927e458 23 outputSample = 0.0;
asuszek 13:bb0ec927e458 24
asuszek 6:688698f814c0 25 #if USE_PWM
asuszek 6:688698f814c0 26 audioOut.period(1.0/200000.0);
asuszek 6:688698f814c0 27 #endif
asuszek 6:688698f814c0 28
asuszek 6:688698f814c0 29 // Set up the sampler.
asuszek 6:688698f814c0 30 samplePeriod.attach(this, &AudioEngine::outputAudio, 1.0 / float(C::SAMPLE_RATE));
asuszek 6:688698f814c0 31 }
asuszek 6:688698f814c0 32
asuszek 6:688698f814c0 33 void AudioEngine::midiNoteOn(const int key, const int velocity) {
asuszek 6:688698f814c0 34 // Find the firt disabled voice or the one that has been playing longest.
asuszek 6:688698f814c0 35 int64_t min = synthesizers[0].getVoiceIndex();
asuszek 6:688698f814c0 36 int minIndex = 0;
asuszek 6:688698f814c0 37 for (int i = 1; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 38 int64_t voiceIndex = synthesizers[i].getVoiceIndex();
asuszek 6:688698f814c0 39 if (voiceIndex < min) {
asuszek 6:688698f814c0 40 min = voiceIndex;
asuszek 6:688698f814c0 41 minIndex = i;
asuszek 6:688698f814c0 42 }
asuszek 6:688698f814c0 43 }
asuszek 6:688698f814c0 44
asuszek 6:688698f814c0 45 // Send the note to the minimum voice.
asuszek 6:688698f814c0 46 synthesizers[minIndex].midiNoteOn(key, velocity);
asuszek 6:688698f814c0 47 }
asuszek 6:688698f814c0 48
asuszek 6:688698f814c0 49 void AudioEngine::midiNoteOff(const int key) {
asuszek 6:688698f814c0 50 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 51 if (synthesizers[i].isPlaying() && synthesizers[i].getCurrentKey() == key) {
asuszek 6:688698f814c0 52 synthesizers[i].midiNoteOff();
asuszek 6:688698f814c0 53 break;
asuszek 6:688698f814c0 54 }
asuszek 6:688698f814c0 55 }
asuszek 6:688698f814c0 56 }
asuszek 6:688698f814c0 57
asuszek 18:26d93c5b9bb6 58 int AudioEngine::nextSynth(int direction) {
asuszek 18:26d93c5b9bb6 59 int nextIndex;
asuszek 6:688698f814c0 60 // Hand the command down to the synthesizers.
asuszek 6:688698f814c0 61 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 18:26d93c5b9bb6 62 nextIndex = synthesizers[i].nextSynth(direction);
asuszek 6:688698f814c0 63 }
asuszek 18:26d93c5b9bb6 64 return nextIndex;
asuszek 6:688698f814c0 65 }
asuszek 6:688698f814c0 66
asuszek 6:688698f814c0 67 void AudioEngine::outputAudio() {
asuszek 13:bb0ec927e458 68 // The first thing we do is output the last calculated sample.
asuszek 13:bb0ec927e458 69 // Map [-1, 1] range to [0, 1] range.
asuszek 13:bb0ec927e458 70 audioOut = (outputSample + 1.0) / 2.0;
asuszek 13:bb0ec927e458 71
asuszek 13:bb0ec927e458 72 // Now reset output and calculate the next sample.
asuszek 13:bb0ec927e458 73 outputSample = 0.0;
asuszek 6:688698f814c0 74
asuszek 6:688698f814c0 75 // Poll all of the synthesizers.
asuszek 6:688698f814c0 76 for (int i = 0; i < C::MAX_POLYPHONY; i++) {
asuszek 6:688698f814c0 77 if (synthesizers[i].isPlaying()) {
asuszek 13:bb0ec927e458 78 // Get the next sample.
asuszek 13:bb0ec927e458 79 outputSample += synthesizers[i].getSample();
asuszek 6:688698f814c0 80 }
asuszek 6:688698f814c0 81 }
asuszek 6:688698f814c0 82
asuszek 6:688698f814c0 83 // Scale the output by the number of voices.
asuszek 13:bb0ec927e458 84 outputSample /= float(C::MAX_POLYPHONY);
asuszek 6:688698f814c0 85 // Check that we do not clip.
asuszek 13:bb0ec927e458 86 if (outputSample > 1.0) {
asuszek 13:bb0ec927e458 87 outputSample = 1.0;
asuszek 6:688698f814c0 88 }
asuszek 13:bb0ec927e458 89 if (outputSample < -1.0) {
asuszek 13:bb0ec927e458 90 outputSample = -1.0;
asuszek 6:688698f814c0 91 }
asuszek 6:688698f814c0 92 }