public string Open() { // Open the port var st = AlsaNativeMethods.Snd_rawmidi_open_input( ref handle, IntPtr.Zero, Device, AlsaNativeMethods.EMode.SND_RAWMIDI_NONBLOCK); return(AlsaUtils.StrError(st)); }
static public string StrError(int err) { string result = null; if (err < 0) { var ptr = AlsaNativeMethods.Snd_strerror(err); result = Marshal.PtrToStringAuto(ptr); } return(result); }
public string Start() { int st = (int)AlsaNativeMethods.Snd_rawmidi_read(handle, null, 0); if (st == 0) { stop = false; readThread = new Thread(ReadThreadStart); readThread.Start(); } return(AlsaUtils.StrError(st)); }
public string Close() { int st = 0; if (handle != IntPtr.Zero) { st = AlsaNativeMethods.Snd_rawmidi_close(handle); handle = IntPtr.Zero; } return(AlsaUtils.StrError(st)); }
// Send a message public string Send(MidiMessage m) { byte[] data = m.GetAsByteArray(); // Meta messages are not sent over the wire if (data == null) { return(null); } ulong size = (ulong)data.Length; long st = AlsaNativeMethods.Snd_rawmidi_write(handle, data, size); return(AlsaUtils.StrError((int)st)); }
static public DeviceDescription[] EnumerateMidiPorts(AlsaNativeMethods.ESnd_rawmidi_stream type) { var ports = new List <DeviceDescription>(); // Enumerate all the sound cards int soundCardIx = -1; while (true) { // Get next sound card int err = AlsaNativeMethods.Snd_card_next(ref soundCardIx); if (err < 0) { throw new InvalidOperationException("Cannot get next sound card err = " + StrError(err)); } // No more sound card (normal end) if (soundCardIx < 0) { break; } // Build sound card name string soundCardName = "hw:" + soundCardIx.ToString(); // Open the sound card IntPtr handlePtr = IntPtr.Zero; err = AlsaNativeMethods.Snd_ctl_open(ref handlePtr, soundCardName, 0); if (err < 0) { throw new InvalidOperationException( "Cannot open sound card " + soundCardName + ", " + StrError(err)); } // Get all midi out devices on this sound card int deviceIx = -1; while (true) { err = AlsaNativeMethods.Snd_ctl_rawmidi_next_device(handlePtr, ref deviceIx); if (err < 0) { throw new InvalidOperationException( "Cannot get next midi device on sound card " + soundCardName + ", " + StrError(err)); } // End of devices if (deviceIx < 0) { break; } // We have a device! //Console.WriteLine("Found device " + deviceIx + " on soundcard " + soundCardName); // Get info block IntPtr infoPtr = IntPtr.Zero; AlsaNativeMethods.Snd_rawmidi_info_malloc(ref infoPtr); // Set device id in info block AlsaNativeMethods.Snd_rawmidi_info_set_device(infoPtr, (uint)deviceIx); // Set stream type (i.e. input/output) AlsaNativeMethods.Snd_rawmidi_info_set_stream(infoPtr, type); // Get info err = AlsaNativeMethods.Snd_ctl_rawmidi_info(handlePtr, infoPtr); if (err >= 0) { // We have a midi device of the type we are looking for! // Get number of sub-devices int subDeviceCount = AlsaNativeMethods.Snd_rawmidi_info_get_subdevices_count(infoPtr); // Iterate on sub-devices for (uint subDevice = 0; subDevice < subDeviceCount; subDevice++) { AlsaNativeMethods.Snd_rawmidi_info_set_subdevice(infoPtr, subDevice); err = AlsaNativeMethods.Snd_ctl_rawmidi_info(handlePtr, infoPtr); if (err < 0) { throw new InvalidOperationException( "Cannot get raw midi info err = " + StrError(err)); } var namePtr = AlsaNativeMethods.Snd_rawmidi_info_get_name(infoPtr); var name = Marshal.PtrToStringAuto(namePtr); var subNamePtr = AlsaNativeMethods.Snd_rawmidi_info_get_subdevice_name(infoPtr); var subName = Marshal.PtrToStringAuto(subNamePtr); string portName = (subDevice == 0 && subName == "") ? soundCardName + "," + deviceIx : soundCardName + "," + deviceIx + "," + subDevice; name = (subDevice == 0 && subName == "") ? name : subName; ports.Add(new DeviceDescription(portName, name)); } } // Free info block AlsaNativeMethods.Snd_rawmidi_info_free(infoPtr); } // Close sound card AlsaNativeMethods.Snd_ctl_close(handlePtr); } return(ports.ToArray()); }
private void ReadThreadStart() { byte[] buf = new byte[512]; byte[] overflowBuf = null; // Compute number of pollfd structures required to poll int numPollStructs = AlsaNativeMethods.Snd_rawmidi_poll_descriptors_count(handle); // Allocate space for the poll structures IntPtr pollAreaPtr = Marshal.AllocHGlobal(numPollStructs * AlsaNativeMethods.POLLFDSZ); int st = AlsaNativeMethods.Snd_rawmidi_poll_descriptors(handle, pollAreaPtr, (uint)numPollStructs); while (!stop) { st = AlsaNativeMethods.Poll(pollAreaPtr, numPollStructs, 200); if (st < 0) { var errno = Marshal.GetLastWin32Error(); if (errno == 4 /* EINTR */) { continue; } Console.WriteLine("MidiIn: Cannot poll - errno = " + errno); break; } if (st == 0) { continue; } // We got something - scan the poll struct ushort revent = 0; st = AlsaNativeMethods.Snd_rawmidi_poll_descriptors_revents( handle, pollAreaPtr, (uint)numPollStructs, ref revent); if (st < 0) { Console.WriteLine("MidiIn: Cannot parse poll - " + AlsaUtils.StrError(st)); break; } AlsaNativeMethods.EPoll evt = (AlsaNativeMethods.EPoll)revent; if (evt.HasFlag(AlsaNativeMethods.EPoll.POLLERR) || evt.HasFlag(AlsaNativeMethods.EPoll.POLLHUP)) { break; } if (evt.HasFlag(AlsaNativeMethods.EPoll.POLLIN)) { // We have something to read - read it int nRead = (int)AlsaNativeMethods.Snd_rawmidi_read(handle, buf, (uint)buf.Length); if (nRead < 0) { int errno = Marshal.GetLastWin32Error(); if (errno == 4 /* EINTR */) { continue; } Console.WriteLine("MidiIn: Cannot parse poll - " + AlsaUtils.StrError(st)); break; } // Combine with overflow buffer if we had an overflow last time if (overflowBuf != null) { var newBuf = new byte[buf.Length + overflowBuf.Length]; Array.Copy(overflowBuf, 0, newBuf, 0, overflowBuf.Length); Array.Copy(buf, 0, newBuf, overflowBuf.Length, buf.Length); buf = newBuf; overflowBuf = null; } // Translate the input to midi message int nParsed = 0; while (true) { st = ParseBuffer(buf, nParsed, nRead, out MidiMessage midiMessage); if (st < 0) { // buffer contains an incomplete message overflowBuf = buf; buf = new byte[overflowBuf.Length]; } else if (st == 0) { // Message not supported - drop everything. break; } else // st > 0 { // Send message var midiEvent = new MidiEvent(midiMessage, 0); var midiEventArg = new WindowsMultiMedia.WindowsMidiEventArgs(midiEvent, IntPtr.Zero, IntPtr.Zero); MidiInputReceived?.Invoke(this, midiEventArg); // Update counters nParsed += st; nRead -= st; if (nRead <= 0) { // Normal end break; } } } } } Marshal.FreeHGlobal(pollAreaPtr); }
public string Reset() { int st = AlsaNativeMethods.Snd_rawmidi_drop(handle); return(AlsaUtils.StrError(st)); }