예제 #1
0
        // Start the port and setup buffers to receives Sysex
        public string Start()
        {
            // Allocate buffer array
            if (buffers == null)
            {
                const int numBuffers = 4;
                const int bufferSize = 4096; // ZZZ Param?

                buffers = new MidiBuffer[numBuffers];

                // Allocate and prepare the buffers
                for (int b = 0; b < buffers.Length; b++)
                {
                    // Create buffer
                    buffers[b] = new MidiBuffer(bufferSize, (IntPtr)b);

                    // Prepare the buffer and give it to windows
                    EMMError st = buffers[b].AddMidiInBuffer(handle);
                    if (st != EMMError.NOERROR)
                    {
                        return(WindowsUtil.StrError(st));
                    }
                }
            }

            // Finally, start the port
            return(WindowsUtil.StrError(NativeMethods.midiInStart(handle)));
        }
예제 #2
0
        // Send a message
        public string Send(MidiMessage m)
        {
            var st = EMMError.NOERROR;

            if (m is MidiSysexMessage)
            {
                // Sysex messages are sent using a buffer.
                var sysex  = m as MidiSysexMessage;
                var buffer = new MidiBuffer(sysex.Body);
                using (buffer)
                {
                    // Prepare the buffer
                    st = buffer.PrepareForMidiOut(handle);
                    if (st == EMMError.NOERROR)
                    {
                        // Send the sysex
                        st = NativeMethods.midiOutLongMsg(handle, buffer.Header, buffer.HeaderSize);
                    }
                    if (st == EMMError.NOERROR)
                    {
                        // Wait until it is sent
                        // Note: this is simple but weak... If performance becomes necessary
                        // we can declare a callback, not wait here (just queue the buffer) and
                        // unprepare it when we receive the appropriate message in the callback
                        while (!buffer.IsFree())
                        {
                            Thread.Sleep(1);
                        }

                        // unprepare the buffer
                        st = buffer.UnprepareForMidiOut(handle);
                    }
                }
            }
            else
            {
                uint sm = m.GetAsShortMessage();
                if (sm != uint.MaxValue)
                {
                    st = NativeMethods.midiOutShortMsg(handle, sm);
                }
            }

            return(WindowsUtil.StrError(st));
        }
예제 #3
0
        // Forward callback to user-provided function
        private void MidiProc(IntPtr hMidiIn,
                              EMMMidiMessages wMsg,
                              IntPtr dwInstance,
                              IntPtr dwParam1,
                              IntPtr dwParam2)
        {
            if (wMsg == EMMMidiMessages.MIM_DATA)
            {
                if (MidiInputReceived != null)
                {
                    // Make a midi event out of the incoming params
                    MidiEvent e = MidiInParser.ParseMimDataMessage((uint)dwParam1, (uint)dwParam2);

                    // Give it to the user
                    MidiInputReceived.Invoke(this, new WindowsMidiEventArgs(e, dwParam1, dwParam2));
                }
            }
            else if (wMsg == EMMMidiMessages.MIMLONG_DATA)
            {
                // The first parameter is a pointer to a buffer descriptor
                var header = dwParam1;

                // Find this buffer in our buffer set
                int index = (int)MidiBuffer.GetUserData(header);
                if (index < 0 || index >= buffers.Length)
                {
                    throw new InvalidOperationException("midiInputPort: MIMLONG_DATA buffer not found - index " + index);
                }

                var buffer = buffers[index];
                if (buffer != null)
                {
                    // Get data from buffer
                    var data = buffer.GetRecordedData();
                    if (data.Length == 0)
                    {
                        // This happens on Reset(), all the buffers are freed by windows and we get a MIMLONG_DATA for each of them.
                        // Free the buffer.
                        buffer.RemoveMidiInBuffer(handle);
                        buffer.Dispose();
                        buffers[index] = null;
                    }
                    else
                    {
                        // Give the buffer back to windows, we are done with it
                        buffer.AddMidiInBuffer(handle);

                        // If we have a callback, either generate a sysex or
                        // memorize the data if we don't have a full sysex
                        if (MidiInputReceived != null)
                        {
                            MidiSysexMessage sysex = null;

                            if (data[0] == (byte)EMidiCommand.SystemExclusive)
                            {
                                // This buffer contains the beginning of the sysex - check we don't have an ongoing sysex
                                if (this.partialSysex != null)
                                {
                                    throw new InvalidOperationException("midiInputPort: Beginning of new sysex received while previous one still on-going");
                                }

                                if (data[data.Length - 1] == (byte)EMidiCommand.EndOfSystemExclusive)
                                {
                                    // This buffer contains a full sysex
                                    sysex = new MidiSysexMessage(data);
                                }
                                else
                                {
                                    // This buffer contains the beginning of a sysex
                                    this.partialSysex = data;
                                }
                            }
                            else
                            {
                                // This buffer is a continuation of a sysex. Verify we have an ongoing sysex
                                if (this.partialSysex == null)
                                {
                                    throw new InvalidOperationException("midiInputPort: Continuation sysex without beginning");
                                }

                                // Concatenate the partial data and the new data
                                var dataSoFar = new byte[partialSysex.Length + data.Length];
                                partialSysex.CopyTo(dataSoFar, 0);
                                data.CopyTo(dataSoFar, dataSoFar.Length);

                                if (data[data.Length - 1] == (byte)EMidiCommand.EndOfSystemExclusive)
                                {
                                    // This buffer concludes the sysex
                                    sysex             = new MidiSysexMessage(dataSoFar);
                                    this.partialSysex = null;
                                }
                                else
                                {
                                    // This buffer contains a partial sysex, add it to the partial sysex
                                    this.partialSysex = dataSoFar;
                                }
                            }

                            // Create sysex event if we have a sysex
                            if (sysex != null)
                            {
                                // Make a midi event out of the sysex
                                var e = new MidiEvent(sysex, (uint)dwParam2);

                                // Give it to the user
                                MidiInputReceived.Invoke(this, new WindowsMidiEventArgs(e, dwParam1, dwParam2));
                            }
                        }
                    }
                }
            }
        }