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));
        }
Beispiel #2
0
        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));
        }
Beispiel #5
0
        // 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));
        }
Beispiel #6
0
        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));
        }