Ejemplo n.º 1
0
 /// <summary>
 /// Sends a message immediately to the device
 /// </summary>
 /// <param name="message">The message to send</param>
 /// <remarks>The message is not queued. Tempo change messages are not honored.</remarks>
 public void Send(MidiMessage message)
 {
     if (IntPtr.Zero == _handle)
     {
         throw new InvalidOperationException("The device is closed.");
     }
     if (null == message)
     {
         throw new ArgumentNullException("message");
     }
     if (0xF0 == (message.Status & 0xF0))
     {
         if (0xF != message.Channel)
         {
             var data = MidiUtility.ToMessageBytes(message);
             if (null == data)
             {
                 return;
             }
             if (254 < data.Length)
             {
                 var len = 254;
                 for (var i = 0; i < data.Length; i += len)
                 {
                     if (data.Length <= i + len)
                     {
                         len = data.Length - i;
                     }
                     _SendRaw(data, i, len);
                 }
             }
             else
             {
                 _SendRaw(data, 0, data.Length);
             }
         }
     }
     else
     {
         _CheckOutResult(midiOutShortMsg(_handle, MidiUtility.PackMessage(message)));
     }
 }
Ejemplo n.º 2
0
        void _SendBlock()
        {
            if (null == _sendQueue)
            {
                return;
            }
            if (IntPtr.Zero == _handle)
            {
                throw new InvalidOperationException("The stream is closed.");
            }

            if (IntPtr.Zero != Interlocked.CompareExchange(ref _sendHeader.lpData, _sendEventBuffer, IntPtr.Zero))
            {
                throw new InvalidOperationException("The stream is busy playing.");
            }

            int    baseEventSize = Marshal.SizeOf(typeof(MIDIEVENT));
            int    blockSize     = 0;
            IntPtr eventPointer  = _sendEventBuffer;
            var    ofs           = 0;
            var    ptrOfs        = 0;

            for (; _sendQueuePosition < _sendQueue.Count; Interlocked.Exchange(ref _sendQueuePosition, _sendQueuePosition + 1))
            {
                var @event = _sendQueue[_sendQueuePosition];
                if (0x00 != @event.Message.Status && 0xF0 != (@event.Message.Status & 0xF0))
                {
                    if (_SendBufferSize < blockSize + baseEventSize)
                    {
                        break;
                    }
                    blockSize += baseEventSize;
                    var se = new MIDIEVENT();
                    se.dwDeltaTime = @event.Position + ofs;
                    se.dwStreamId  = 0;
                    se.dwEvent     = MidiUtility.PackMessage(@event.Message);
                    var gch = GCHandle.Alloc(se, GCHandleType.Pinned);
                    CopyMemory(new IntPtr(ptrOfs + eventPointer.ToInt64()), gch.AddrOfPinnedObject(), Marshal.SizeOf(typeof(MIDIEVENT)));
                    gch.Free();
                    ptrOfs += baseEventSize;
                    ofs     = 0;
                }
                else if (0xFF == @event.Message.Status)
                {
                    var mm = @event.Message as MidiMessageMeta;
                    if (0x51 == mm.Data1)                     // tempo
                    {
                        if (_SendBufferSize < blockSize + baseEventSize)
                        {
                            break;
                        }
                        blockSize += baseEventSize;
                        var se = new MIDIEVENT();
                        se.dwDeltaTime = @event.Position + ofs;
                        se.dwStreamId  = 0;
                        se.dwEvent     = (mm.Data[0] << 16) | (mm.Data[1] << 8) | mm.Data[2] | (MEVT_TEMPO << 24);
                        var gch = GCHandle.Alloc(se, GCHandleType.Pinned);
                        CopyMemory(new IntPtr(ptrOfs + eventPointer.ToInt64()), gch.AddrOfPinnedObject(), Marshal.SizeOf(typeof(MIDIEVENT)));
                        gch.Free();
                        ptrOfs += baseEventSize;
                        ofs     = 0;
                    }
                    else if (0x2f == mm.Data1)                     // end track
                    {
                        if (_SendBufferSize < blockSize + baseEventSize)
                        {
                            break;
                        }
                        blockSize += baseEventSize;

                        // add a NOP message to it just to pad our output in case we're looping
                        var se = new MIDIEVENT();
                        se.dwDeltaTime = @event.Position + ofs;
                        se.dwStreamId  = 0;
                        se.dwEvent     = (MEVT_NOP << 24);
                        var gch = GCHandle.Alloc(se, GCHandleType.Pinned);
                        CopyMemory(new IntPtr(ptrOfs + eventPointer.ToInt64()), gch.AddrOfPinnedObject(), Marshal.SizeOf(typeof(MIDIEVENT)));
                        gch.Free();
                        ptrOfs += baseEventSize;
                        ofs     = 0;
                    }
                    else
                    {
                        ofs = @event.Position;
                    }
                }
                else                 // sysex or sysex part
                {
                    byte[] data;
                    if (0 == @event.Message.Status)
                    {
                        data = (@event.Message as MidiMessageSysexPart).Data;
                    }
                    else
                    {
                        data = MidiUtility.ToMessageBytes(@event.Message);
                    }


                    var dl = data.Length;
                    if (0 != (dl % 4))
                    {
                        dl += 4 - (dl % 4);
                    }
                    if (_SendBufferSize < blockSize + baseEventSize + dl)
                    {
                        break;
                    }

                    blockSize += baseEventSize + dl;

                    var se = new MIDIEVENT();
                    se.dwDeltaTime = @event.Position + ofs;
                    se.dwStreamId  = 0;
                    se.dwEvent     = MEVT_F_LONG | data.Length;
                    var gch = GCHandle.Alloc(se, GCHandleType.Pinned);
                    CopyMemory(new IntPtr(ptrOfs + eventPointer.ToInt64()), gch.AddrOfPinnedObject(), Marshal.SizeOf(typeof(MIDIEVENT)));
                    gch.Free();
                    ptrOfs += baseEventSize;
                    Marshal.Copy(data, 0, new IntPtr(ptrOfs + eventPointer.ToInt64()), data.Length);

                    ptrOfs += dl;
                    ofs     = 0;
                }
            }
            _sendHeader = default(MIDIHDR);
            _sendHeader.dwBufferLength = _sendHeader.dwBytesRecorded = unchecked ((uint)blockSize);
            _sendHeader.lpData         = _sendEventBuffer;
            int headerSize = Marshal.SizeOf(typeof(MIDIHDR));

            _CheckOutResult(midiOutPrepareHeader(_handle, ref _sendHeader, headerSize));
            _CheckOutResult(midiStreamOut(_handle, ref _sendHeader, headerSize));
        }
Ejemplo n.º 3
0
        void _SendBlock()
        {
            if (null == _sendQueue)
            {
                return;
            }
            if (IntPtr.Zero == Handle)
            {
                throw new InvalidOperationException("The stream is closed.");
            }

            int    blockSize     = 0;
            IntPtr headerPointer = Marshal.AllocHGlobal(MIDIHDR_SIZE + MAX_EVENTBLOCK_SIZE);

            try
            {
                IntPtr eventPointer = new IntPtr(headerPointer.ToInt64() + MIDIHDR_SIZE);
                var    ofs          = 0;
                var    ptrOfs       = 0;
                for (; _sendQueuePosition < _sendQueue.Count; Interlocked.Exchange(ref _sendQueuePosition, _sendQueuePosition + 1))
                {
                    var @event = _sendQueue[_sendQueuePosition];
                    if (0x00 != @event.Message.Status && 0xF0 != (@event.Message.Status & 0xF0))
                    {
                        if (MAX_EVENTBLOCK_SIZE < blockSize + MIDIEVENT_SIZE)
                        {
                            break;
                        }
                        blockSize += MIDIEVENT_SIZE;
                        var se = default(MIDIEVENT);
                        se.dwDeltaTime = @event.Position + ofs;
                        se.dwStreamId  = 0;
                        se.dwEvent     = MidiUtility.PackMessage(@event.Message);
                        Marshal.StructureToPtr(se, new IntPtr(ptrOfs + eventPointer.ToInt64()), false);
                        ptrOfs += MIDIEVENT_SIZE;
                        ofs     = 0;
                    }
                    else if (0xFF == @event.Message.Status)
                    {
                        var mm = @event.Message as MidiMessageMeta;
                        if (0x51 == mm.Data1)                         // tempo
                        {
                            if (MAX_EVENTBLOCK_SIZE < blockSize + MIDIEVENT_SIZE)
                            {
                                break;
                            }
                            blockSize += MIDIEVENT_SIZE;
                            var se = default(MIDIEVENT);
                            se.dwDeltaTime = @event.Position + ofs;
                            se.dwStreamId  = 0;
                            se.dwEvent     = (mm.Data[0] << 16) | (mm.Data[1] << 8) | mm.Data[2] | (MEVT_TEMPO << 24);
                            Marshal.StructureToPtr(se, new IntPtr(ptrOfs + eventPointer.ToInt64()), false);
                            ptrOfs += MIDIEVENT_SIZE;
                            ofs     = 0;
                        }
                        else if (0x2f == mm.Data1)                         // end track
                        {
                            if (MAX_EVENTBLOCK_SIZE < blockSize + MIDIEVENT_SIZE)
                            {
                                break;
                            }
                            blockSize += MIDIEVENT_SIZE;

                            // add a NOP message to it just to pad our output in case we're looping
                            var se = default(MIDIEVENT);
                            se.dwDeltaTime = @event.Position + ofs;
                            se.dwStreamId  = 0;
                            se.dwEvent     = (MEVT_NOP << 24);
                            Marshal.StructureToPtr(se, new IntPtr(ptrOfs + eventPointer.ToInt64()), false);
                            ptrOfs += MIDIEVENT_SIZE;
                            ofs     = 0;
                        }
                        else
                        {
                            ofs = @event.Position;
                        }
                    }
                    else                     // sysex or sysex part
                    {
                        byte[] data;
                        if (0 == @event.Message.Status)
                        {
                            data = (@event.Message as MidiMessageSysexPart).Data;
                        }
                        else
                        {
                            data = MidiUtility.ToMessageBytes(@event.Message);
                        }


                        var dl = data.Length;
                        if (0 != (dl % 4))
                        {
                            dl += 4 - (dl % 4);
                        }
                        if (MAX_EVENTBLOCK_SIZE < blockSize + MIDIEVENT_SIZE + dl)
                        {
                            break;
                        }

                        blockSize += MIDIEVENT_SIZE + dl;

                        var se = default(MIDIEVENT);
                        se.dwDeltaTime = @event.Position + ofs;
                        se.dwStreamId  = 0;
                        se.dwEvent     = MEVT_F_LONG | data.Length;
                        Marshal.StructureToPtr(se, new IntPtr(ptrOfs + eventPointer.ToInt64()), false);
                        ptrOfs += MIDIEVENT_SIZE;
                        Marshal.Copy(data, 0, new IntPtr(ptrOfs + eventPointer.ToInt64()), data.Length);

                        ptrOfs += dl;
                        ofs     = 0;
                    }
                }
                var header = default(MIDIHDR);
                header.dwBufferLength = header.dwBytesRecorded = unchecked ((uint)blockSize);
                header.lpData         = eventPointer;
                Marshal.StructureToPtr(header, headerPointer, false);
                _CheckOutResult(midiOutPrepareHeader(Handle, headerPointer, MIDIHDR_SIZE));
                _CheckOutResult(midiStreamOut(Handle, headerPointer, MIDIHDR_SIZE));
                headerPointer = IntPtr.Zero;
            }
            finally
            {
                if (IntPtr.Zero != headerPointer)
                {
                    Marshal.FreeHGlobal(headerPointer);
                }
            }
        }