Browse Source

added class MidiIn;
added classes for various types of midi messages

Fabian Peter Hammerle 11 years ago
parent
commit
0eb922a754
6 changed files with 242 additions and 0 deletions
  1. 18 0
      Midi.cpp
  2. 19 0
      Midi.h
  3. 92 0
      MidiMessage.cpp
  4. 97 0
      MidiMessage.h
  5. 4 0
      msw/rtmidilib.vcxproj
  6. 12 0
      msw/rtmidilib.vcxproj.filters

+ 18 - 0
Midi.cpp

@@ -0,0 +1,18 @@
+#include "Midi.h"
+
+void MidiIn :: setCallback( MidiIn::MidiMessageInCallback callback, void *userData )
+{
+	userCallback = callback;
+    userCallbackData = userData;
+
+	RtMidiIn::setCallback( rtmidiCallback, (void*) this );
+}
+
+void MidiIn :: rtmidiCallback( double timeStamp, std::vector<unsigned char> *messageBytes, void *callbackData )
+{
+	MidiIn *midiin = (MidiIn*) callbackData;
+
+	MidiMessage* message = MidiMessage::parseMessage(*messageBytes);
+	midiin->userCallback( timeStamp, *message, midiin->userCallbackData );
+	delete message;
+}

+ 19 - 0
Midi.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include <vector>
+#include "RtMidi.h"
+#include "MidiMessage.h"
+
+class MidiIn : public RtMidiIn
+{
+public:
+	typedef void (*MidiMessageInCallback)( double timeStamp, MidiMessage &message, void *userData );
+	void setCallback( MidiMessageInCallback callback, void *userData = 0 );
+
+protected:
+	static void rtmidiCallback( double timeStamp, std::vector<unsigned char> *message, void *midiin );
+
+private:
+	MidiMessageInCallback userCallback;
+    void *userCallbackData;
+};

+ 92 - 0
MidiMessage.cpp

@@ -0,0 +1,92 @@
+#include <vector>
+#include "RtMidi.h" // RtMidiError
+#include "MidiMessage.h"
+
+MidiMessage* MidiMessage::parseMessage(std::vector<unsigned char> &messageBytes)
+{
+	// msg[0] has 8 bits                                                                        
+    //	- 4 higher significant bits: message type
+    //	- 4 lower significant bits: channel (0 - 15)
+	unsigned char messageType = messageBytes[0] >> 4;
+	if(messageType == 0xF) 
+	{
+		// system message
+		throw RtMidiError("MidiMessage::parseMessage() does not support system messages yet.", RtMidiError::DEBUG_WARNING);
+	}
+	else
+	{
+		// channel message
+		unsigned char channel = messageBytes[0] & 0xF;
+
+		switch(messageType)
+		{
+			case 0x8:
+			case 0x9:
+			{
+				unsigned char pitch = messageBytes[1];
+				unsigned char velocity = messageBytes[2];
+				if(messageType == 0x8 || velocity == 0)
+				{
+					return new NoteOffMessage(channel, pitch, velocity);
+				}
+				else
+				{
+					return new NoteOnMessage(channel, pitch, velocity);
+				}
+			}
+			case 0xB:
+				return new ControlChangeMessage(channel, messageBytes[1], messageBytes[2]);
+			case 0xC:
+				return new ProgramChangeMessage(channel, messageBytes[1]);
+			case 0xE:
+				// messageBytes[1] are the least significant 7 bits. 
+				// messageBytes[2] are the most significant 7 bits.
+				return new PitchBendChangeMessage(
+					channel, 
+					(messageBytes[2] << 7) + messageBytes[1]
+					);
+			default:
+				throw RtMidiError(
+					"MidiMessage::parseMessage() does not support the given type of channel message yet.", 
+					RtMidiError::DEBUG_WARNING
+					);
+		}
+	}
+}
+
+std::ostream& operator<<(std::ostream& stream, const MidiMessage& message)
+{
+	message.print(stream);
+	return stream;
+}
+
+void NoteOnMessage::print(std::ostream& stream) const
+{
+	stream	<< "channel #" << (unsigned short)(channel + 1) << ": "
+			<< "note " << (unsigned short)pitch << " with velocity " << (unsigned short)velocity << " on\n"; 
+}
+
+void NoteOffMessage::print(std::ostream& stream) const
+{
+	stream	<< "channel #" << (unsigned short)(channel + 1) << ": "
+			<< "note " << (unsigned short)pitch << " off\n"; 
+}
+
+void ControlChangeMessage::print(std::ostream& stream) const
+{
+	stream	<< "channel #" << (unsigned short)(channel + 1) << ": "
+			<< "change value of control #" << (unsigned short)(control + 1)
+			<< " to " << (unsigned short)value << "\n"; 
+}
+
+void ProgramChangeMessage::print(std::ostream& stream) const
+{
+	stream	<< "channel #" << (unsigned short)(channel + 1) << ": "
+			<< "switch to program # " << (unsigned short)(program + 1) << "\n"; 
+}
+
+void PitchBendChangeMessage::print(std::ostream& stream) const
+{
+	stream	<< "channel #" << (unsigned short)(channel + 1) << ": "
+			<< "pitch bended to " << value << "\n"; 
+}

+ 97 - 0
MidiMessage.h

@@ -0,0 +1,97 @@
+#pragma once
+#include <cstdint>
+
+class MidiMessage
+{
+public:
+	static MidiMessage* parseMessage(std::vector<unsigned char> &messageBytes);
+
+	virtual void print(std::ostream& stream) const = 0;
+};
+
+std::ostream& operator<<(std::ostream& stream, const MidiMessage& message);
+
+class ChannelMessage : public MidiMessage
+{
+public:
+	unsigned char channel;
+
+	ChannelMessage(unsigned char channel)
+		: channel(channel)
+	{
+	}
+};
+
+class NoteMessage : public ChannelMessage
+{
+public:
+	unsigned char pitch;
+	unsigned char velocity;
+
+	NoteMessage(unsigned char channel, unsigned char pitch, unsigned char velocity)
+		: ChannelMessage(channel), pitch(pitch), velocity(velocity)
+	{
+	}
+};
+
+class NoteOnMessage : public NoteMessage
+{
+public:
+	NoteOnMessage(unsigned char channel, unsigned char pitch, unsigned char velocity)
+		: NoteMessage(channel, pitch, velocity)
+	{
+	}
+
+	virtual void print(std::ostream& stream) const;
+};
+
+class NoteOffMessage : public NoteMessage
+{
+public:
+	NoteOffMessage(unsigned char channel, unsigned char pitch, unsigned char velocity)
+		: NoteMessage(channel, pitch, velocity)
+	{
+	}
+
+	virtual void print(std::ostream& stream) const;
+};
+
+class ControlChangeMessage : public ChannelMessage
+{
+public:
+	unsigned char control;
+	unsigned char value;
+
+	ControlChangeMessage(unsigned char channel, unsigned char control, unsigned char value)
+		: ChannelMessage(channel), control(control), value(value)
+	{
+	}
+	
+	virtual void print(std::ostream& stream) const;
+};
+
+class ProgramChangeMessage : public ChannelMessage
+{
+public:
+	unsigned char program;
+
+	ProgramChangeMessage(unsigned char channel, unsigned char program)
+		: ChannelMessage(channel), program(program)
+	{
+	}
+	
+	virtual void print(std::ostream& stream) const;
+};
+
+class PitchBendChangeMessage : public ChannelMessage
+{
+public:
+	uint16_t value;
+
+	PitchBendChangeMessage(unsigned char channel, uint16_t value)
+		: ChannelMessage(channel), value(value)
+	{
+	}
+	
+	virtual void print(std::ostream& stream) const;
+};

+ 4 - 0
msw/rtmidilib.vcxproj

@@ -70,9 +70,13 @@
     </Lib>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="..\Midi.cpp" />
+    <ClCompile Include="..\MidiMessage.cpp" />
     <ClCompile Include="..\RtMidi.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\Midi.h" />
+    <ClInclude Include="..\MidiMessage.h" />
     <ClInclude Include="..\RtMidi.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 12 - 0
msw/rtmidilib.vcxproj.filters

@@ -18,10 +18,22 @@
     <ClCompile Include="..\RtMidi.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="..\MidiMessage.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="..\Midi.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\RtMidi.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="..\Midi.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="..\MidiMessage.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>