136 lines
4.8 KiB
C#
136 lines
4.8 KiB
C#
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Threading;
|
|
using static RushMidiLibrary.MidiApiWindows;
|
|
|
|
namespace RushMidiLibrary {
|
|
public class MidiInputDevice : MidiDevice {
|
|
private MidiApiWindows.MidiInProc _inputCallback;
|
|
private UIntPtr _deviceId;
|
|
private MidiApiWindows.HMIDIIN _deviceHandle;
|
|
private Thread _messageProcessingThread;
|
|
private bool _messageProcessingThreadExitRequest = false;
|
|
|
|
readonly BlockingCollection<Message> _messageQueue = new BlockingCollection<Message>();
|
|
|
|
private struct Message {
|
|
public MidiApiWindows.HMIDIIN hMidiIn;
|
|
public MidiApiWindows.MidiInMessage wMsg;
|
|
public UIntPtr dwInstance;
|
|
public UIntPtr dwParam1;
|
|
public UIntPtr dwParam2;
|
|
}
|
|
|
|
public MidiInputDevice(UIntPtr deviceId, MidiApiWindows.MIDIINCAPS caps) {
|
|
_deviceId = deviceId;
|
|
}
|
|
|
|
public static MidiInputDevice[] Enumerate() {
|
|
var devs = MidiApiWindows.midiInGetNumDevs();
|
|
MidiInputDevice[] result = new MidiInputDevice[devs];
|
|
for (uint deviceId = 0; deviceId < devs; deviceId++) {
|
|
MidiApiWindows.MIDIINCAPS caps;
|
|
MidiApiWindows.midiInGetDevCaps((UIntPtr)deviceId, out caps);
|
|
result[deviceId] = new MidiInputDevice((UIntPtr)deviceId, caps);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public void Open() {
|
|
_inputCallback = this.InputCallback;
|
|
|
|
BeginMessageProcessing();
|
|
try {
|
|
CheckMMResult(MidiApiWindows.midiInOpen(out _deviceHandle, _deviceId, _inputCallback, (UIntPtr)0));
|
|
}
|
|
catch (Exception) {
|
|
EndMessageProcessing();
|
|
throw;
|
|
}
|
|
|
|
}
|
|
|
|
public void Start() {
|
|
CheckMMResult(MidiApiWindows.midiInStart(_deviceHandle));
|
|
}
|
|
|
|
private void InputCallback(MidiApiWindows.HMIDIIN hMidiIn, MidiApiWindows.MidiInMessage wMsg, UIntPtr dwInstance, UIntPtr dwParam1, UIntPtr dwParam2) {
|
|
Message message = new Message();
|
|
message.hMidiIn = hMidiIn;
|
|
message.wMsg = wMsg;
|
|
message.dwInstance = dwInstance;
|
|
message.dwParam1 = dwParam1;
|
|
message.dwParam2 = dwParam2;
|
|
_messageQueue.Add(message);
|
|
}
|
|
|
|
|
|
private void BeginMessageProcessing() {
|
|
_messageProcessingThreadExitRequest = false;
|
|
_messageProcessingThread = new Thread(MessageProcessingThreadHandler);
|
|
_messageProcessingThread.Start();
|
|
}
|
|
|
|
private void MessageProcessingThreadHandler() {
|
|
while (!_messageProcessingThreadExitRequest) {
|
|
Message message;
|
|
if (_messageQueue.TryTake(out message, 100)) {
|
|
HandleMessage(message);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void EndMessageProcessing() {
|
|
_messageProcessingThreadExitRequest = true;
|
|
_messageProcessingThread.Join();
|
|
}
|
|
|
|
private void HandleMessage(Message message) {
|
|
|
|
switch (message.wMsg) {
|
|
case MidiInMessage.MIM_DATA:
|
|
HandleMessageData(new MidiShortMessage(message.dwParam1, message.dwParam2));
|
|
break;
|
|
case MidiInMessage.MIM_LONGDATA:
|
|
HandleMessageLongData(message.dwParam1, message.dwParam2);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void HandleMessageData(MidiShortMessage message) {
|
|
if (message.IsNoteOn) {
|
|
MidiChannel channel;
|
|
int noteId;
|
|
int velocity;
|
|
uint timestamp;
|
|
message.GetNoteOn(out channel, out noteId, out velocity, out timestamp);
|
|
|
|
var note = new MidiNote(noteId);
|
|
|
|
Console.WriteLine($"Received short message NoteOn: Name={note.Name} Octave={note.OctaveName} Channel={channel.ToString()}, NoteId={noteId}, Velocity={velocity}, Timestapm={timestamp}");
|
|
|
|
} else if (message.IsNoteOff) {
|
|
MidiChannel channel;
|
|
int noteId;
|
|
int velocity;
|
|
uint timestamp;
|
|
message.GetNoteOff(out channel, out noteId, out velocity, out timestamp);
|
|
|
|
var note = new MidiNote(noteId);
|
|
|
|
Console.WriteLine($"Received short message NoteOff: Name={note.Name} Octave={note.OctaveName} Channel={channel.ToString()}, NoteId={noteId}, Velocity={velocity}, Timestapm={timestamp}");
|
|
|
|
} else {
|
|
Console.WriteLine($"Received short message");
|
|
}
|
|
|
|
}
|
|
|
|
private void HandleMessageLongData(UIntPtr dwParam1, UIntPtr dwParam2) {
|
|
Console.WriteLine($"Received long message");
|
|
}
|
|
}
|
|
}
|