comparison examples/05-Communication/basic-midi/render.cpp @ 464:8fcfbfb32aa0 prerelease

Examples reorder with subdirectories. Added header to each project. Moved Doxygen to bottom of render.cpp.
author Robert Jack <robert.h.jack@gmail.com>
date Mon, 20 Jun 2016 16:20:38 +0100
parents
children 8f8809c77dda
comparison
equal deleted inserted replaced
463:c47709e8b5c9 464:8fcfbfb32aa0
1 /*
2 ____ _____ _ _
3 | __ )| ____| | / \
4 | _ \| _| | | / _ \
5 | |_) | |___| |___ / ___ \
6 |____/|_____|_____/_/ \_\
7
8 The platform for ultra-low latency audio and sensor processing
9
10 http://bela.io
11
12 A project of the Augmented Instruments Laboratory within the
13 Centre for Digital Music at Queen Mary University of London.
14 http://www.eecs.qmul.ac.uk/~andrewm
15
16 (c) 2016 Augmented Instruments Laboratory: Andrew McPherson,
17 Astrid Bin, Liam Donovan, Christian Heinrichs, Robert Jack,
18 Giulio Moro, Laurel Pardue, Victor Zappi. All rights reserved.
19
20 The Bela software is distributed under the GNU Lesser General Public License
21 (LGPL 3.0), available here: https://www.gnu.org/licenses/lgpl-3.0.txt
22 */
23
24
25 #include <Bela.h>
26 #include <Midi.h>
27 #include <stdlib.h>
28 #include <rtdk.h>
29 #include <cmath>
30
31 float gFreq;
32 float gPhaseIncrement = 0;
33 bool gIsNoteOn = 0;
34 int gVelocity = 0;
35 float gSamplingPeriod = 0;
36
37 void midiMessageCallback(MidiChannelMessage message, void* arg){
38 if(arg != NULL){
39 rt_printf("Message from midi port %d: ", *(int*)arg);
40 }
41 message.prettyPrint();
42 if(message.getType() == kmmNoteOn){
43 gFreq = powf(2, (message.getDataByte(0)-69)/12.0f) * 440;
44 gVelocity = message.getDataByte(1);
45 gPhaseIncrement = 2 * M_PI * gFreq * gSamplingPeriod;
46 gIsNoteOn = gVelocity > 0;
47 rt_printf("v0:%f, ph: %6.5f, gVelocity: %d\n", gFreq, gPhaseIncrement, gVelocity);
48 }
49 }
50 // setup() is called once before the audio rendering starts.
51 // Use it to perform any initialisation and allocation which is dependent
52 // on the period size or sample rate.
53 //
54 // userData holds an opaque pointer to a data structure that was passed
55 // in from the call to initAudio().
56 //
57 // Return true on success; returning false halts the program.
58 Midi midi;
59 int gMidiPort0 = 0;
60 bool setup(BelaContext *context, void *userData)
61 {
62 midi.readFrom(gMidiPort0);
63 midi.writeTo(gMidiPort0);
64 midi.enableParser(true);
65 midi.setParserCallback(midiMessageCallback, &gMidiPort0);
66 if(context->analogFrames == 0) {
67 rt_printf("Error: this example needs the analog I/O to be enabled\n");
68 return false;
69 }
70 gSamplingPeriod = 1/context->audioSampleRate;
71 return true;
72 }
73
74 // render() is called regularly at the highest priority by the audio engine.
75 // Input and output are given from the audio hardware and the other
76 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
77 // will be 0.
78
79
80 enum {kVelocity, kNoteOn, kNoteNumber};
81 void render(BelaContext *context, void *userData)
82 {
83 // one way of getting the midi data is to parse them yourself
84 // (you should set midi.enableParser(false) above):
85 /*
86 static midi_byte_t noteOnStatus = 0x90; //on channel 1
87 static int noteNumber = 0;
88 static int waitingFor = kNoteOn;
89 static int playingNote = -1;
90 int message;
91 while ((message = midi.getInput()) >= 0){
92 rt_printf("%d\n", message);
93 switch(waitingFor){
94 case kNoteOn:
95 if(message == noteOnStatus){
96 waitingFor = kNoteNumber;
97 }
98 break;
99 case kNoteNumber:
100 if((message & (1<<8)) == 0){
101 noteNumber = message;
102 waitingFor = kVelocity;
103 }
104 break;
105 case kVelocity:
106 if((message & (1<<8)) == 0){
107 int _velocity = message;
108 waitingFor = kNoteOn;
109 // "monophonic" behaviour, with priority to the latest note on
110 // i.e.: a note off from a previous note does not stop the current note
111 // still you might end up having a key down and no note being played if you pressed and released another
112 // key in the meantime
113 if(_velocity == 0 && noteNumber == playingNote){
114 noteOn = false;
115 playingNote = -1;
116 velocity = _velocity;
117 } else if (_velocity > 0) {
118 noteOn = true;
119 velocity = _velocity;
120 playingNote = noteNumber;
121 f0 = powf(2, (playingNote-69)/12.0f) * 440;
122 phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate;
123 }
124 rt_printf("NoteOn: %d, NoteNumber: %d, velocity: %d\n", noteOn, noteNumber, velocity);
125 }
126 break;
127 }
128 }
129 */
130 /*
131 int num;
132 //alternatively, you can use the built-in parser (only processes channel messages at the moment).
133 while((num = midi.getParser()->numAvailableMessages()) > 0){
134 static MidiChannelMessage message;
135 message = midi.getParser()->getNextChannelMessage();
136 message.prettyPrint();
137 if(message.getType() == kmmNoteOn){
138 f0 = powf(2, (message.getDataByte(0)-69)/12.0f) * 440;
139 velocity = message.getDataByte(1);
140 phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate;
141 noteOn = velocity > 0;
142 rt_printf("v0:%f, ph: %6.5f, velocity: %d\n", f0, phaseIncrement, gVelocity);
143 }
144 }
145 */
146 // the following block toggles the LED on an Owl pedal
147 // and asks the pedal to return the status of the LED
148 // using MIDI control changes
149 for(unsigned int n = 0; n < context->analogFrames; n++){
150 static int count = 0;
151 static bool state = 0;
152 analogWriteOnce(context, n, 1, state);
153 if(count % 40000 == 0){
154 state = !state;
155 midi_byte_t bytes[6] = {176, 30, (char)(state*127), 176, 67, 30}; // toggle the OWL led and ask for the led status
156 midi.writeOutput(bytes, 6);
157 }
158 count++;
159 }
160 for(unsigned int n = 0; n < context->audioFrames; n++){
161 if(gIsNoteOn == 1){
162 static float phase = 0;
163 phase += gPhaseIncrement;
164 if(phase > 2 * M_PI)
165 phase -= 2 * M_PI;
166 float value = sinf(phase) * gVelocity/128.0f;
167 audioWrite(context, n, 0, value);
168 audioWrite(context, n, 1, value);
169 } else {
170 audioWrite(context, n, 0, 0);
171 audioWrite(context, n, 1, 0);
172 }
173 }
174 }
175
176 // cleanup() is called once at the end, after the audio has stopped.
177 // Release any resources that were allocated in setup().
178
179 void cleanup(BelaContext *context, void *userData)
180 {
181
182 }