changeset 181:391ad036557d

Basic Midi input implementation
author Giulio Moro <giuliomoro@yahoo.it>
date Fri, 15 Jan 2016 21:50:46 +0000
parents 07cfd337ad18
children 4c5acd649d46
files .cproject core/Midi.cpp include/Midi.h projects/basic_midi/render.cpp
diffstat 4 files changed, 271 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/.cproject	Sat Jan 02 13:55:01 2016 +0100
+++ b/.cproject	Fri Jan 15 21:50:46 2016 +0000
@@ -90,20 +90,10 @@
 							</tool>
 						</toolChain>
 					</folderInfo>
-					<folderInfo id="cdt.managedbuild.config.gnu.exe.debug.528876549.2008927038" name="/" resourcePath="projects/basic_passthru">
-						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.debug.1736850748" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.debug" unusedChildren="">
-							<tool id="cdt.managedbuild.tool.gnu.archiver.base.1097917114" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base.1542380883"/>
-							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.1032137455" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.2030825480"/>
-							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.2021994070" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.debug.917207395"/>
-							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.debug.1495645726" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.debug.214461086"/>
-							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.139128145" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.debug.1669966018"/>
-							<tool id="cdt.managedbuild.tool.gnu.assembler.exe.debug.757962791" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.debug.37270610"/>
-						</toolChain>
-					</folderInfo>
 					<sourceEntries>
 						<entry excluding="audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/>
 						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/>
-						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects/logAllAnalogs"/>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects/basic_midi"/>
 						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="source"/>
 					</sourceEntries>
 				</configuration>
@@ -125,7 +115,7 @@
 				</extensions>
 			</storageModule>
 			<storageModule moduleId="cdtBuildSystem" version="4.0.0">
-				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.1521194538" name="Release" parent="cdt.managedbuild.config.gnu.exe.release" postannouncebuildStep="Stopping process on BBB and copying new binary" postbuildStep="ssh root@192.168.7.2 &quot;kill -s 2 \`pidof ${BuildArtifactFileName}\` 2&gt;/dev/null&quot;; scp ${BuildArtifactFilePrefix}${BuildArtifactFileName} root@192.168.7.2:~/beaglert/ ; echo 'done copying' | wall">
+				<configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release,org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.exe.release.1521194538" name="Release" parent="cdt.managedbuild.config.gnu.exe.release" postannouncebuildStep="Stopping process on BBB and copying new binary" postbuildStep="ssh root@192.168.7.2 &quot;kill -s 2 \`pidof ${BuildArtifactFileName}\` 2&gt;/dev/null&quot;; sleep 0.5; scp ${BuildArtifactFilePrefix}${BuildArtifactFileName} root@192.168.7.2:~/beaglert/  &amp;&amp; echo 'done copying' | wall || echo 'error' | wall">
 					<folderInfo id="cdt.managedbuild.config.gnu.exe.release.1521194538." name="/" resourcePath="">
 						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.1612059942" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release">
 							<targetPlatform id="cdt.managedbuild.target.gnu.platform.exe.release.908983575" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.exe.release"/>
@@ -191,20 +181,10 @@
 							</tool>
 						</toolChain>
 					</folderInfo>
-					<folderInfo id="cdt.managedbuild.config.gnu.exe.release.1521194538.842563663" name="/" resourcePath="projects/basic_passthru">
-						<toolChain id="cdt.managedbuild.toolchain.gnu.exe.release.586079455" name="Linux GCC" superClass="cdt.managedbuild.toolchain.gnu.exe.release" unusedChildren="">
-							<tool id="cdt.managedbuild.tool.gnu.archiver.base.909396192" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.base.810674388"/>
-							<tool id="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.426622727" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.163790048"/>
-							<tool id="cdt.managedbuild.tool.gnu.c.compiler.exe.release.967588030" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.exe.release.1302828968"/>
-							<tool id="cdt.managedbuild.tool.gnu.c.linker.exe.release.240084743" name="GCC C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.exe.release.281634187"/>
-							<tool id="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.1381992272" name="GCC C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.exe.release.929570421"/>
-							<tool id="cdt.managedbuild.tool.gnu.assembler.exe.release.2090246626" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.exe.release.2052985276"/>
-						</toolChain>
-					</folderInfo>
 					<sourceEntries>
 						<entry excluding="audio_routines_old.S" flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="core"/>
 						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="include"/>
-						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects/logAllAnalogs"/>
+						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="projects/basic_midi"/>
 						<entry flags="VALUE_WORKSPACE_PATH|RESOLVED" kind="sourcePath" name="source"/>
 					</sourceEntries>
 				</configuration>
@@ -234,12 +214,12 @@
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.528876549;cdt.managedbuild.config.gnu.exe.debug.528876549.;cdt.managedbuild.tool.gnu.c.compiler.exe.debug.917207395;cdt.managedbuild.tool.gnu.c.compiler.input.308014221">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
 		</scannerConfigBuildInfo>
+		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1521194538;cdt.managedbuild.config.gnu.exe.release.1521194538.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.1302828968;cdt.managedbuild.tool.gnu.c.compiler.input.574072828">
+			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
+		</scannerConfigBuildInfo>
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1521194538;cdt.managedbuild.config.gnu.exe.release.1521194538.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.release.163790048;cdt.managedbuild.tool.gnu.cpp.compiler.input.601059736">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
 		</scannerConfigBuildInfo>
-		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.release.1521194538;cdt.managedbuild.config.gnu.exe.release.1521194538.;cdt.managedbuild.tool.gnu.c.compiler.exe.release.1302828968;cdt.managedbuild.tool.gnu.c.compiler.input.574072828">
-			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC"/>
-		</scannerConfigBuildInfo>
 		<scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.exe.debug.528876549;cdt.managedbuild.config.gnu.exe.debug.528876549.;cdt.managedbuild.tool.gnu.cpp.compiler.exe.debug.2030825480;cdt.managedbuild.tool.gnu.cpp.compiler.input.1166892316">
 			<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
 		</scannerConfigBuildInfo>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core/Midi.cpp	Fri Jan 15 21:50:46 2016 +0000
@@ -0,0 +1,92 @@
+/*
+ * Midi.cpp
+ *
+ *  Created on: 15 Jan 2016
+ *      Author: giulio
+ */
+
+#include "Midi.h"
+#include <fcntl.h>
+#include <errno.h>
+
+bool Midi::staticConstructed;
+AuxiliaryTask Midi::midiInputTask;
+AuxiliaryTask Midi::midiOutputTask;
+std::vector<Midi *> Midi::objAddrs(0);
+
+Midi::Midi(){
+	outputPort = -1;
+	inputPort = -1;
+	size_t inputBytesInitialSize = 1000;
+	inputBytes.resize(inputBytesInitialSize);
+	inputBytesWritePointer = 0;
+	inputBytesReadPointer = inputBytes.size() - 1;
+	if(!staticConstructed){
+		staticConstructor();
+	}
+}
+
+void Midi::staticConstructor(){
+	staticConstructed = true;
+	midiInputTask = BeagleRT_createAuxiliaryTask(Midi::midiInputLoop, 50, "MidiInput");
+	midiOutputTask = BeagleRT_createAuxiliaryTask(Midi::midiInputLoop, 50, "MidiOutupt");
+}
+
+Midi::~Midi(){}
+
+void Midi::midiInputLoop(){
+	printf("Midi input loop %d\n", objAddrs.size());
+	for(unsigned int n = 0; n < objAddrs.size(); n++){
+		printf("In the for\n");
+		objAddrs[n] -> readInputLoop();
+	}
+}
+
+void Midi::readInputLoop(){
+	while(!gShouldStop){
+		int maxBytesToRead = inputBytes.size() - inputBytesWritePointer;
+		int ret = read(inputPort, &inputBytes[inputBytesWritePointer], sizeof(midi_byte_t)*maxBytesToRead);
+		static int count = 0;
+		count++;
+		if(ret < 0){
+			if(errno != EAGAIN){ // read() would return EAGAIN when no data are available to read just now
+				rt_printf("Error while reading midi %d\n", errno);
+			}
+			usleep(1000);
+			continue;
+		}
+		inputBytesWritePointer += ret;
+		if(inputBytesWritePointer == inputBytes.size()){ //wrap pointer around
+			inputBytesWritePointer = 0;
+		}
+		if(ret < maxBytesToRead){ //no more data to retrieve at the moment
+			usleep(1000);
+		} // otherwise there might be more data ready to be read, so don't sleep
+	}
+}
+
+int Midi::readFrom(int port){
+	objAddrs.push_back(this);
+	inputPort = open("/dev/midi1", O_RDONLY | O_NONBLOCK | O_NOCTTY);
+	if(inputPort < 0){
+		printf("Error occurred while opening midi port %d: %d", port, inputPort);
+		return -1;
+	} else {
+		printf("Reading from port %d\n", inputPort);
+		BeagleRT_scheduleAuxiliaryTask(midiInputTask);
+		return 1;
+	}
+}
+
+int  Midi::getInput(){
+	if(inputPort < 0)
+		return -2;
+	if(inputBytesReadPointer == inputBytesWritePointer){
+		return -1; // no bytes to read
+	}
+	midi_byte_t inputMessage = inputBytes[inputBytesReadPointer++];
+	if(inputBytesReadPointer == inputBytes.size()){ // wrap pointer
+		inputBytesReadPointer = 0;
+	}
+	return inputMessage;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/Midi.h	Fri Jan 15 21:50:46 2016 +0000
@@ -0,0 +1,72 @@
+/*
+ * Midi.h
+ *
+ *  Created on: 15 Jan 2016
+ *      Author: giulio
+ */
+
+#ifndef MIDI_H_
+#define MIDI_H_
+
+#include <BeagleRT.h>
+#include <vector>
+
+typedef unsigned char midi_byte_t;
+
+class Midi {
+public:
+	Midi();
+	/**
+	 * Open the specified input Midi port and start reading from it.
+	 * @param port Midi port to open
+	 * @return 1 on success, -1 on failure
+	 */
+	int readFrom(int port);
+	/**
+	 * Open the specified output Midi port and prepares to write to it.
+	 * @param port Midi port to open
+	 * @return 1 on success, -1 on failure
+	 */
+	int writeTo(int port);
+
+	/**
+	 * Get received midi byte, one at a time.
+	 * @return  -1 if no new byte is available, -2 on error,
+	 * the oldest not yet retrieved midi byte otherwise
+	*/
+	int getInput();
+
+	/**
+	 * Writes a Midi byte to the output port
+	 * @param byte the Midi byte to write
+	 * @return 1 on success, -1 on error
+	 */
+	int writeOutput(midi_byte_t byte);
+
+	/**
+	 * Writes Midi bytes to the output port
+	 * @param bytes an array of bytes to be written
+	 * @param length number of bytes to write
+	 * @return 1 on success, -1 on error
+	 */
+	int writeMidiOut(short unsigned int* bytes, unsigned int length);
+
+	virtual ~Midi();
+	static void midiInputLoop();
+    static bool staticConstructed;
+	static void staticConstructor();
+private:
+	void readInputLoop();
+	int outputPort;
+	int inputPort;
+	std::vector<midi_byte_t> inputBytes;
+	unsigned int inputBytesWritePointer;
+	unsigned int inputBytesReadPointer;
+	std::vector<midi_byte_t> outputBytes;
+	static std::vector<Midi*> objAddrs;
+	static AuxiliaryTask midiInputTask;
+	static AuxiliaryTask midiOutputTask;
+};
+
+
+#endif /* MIDI_H_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/projects/basic_midi/render.cpp	Fri Jan 15 21:50:46 2016 +0000
@@ -0,0 +1,101 @@
+/*
+ * render.cpp
+ *
+ *  Created on: Oct 24, 2014
+ *      Author: parallels
+ */
+
+
+#include <BeagleRT.h>
+#include <Midi.h>
+#include <stdlib.h>
+#include <Utilities.h>
+#include <rtdk.h>
+#include <cmath>
+
+// 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.
+//
+// userData holds an opaque pointer to a data structure that was passed
+// in from the call to initAudio().
+//
+// Return true on success; returning false halts the program.
+Midi midi;
+bool setup(BeagleRTContext *context, void *userData)
+{
+	midi.readFrom(0);
+	if(context->analogFrames == 0) {
+		rt_printf("Error: this example needs the matrix enabled\n");
+		return false;
+	}
+	return true;
+}
+
+// render() is called regularly at the highest priority by the audio engine.
+// Input and output are given from the audio hardware and the other
+// 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;
+	int message;
+	static bool noteOn = 0;
+	static int velocity = 0;
+	static int noteNumber = 0;
+	static int waitingFor = kNoteOn;
+	while ((message = midi.getInput()) >= 0){
+		switch(waitingFor){
+		case kNoteOn:
+			if(message == noteOnStatus){
+				noteOn = true;
+				waitingFor = kNoteNumber;
+			}
+			break;
+		case kNoteNumber:
+			if((message & (1<<8)) == 0){
+				noteNumber = message;
+				waitingFor = kVelocity;
+				f0 = powf(2, (noteNumber-69)/12.0f) * 440;
+				phaseIncrement = 2 * M_PI * f0 / context->audioSampleRate;
+			}
+			break;
+		case kVelocity:
+			if((message & (1<<8)) == 0){
+				velocity = message;
+				waitingFor = kNoteOn;
+				if(velocity == 0)
+					noteOn = false;
+				rt_printf("NoteOn: %d, NoteNumber: %d, velocity: %d\n", noteOn, noteNumber, velocity);
+			}
+			break;
+		}
+	}
+	for(unsigned int n = 0; n < context->audioFrames; n++){
+		if(noteOn == 1){
+			static float phase = 0;
+			phase += phaseIncrement;
+			if(phase > 2 * M_PI)
+				phase -= 2 * M_PI;
+			float value = sinf(phase) * velocity/128.0f;
+			audioWriteFrame(context, n, 0, value);
+			audioWriteFrame(context, n, 1, value);
+		} else {
+			audioWriteFrame(context, n, 0, 0);
+			audioWriteFrame(context, n, 1, 0);
+		}
+	}
+}
+
+// cleanup() is called once at the end, after the audio has stopped.
+// Release any resources that were allocated in setup().
+
+void cleanup(BeagleRTContext *context, void *userData)
+{
+
+}