changeset 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 ec9425f728bc
children 444f6028d6b1
files core/Midi.cpp include/Midi.h projects/basic_midi/render.cpp
diffstat 3 files changed, 64 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
--- a/core/Midi.cpp	Mon Feb 22 11:28:21 2016 +0000
+++ b/core/Midi.cpp	Tue Mar 08 15:49:42 2016 +0000
@@ -58,6 +58,11 @@
 			messages[writePointer].setDataByte(elapsedDataBytes, input[n]);
 			elapsedDataBytes++;
 			if(elapsedDataBytes == messages[writePointer].getNumDataBytes()){
+				// done with the current message
+				// call the callback if available
+				if(isCallbackEnabled() == true){
+					messageReadyCallback(getNextChannelMessage());
+				}
 				waitingForStatus = true;
 				writePointer++;
 				if(writePointer == messages.size()){
@@ -66,6 +71,7 @@
 			}
 		}
 	}
+
 	return consumedBytes;
 };
 
@@ -104,14 +110,12 @@
 }
 
 void Midi::midiInputLoop(){
-	printf("Midi input loop %d\n", objAddrs[kMidiInput].size());
 	for(unsigned int n = 0; n < objAddrs[kMidiInput].size(); n++){
 		objAddrs[kMidiInput][n] -> readInputLoop();
 	}
 }
 
 void Midi::midiOutputLoop(){
-	printf("Midi output loop %d\n", objAddrs[kMidiOutput].size());
 	for(unsigned int n = 0; n < objAddrs[kMidiOutput].size(); n++){
 		objAddrs[kMidiOutput][n] -> writeOutputLoop();
 	}
@@ -132,6 +136,7 @@
 		if(inputBytesWritePointer == inputBytes.size()){ //wrap pointer around
 			inputBytesWritePointer = 0;
 		}
+
 		if(parserEnabled == true && ret > 0){ // if the parser is enabled and there is new data, send the data to it
 			int input;
 			while((input=_getInput()) >= 0){
--- a/include/Midi.h	Mon Feb 22 11:28:21 2016 +0000
+++ b/include/Midi.h	Tue Mar 08 15:49:42 2016 +0000
@@ -115,6 +115,8 @@
 	unsigned int readPointer;
 	unsigned int elapsedDataBytes;
 	bool waitingForStatus;
+	void (*messageReadyCallback)(MidiChannelMessage);
+	bool callbackEnabled;
 public:
 	MidiParser(){
 		waitingForStatus = true;
@@ -122,6 +124,8 @@
 		messages.resize(100); // 100 is the number of messages that can be buffered
 		writePointer = 0;
 		readPointer = 0;
+		callbackEnabled = false;
+		messageReadyCallback = NULL;
 	}
 
 	/**
@@ -133,14 +137,25 @@
 	 * @return the number of bytes parsed
 	 */
 	int parse(midi_byte_t* input, unsigned int length);
-	int callme(){
-		return readPointer;
+
+	void setCallback(void (*newCallback)(MidiChannelMessage)){
+		messageReadyCallback = newCallback;
+		if(newCallback != NULL){
+			callbackEnabled = true;
+		} else {
+			callbackEnabled = false;
+		}
 	};
+
+	bool isCallbackEnabled(){
+		return callbackEnabled;
+	};
+
 	int numAvailableMessages(){
 		int num = (writePointer - readPointer + messages.size() ) % messages.size();
 		if(num > 0){
 			int a = a +1;
-			a = callme();
+			a = readPointer;
 		}
 		return num;
 	}
@@ -202,6 +217,12 @@
 	 */
 	MidiParser* getParser();
 
+	void setParserCallback(void (*callback)(MidiChannelMessage)){
+		// if callback is not NULL, also enable the parser
+		enableParser(callback != NULL); //this needs to be first, as it deletes the parser(if exists)
+		getParser()->setCallback(callback);
+	}
+
 	/**
 	 * Open the specified input Midi port and start reading from it.
 	 * @param port Midi port to open
--- a/projects/basic_midi/render.cpp	Mon Feb 22 11:28:21 2016 +0000
+++ b/projects/basic_midi/render.cpp	Tue Mar 08 15:49:42 2016 +0000
@@ -12,6 +12,22 @@
 #include <rtdk.h>
 #include <cmath>
 
+float gFreq;
+float gPhaseIncrement = 0;
+bool gIsNoteOn = 0;
+int gVelocity = 0;
+float gSamplingPeriod = 0;
+
+void midiMessageCallback(MidiChannelMessage message){
+	message.prettyPrint();
+	if(message.getType() == kmmNoteOn){
+		gFreq = powf(2, (message.getDataByte(0)-69)/12.0f) * 440;
+		gVelocity = message.getDataByte(1);
+		gPhaseIncrement = 2 * M_PI * gFreq * gSamplingPeriod;
+		gIsNoteOn = gVelocity > 0;
+		rt_printf("v0:%f, ph: %6.5f, gVelocity: %d\n", gFreq, gPhaseIncrement, gVelocity);
+	}
+}
 // setup() is called once before the audio rendering starts.
 // Use it to perform any initialisation and allocation which is dependent
 // on the period size or sample rate.
@@ -25,11 +41,13 @@
 {
 	midi.readFrom(0);
 	midi.writeTo(0);
-//	midi.enableParser(true);
+	midi.enableParser(true);
+	midi.setParserCallback(midiMessageCallback);
 	if(context->analogFrames == 0) {
 		rt_printf("Error: this example needs the matrix enabled\n");
 		return false;
 	}
+	gSamplingPeriod = 1/context->audioSampleRate;
 	return true;
 }
 
@@ -38,21 +56,18 @@
 // ADCs and DACs (if available). If only audio is available, numMatrixFrames
 // will be 0.
 
-static midi_byte_t noteOnStatus = 0x90; //on channel 1
 
 enum {kVelocity, kNoteOn, kNoteNumber};
 void render(BeagleRTContext *context, void *userData)
 {
-	static float f0;
-	static float phaseIncrement = 0;
-	static bool noteOn = 0;
-	static int velocity = 0;
+// one way of getting the midi data is to parse them yourself
+//	(you should set midi.enableParser(false) above):
+/*
+	static midi_byte_t noteOnStatus = 0x90; //on channel 1
 	static int noteNumber = 0;
 	static int waitingFor = kNoteOn;
 	static int playingNote = -1;
-/*
 	int message;
-	// one way of getting the midi data is to parse them yourself (you should set midi.enableParser(false) above):
 	while ((message = midi.getInput()) >= 0){
 		rt_printf("%d\n", message);
 		switch(waitingFor){
@@ -92,6 +107,7 @@
 		}
 	}
 */
+	/*
 	int num;
 	//alternatively, you can use the built-in parser (only processes channel messages at the moment).
 	while((num = midi.getParser()->numAvailableMessages()) > 0){
@@ -103,28 +119,31 @@
 			velocity = message.getDataByte(1);
 			phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate;
 			noteOn = velocity > 0;
-			rt_printf("v0:%f, ph: %6.5f, velocity: %d\n", f0, phaseIncrement, velocity);
+			rt_printf("v0:%f, ph: %6.5f, velocity: %d\n", f0, phaseIncrement, gVelocity);
 		}
 	}
-
+	 */
+	// the following block toggles the LED on an Owl pedal
+	// and asks the pedal to return the status of the LED
+	// using MIDI control changes
 	for(unsigned int n = 0; n < context->analogFrames; n++){
 		static int count = 0;
 		static bool state = 0;
 		analogWriteFrameOnce(context, n, 1, state);
 		if(count % 40000 == 0){
 			state = !state;
-			midi_byte_t bytes[6] = {176, 30, state*127, 176, 67, 30}; // toggle the OWL led and ask for the led status
+			midi_byte_t bytes[6] = {176, 30, (char)(state*127), 176, 67, 30}; // toggle the OWL led and ask for the led status
 			midi.writeOutput(bytes, 6);
 		}
 		count++;
 	}
 	for(unsigned int n = 0; n < context->audioFrames; n++){
-		if(noteOn == 1){
+		if(gIsNoteOn == 1){
 			static float phase = 0;
-			phase += phaseIncrement;
+			phase += gPhaseIncrement;
 			if(phase > 2 * M_PI)
 				phase -= 2 * M_PI;
-			float value = sinf(phase) * velocity/128.0f;
+			float value = sinf(phase) * gVelocity/128.0f;
 			audioWriteFrame(context, n, 0, value);
 			audioWriteFrame(context, n, 1, value);
 		} else {