annotate examples/basic_midi/render.cpp @ 407:5f3d7c23ffa7 prerelease

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