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