annotate projects/basic_midi/render.cpp @ 224:97faaf985164 mergingClockSync

Added callback for Midi channel messages
author Giulio Moro <giuliomoro@yahoo.it>
date Tue, 08 Mar 2016 15:49:42 +0000
parents b128e3ea84ff
children af1e662400fc
rev   line source
giuliomoro@181 1 /*
giuliomoro@181 2 * render.cpp
giuliomoro@181 3 *
giuliomoro@181 4 * Created on: Oct 24, 2014
giuliomoro@181 5 * Author: parallels
giuliomoro@181 6 */
giuliomoro@181 7
giuliomoro@181 8 #include <BeagleRT.h>
giuliomoro@181 9 #include <Midi.h>
giuliomoro@187 10 #include <Utilities.h>
giuliomoro@181 11 #include <stdlib.h>
giuliomoro@181 12 #include <rtdk.h>
giuliomoro@181 13 #include <cmath>
giuliomoro@181 14
giuliomoro@224 15 float gFreq;
giuliomoro@224 16 float gPhaseIncrement = 0;
giuliomoro@224 17 bool gIsNoteOn = 0;
giuliomoro@224 18 int gVelocity = 0;
giuliomoro@224 19 float gSamplingPeriod = 0;
giuliomoro@224 20
giuliomoro@224 21 void midiMessageCallback(MidiChannelMessage message){
giuliomoro@224 22 message.prettyPrint();
giuliomoro@224 23 if(message.getType() == kmmNoteOn){
giuliomoro@224 24 gFreq = powf(2, (message.getDataByte(0)-69)/12.0f) * 440;
giuliomoro@224 25 gVelocity = message.getDataByte(1);
giuliomoro@224 26 gPhaseIncrement = 2 * M_PI * gFreq * gSamplingPeriod;
giuliomoro@224 27 gIsNoteOn = gVelocity > 0;
giuliomoro@224 28 rt_printf("v0:%f, ph: %6.5f, gVelocity: %d\n", gFreq, gPhaseIncrement, gVelocity);
giuliomoro@224 29 }
giuliomoro@224 30 }
giuliomoro@181 31 // setup() is called once before the audio rendering starts.
giuliomoro@181 32 // Use it to perform any initialisation and allocation which is dependent
giuliomoro@181 33 // on the period size or sample rate.
giuliomoro@181 34 //
giuliomoro@181 35 // userData holds an opaque pointer to a data structure that was passed
giuliomoro@181 36 // in from the call to initAudio().
giuliomoro@181 37 //
giuliomoro@181 38 // Return true on success; returning false halts the program.
giuliomoro@181 39 Midi midi;
giuliomoro@181 40 bool setup(BeagleRTContext *context, void *userData)
giuliomoro@181 41 {
giuliomoro@181 42 midi.readFrom(0);
giuliomoro@191 43 midi.writeTo(0);
giuliomoro@224 44 midi.enableParser(true);
giuliomoro@224 45 midi.setParserCallback(midiMessageCallback);
giuliomoro@181 46 if(context->analogFrames == 0) {
giuliomoro@181 47 rt_printf("Error: this example needs the matrix enabled\n");
giuliomoro@181 48 return false;
giuliomoro@181 49 }
giuliomoro@224 50 gSamplingPeriod = 1/context->audioSampleRate;
giuliomoro@181 51 return true;
giuliomoro@181 52 }
giuliomoro@181 53
giuliomoro@181 54 // render() is called regularly at the highest priority by the audio engine.
giuliomoro@181 55 // Input and output are given from the audio hardware and the other
giuliomoro@181 56 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
giuliomoro@181 57 // will be 0.
giuliomoro@181 58
giuliomoro@181 59
giuliomoro@181 60 enum {kVelocity, kNoteOn, kNoteNumber};
giuliomoro@181 61 void render(BeagleRTContext *context, void *userData)
giuliomoro@181 62 {
giuliomoro@224 63 // one way of getting the midi data is to parse them yourself
giuliomoro@224 64 // (you should set midi.enableParser(false) above):
giuliomoro@224 65 /*
giuliomoro@224 66 static midi_byte_t noteOnStatus = 0x90; //on channel 1
giuliomoro@181 67 static int noteNumber = 0;
giuliomoro@181 68 static int waitingFor = kNoteOn;
giuliomoro@184 69 static int playingNote = -1;
giuliomoro@197 70 int message;
giuliomoro@181 71 while ((message = midi.getInput()) >= 0){
giuliomoro@191 72 rt_printf("%d\n", message);
giuliomoro@181 73 switch(waitingFor){
giuliomoro@181 74 case kNoteOn:
giuliomoro@181 75 if(message == noteOnStatus){
giuliomoro@181 76 waitingFor = kNoteNumber;
giuliomoro@181 77 }
giuliomoro@181 78 break;
giuliomoro@181 79 case kNoteNumber:
giuliomoro@181 80 if((message & (1<<8)) == 0){
giuliomoro@181 81 noteNumber = message;
giuliomoro@181 82 waitingFor = kVelocity;
giuliomoro@181 83 }
giuliomoro@181 84 break;
giuliomoro@181 85 case kVelocity:
giuliomoro@181 86 if((message & (1<<8)) == 0){
giuliomoro@184 87 int _velocity = message;
giuliomoro@181 88 waitingFor = kNoteOn;
giuliomoro@184 89 // "monophonic" behaviour, with priority to the latest note on
giuliomoro@184 90 // i.e.: a note off from a previous note does not stop the current note
giuliomoro@184 91 // still you might end up having a key down and no note being played if you pressed and released another
giuliomoro@184 92 // key in the meantime
giuliomoro@184 93 if(_velocity == 0 && noteNumber == playingNote){
giuliomoro@181 94 noteOn = false;
giuliomoro@184 95 playingNote = -1;
giuliomoro@184 96 velocity = _velocity;
giuliomoro@184 97 } else if (_velocity > 0) {
giuliomoro@184 98 noteOn = true;
giuliomoro@184 99 velocity = _velocity;
giuliomoro@184 100 playingNote = noteNumber;
giuliomoro@184 101 f0 = powf(2, (playingNote-69)/12.0f) * 440;
giuliomoro@184 102 phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate;
giuliomoro@184 103 }
giuliomoro@181 104 rt_printf("NoteOn: %d, NoteNumber: %d, velocity: %d\n", noteOn, noteNumber, velocity);
giuliomoro@181 105 }
giuliomoro@181 106 break;
giuliomoro@181 107 }
giuliomoro@181 108 }
giuliomoro@199 109 */
giuliomoro@224 110 /*
giuliomoro@197 111 int num;
giuliomoro@197 112 //alternatively, you can use the built-in parser (only processes channel messages at the moment).
giuliomoro@197 113 while((num = midi.getParser()->numAvailableMessages()) > 0){
giuliomoro@197 114 static MidiChannelMessage message;
giuliomoro@197 115 message = midi.getParser()->getNextChannelMessage();
giuliomoro@197 116 message.prettyPrint();
giuliomoro@199 117 if(message.getType() == kmmNoteOn){
giuliomoro@199 118 f0 = powf(2, (message.getDataByte(0)-69)/12.0f) * 440;
giuliomoro@199 119 velocity = message.getDataByte(1);
giuliomoro@199 120 phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate;
giuliomoro@199 121 noteOn = velocity > 0;
giuliomoro@224 122 rt_printf("v0:%f, ph: %6.5f, velocity: %d\n", f0, phaseIncrement, gVelocity);
giuliomoro@199 123 }
giuliomoro@197 124 }
giuliomoro@224 125 */
giuliomoro@224 126 // the following block toggles the LED on an Owl pedal
giuliomoro@224 127 // and asks the pedal to return the status of the LED
giuliomoro@224 128 // using MIDI control changes
giuliomoro@191 129 for(unsigned int n = 0; n < context->analogFrames; n++){
giuliomoro@191 130 static int count = 0;
giuliomoro@191 131 static bool state = 0;
giuliomoro@191 132 analogWriteFrameOnce(context, n, 1, state);
giuliomoro@191 133 if(count % 40000 == 0){
giuliomoro@191 134 state = !state;
giuliomoro@224 135 midi_byte_t bytes[6] = {176, 30, (char)(state*127), 176, 67, 30}; // toggle the OWL led and ask for the led status
giuliomoro@191 136 midi.writeOutput(bytes, 6);
giuliomoro@191 137 }
giuliomoro@199 138 count++;
giuliomoro@199 139 }
giuliomoro@199 140 for(unsigned int n = 0; n < context->audioFrames; n++){
giuliomoro@224 141 if(gIsNoteOn == 1){
giuliomoro@181 142 static float phase = 0;
giuliomoro@224 143 phase += gPhaseIncrement;
giuliomoro@181 144 if(phase > 2 * M_PI)
giuliomoro@181 145 phase -= 2 * M_PI;
giuliomoro@224 146 float value = sinf(phase) * gVelocity/128.0f;
giuliomoro@181 147 audioWriteFrame(context, n, 0, value);
giuliomoro@181 148 audioWriteFrame(context, n, 1, value);
giuliomoro@181 149 } else {
giuliomoro@181 150 audioWriteFrame(context, n, 0, 0);
giuliomoro@181 151 audioWriteFrame(context, n, 1, 0);
giuliomoro@181 152 }
giuliomoro@181 153 }
giuliomoro@181 154 }
giuliomoro@181 155
giuliomoro@181 156 // cleanup() is called once at the end, after the audio has stopped.
giuliomoro@181 157 // Release any resources that were allocated in setup().
giuliomoro@181 158
giuliomoro@181 159 void cleanup(BeagleRTContext *context, void *userData)
giuliomoro@181 160 {
giuliomoro@181 161
giuliomoro@181 162 }