Click here to Skip to main content
15,879,326 members
Home / Discussions / C#
   

C#

 
AnswerRe: C# Class for Finger Print Capture Pin
Thomas Duwe5-Sep-12 22:18
Thomas Duwe5-Sep-12 22:18 
QuestionPicture box click event Pin
Soni_moni5-Sep-12 19:43
Soni_moni5-Sep-12 19:43 
AnswerRe: Picture box click event Pin
Shameel5-Sep-12 20:36
professionalShameel5-Sep-12 20:36 
AnswerRe: Picture box click event Pin
DaveyM696-Sep-12 3:18
professionalDaveyM696-Sep-12 3:18 
QuestionC# MIDI controller interface. Pin
Jumpin' Jeff5-Sep-12 16:38
Jumpin' Jeff5-Sep-12 16:38 
AnswerRe: C# MIDI controller interface. Pin
DaveyM695-Sep-12 22:17
professionalDaveyM695-Sep-12 22:17 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff6-Sep-12 14:26
Jumpin' Jeff6-Sep-12 14:26 
GeneralRe: C# MIDI controller interface. Pin
DaveyM697-Sep-12 0:57
professionalDaveyM697-Sep-12 0:57 
Hi Jeff,

Two versions, one simple and one more complex. Any questions, just ask Smile | :)

This is using a console app and procedurally rather than using OOP as it's simpler to understand. This is as simple as I can make it!
C#
using System;
using System.Runtime.InteropServices;
using System.Threading;

namespace SimpleSysExSender
{
    class Program
    {
        const int MMSYSERR_NOERROR = 0;
        const int MIDIERR_STILLPLAYING = 65;
        static readonly int MidiHdrSize = Marshal.SizeOf(typeof(MIDIHDR));

        static void Main(string[] args)
        {
            int id = 0;
            byte[] data = new byte[] { 0xF0, 0x7E, 0x7F, 0x09, 0x01, 0xF7 }; // GM On


            if (id >= 0 && id < midiOutGetNumDevs())
            {
                IntPtr handle;
                if (midiOutOpen(out handle, id, IntPtr.Zero, IntPtr.Zero, 0) == MMSYSERR_NOERROR)
                {

                    IntPtr dataHandle = Marshal.AllocHGlobal(data.Length);
                    Marshal.Copy(data, 0, dataHandle, data.Length);
                    MIDIHDR buffer = new MIDIHDR(dataHandle, data.Length);
                    GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                    IntPtr address = gcHandle.AddrOfPinnedObject();

                    if (midiOutPrepareHeader(handle, address, MidiHdrSize) == MMSYSERR_NOERROR)
                    {
                        midiOutLongMsg(handle, address, MidiHdrSize);
                        while (midiOutUnprepareHeader(handle, address, MidiHdrSize) == MIDIERR_STILLPLAYING)
                            Thread.Sleep(1);
                    }

                    gcHandle.Free();
                    Marshal.FreeHGlobal(dataHandle);
                    midiOutClose(handle);
                }
            }
        }

        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutClose(IntPtr hmo);

        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutGetNumDevs();

        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutLongMsg(IntPtr hmo, IntPtr lpMidiOutHdr, int cbMidiOutHdr);

        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutOpen(out IntPtr lphmo, int uDeviceID, IntPtr dwCallback, IntPtr dwCallbackInstance, int dwFlags);

        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutPrepareHeader(IntPtr hmo, IntPtr lpMidiOutHdr, int cbMidiOutHdr);

        public delegate void MidiOutProc(IntPtr hmo, int wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2);

        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutUnprepareHeader(IntPtr hmo, IntPtr lpMidiOutHdr, int cbMidiOutHdr);
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct MIDIHDR
    {
        private IntPtr lpData;
        private int dwBufferLength; // keep this under 16KB
        private int dwBytesRecorded;
        private IntPtr dwUser;
        private int dwFlags;
        private IntPtr lpNext;
        private IntPtr reserved;
        private int dwOffset;
        private IntPtr dwReserved;

        public MIDIHDR(IntPtr lpData, int dwBufferLength)
        {
            this.lpData = lpData;
            this.dwBufferLength = dwBufferLength;
            dwBytesRecorded = dwBufferLength;
            dwUser = IntPtr.Zero;
            dwFlags = 0;
            lpNext = IntPtr.Zero;
            reserved = IntPtr.Zero;
            dwOffset = 0;
            dwReserved = IntPtr.Zero;
        }
    }
}


This is a more OOP version of the same thing (sorry for the length!). More robust and more comments, but may be overkill for your requirements:
C#
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Threading;

namespace MidiSysExSender
{
    class Program
    {
        static void Main(string[] args)
        {
            // Check there are MIDI outs!
            if (MidiOutputCollection.Outputs.Count > 0)
            {
                // I'm assuming your device is the first one
                MidiOutput output = MidiOutputCollection.Outputs[0];
                // Open the output
                output.Open();

                output.SendSysEx(MidiSystemExclusiveMessage.GeneralMidiOn);

                // Close the output
                output.Close();
                Console.WriteLine("Done");
            }
            else
                Console.WriteLine("No MIDI Outs found");
            Console.ReadKey();
        }
    }

    public class MidiOutput
    {
        private NativeMethods.MidiOutProc callback;
        private MIDIOUTCAPS caps;
        private IntPtr handle;
        private int id;

        internal MidiOutput(int id)
        {
            // Get device capabilities/information
            MIDIOUTCAPS caps;
            int nativeResult = NativeMethods.midiOutGetDevCaps(id, out caps, MIDIOUTCAPS.Size);
            if (nativeResult == NativeMethods.MMSYSERR_NOERROR)
            {
                callback = Callback;
                this.caps = caps;
                this.id = id;
            }
            else
                // This should really be a custom MidiException with the message 
                // set to text retrieved from MidiOutGetErrorText
                throw new InvalidOperationException();
        }

        public int ChannelMask
        {
            get { return caps.ChannelMask; }
        }
        public Version DriverVersion
        {
            get { return caps.DriverVersion; }
        }
        public int Id
        {
            get { return id; }
        }
        public bool IsOpen
        {
            get { return handle != IntPtr.Zero; }
        }
        public int ManufacturerId
        {
            get { return caps.ManufacturerId; }
        }
        public string Name
        {
            get { return caps.Name; }
        }
        public int Notes
        {
            get { return caps.Notes; }
        }
        public int ProductId
        {
            get { return caps.ProductId; }
        }
        public MidiOutputTechnology Technology
        {
            get { return caps.Technology; }
        }
        public int Voices
        {
            get { return caps.Voices; }
        }
        public MidiOutputSupport Support
        {
            get { return caps.Support; }
        }

        private void Callback(IntPtr hmo, int wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2)
        {
            // Handle any MIDI Out callbacks here
        }
        public void Close()
        {
            if (IsOpen)
            {
                int nativeResult = NativeMethods.midiOutClose(handle);
                if (nativeResult == NativeMethods.MMSYSERR_NOERROR)
                    handle = IntPtr.Zero;
                else
                    // This should really be a custom MidiException with the message 
                    // set to text retrieved from MidiOutGetErrorText
                    throw new InvalidOperationException();
            }
        }
        public void Open()
        {
            if (!IsOpen)
            {
                IntPtr handle;
                int nativeResult = NativeMethods.midiOutOpen(out handle, id, callback, IntPtr.Zero, NativeMethods.CALLBACK_FUNCTION);
                if (nativeResult == NativeMethods.MMSYSERR_NOERROR)
                    this.handle = handle;
                else
                    // This should really be a custom MidiException with the message 
                    // set to text retrieved from MidiOutGetErrorText
                    throw new InvalidOperationException();
            }
        }
        public void SendSysEx(MidiSystemExclusiveMessage sysEx)
        {
            if (!IsOpen)
                Open();
            MIDIHDR buffer = new MIDIHDR(sysEx);
            // We need to pin the buffer so it doesn't move
            GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            IntPtr address = gcHandle.AddrOfPinnedObject();
            // prepare buffer
            int nativeResult = NativeMethods.midiOutPrepareHeader(handle, address, MIDIHDR.Size);
            if (nativeResult == NativeMethods.MMSYSERR_NOERROR)
            {
                // Send message
                NativeMethods.midiOutLongMsg(handle, address, MIDIHDR.Size);

                // unprepare buffer
                while (NativeMethods.midiOutUnprepareHeader(handle, address, MIDIHDR.Size) == NativeMethods.MIDIERR_STILLPLAYING)
                    Thread.Sleep(1);
            }

            // IMPORTANT! Free all memory once we're done.
            gcHandle.Free();
            buffer.Free();
        }
        public override string ToString()
        {
            return string.Format(CultureInfo.InvariantCulture, "MIDI Output {0}: {1}", id, Name);
        }
    }

    // Singleton that creates a MidiOutput for each MIDI Out installed.
    // For singleton see: http://csharpindepth.com/Articles/General/Singleton.aspx
    // Wraps a List that holds the MIDI Outs
    public class MidiOutputCollection : IDisposable, IEnumerable<MidiOutput>
    {
        private List<MidiOutput> list;

        private MidiOutputCollection()
        {
            // Get how many installed outputs, this gives us the ids zero based (0 to count-1)
            int count = NativeMethods.midiOutGetNumDevs();
            list = new List<MidiOutput>(count);
            if (count > 0)
            {
                for (int id = 0; id < count; id++)
                    list.Add(new MidiOutput(id));
            }
        }
        // We need to ensure that all MIDI Outs are closed before we exit.
        ~MidiOutputCollection()
        {
            Dispose(false);
        }

        public MidiOutput this[int index]
        {
            get { return list[index]; }
        }
        public int Count
        {
            get { return list.Count; }
        }
        public static MidiOutputCollection Outputs
        {
            get { return InstanceHolder.Instance; }
        }
        public void Dispose()
        {
            Dispose(true);
            // Commenting out this line as Outputs may still need disposing if reused.
            // GC.SuppressFinalize(this);
        }
        private void Dispose(bool disposing)
        {
            if (disposing)
            { }
            foreach (MidiOutput midiOutput in this)
                midiOutput.Close();
        }
        public IEnumerator<MidiOutput> GetEnumerator()
        {
            return list.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return list.GetEnumerator();
        }
        public int IndexOf(MidiOutput midiOutput)
        {
            return list.IndexOf(midiOutput);
        }

        private class InstanceHolder
        {
            // Explicit static constructor to tell C# compiler
            // not to mark type as beforefieldinit
            static InstanceHolder()
            { }

            private static readonly MidiOutputCollection instance = new MidiOutputCollection();

            internal static MidiOutputCollection Instance
            {
                get { return instance; }
            }
        }
    }

    public enum MidiOutputTechnology
    {
        Undefined,
        Port = NativeMethods.MOD_MIDIPORT,
        Synthesizer = NativeMethods.MOD_SYNTH,
        SquareWaveSynthesizer = NativeMethods.MOD_SQSYNTH,
        FMSynthesizer = NativeMethods.MOD_FMSYNTH,
        MidiMapper = NativeMethods.MOD_MAPPER,
        WavetableSynthesizer = NativeMethods.MOD_WAVETABLE,
        SoftwareSynthesizer = NativeMethods.MOD_SWSYNTH
    }

    [Flags]
    public enum MidiOutputSupport
    {
        None = 0,
        PatchCaching = NativeMethods.MIDICAPS_CACHE,
        StereoVolume = NativeMethods.MIDICAPS_LRVOLUME,
        StreamOut = NativeMethods.MIDICAPS_STREAM,
        Volume = NativeMethods.MIDICAPS_VOLUME,
    }

    // Wraps a list of data bytes automatically inserting start and end of exclusive bytes
    public class MidiSystemExclusiveMessage : IEnumerable<byte>
    {
        public const byte SOX = 0xF0;
        public const byte EOX = 0xF7;
        public const byte MaxByte = 0x7F;

        public static MidiSystemExclusiveMessage GeneralMidiOn = new MidiSystemExclusiveMessage(0x7E, 0x7F, 0x09, 0x01);
        public static MidiSystemExclusiveMessage GeneralMidiOff = new MidiSystemExclusiveMessage(0x7E, 0x7F, 0x09, 0x02);

        private List<byte> list;

        public MidiSystemExclusiveMessage(params byte[] data)
        {
            if (data == null)
                throw new ArgumentNullException("data");
            list = new List<byte>(data.Length + 2);
            list.Add(SOX);
            foreach (byte b in data)
                if (b <= MaxByte)
                    list.Add(b);
            list.Add(EOX);
            list.TrimExcess();
        }

        public byte this[int index]
        {
            get { return list[index]; }
        }
        public int Count
        {
            get { return list.Count; }
        }

        public IEnumerator<byte> GetEnumerator()
        {
            return list.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            return list.GetEnumerator();
        }
        public byte[] ToArray()
        {
            return list.ToArray();
        }
    }

    #region Interop

    internal static class NativeMethods
    {
        public const int MAXPNAMELEN = 32;

        public const int MOD_MIDIPORT = 1;
        public const int MOD_SYNTH = 2;
        public const int MOD_SQSYNTH = 3;
        public const int MOD_FMSYNTH = 4;
        public const int MOD_MAPPER = 5;
        public const int MOD_WAVETABLE = 6;
        public const int MOD_SWSYNTH = 7;

        public const int MIDICAPS_VOLUME = 0x0001;
        public const int MIDICAPS_LRVOLUME = 0x0002;
        public const int MIDICAPS_CACHE = 0x0004;
        public const int MIDICAPS_STREAM = 0x0008;

        private const int MIDIERR_BASE = 64;
        public const int MMSYSERR_NOERROR = 0;
        public const int MIDIERR_STILLPLAYING = (MIDIERR_BASE + 1);

        public const int CALLBACK_FUNCTION = 0x00030000;

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798468(v=vs.85).aspx
        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutClose(IntPtr hmo);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798469(v=vs.85).aspx
        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutGetDevCaps(int uDeviceID, out MIDIOUTCAPS lpMidiOutCaps, int cbMidiOutCaps);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798472(v=vs.85).aspx
        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutGetNumDevs();

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798474(v=vs.85).aspx
        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutLongMsg(IntPtr hmo, IntPtr lpMidiOutHdr, int cbMidiOutHdr);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798476(v=vs.85).aspx
        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutOpen(out IntPtr lphmo, int uDeviceID, MidiOutProc dwCallback, IntPtr dwCallbackInstance, int dwFlags);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798477(v=vs.85).aspx
        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutPrepareHeader(IntPtr hmo, IntPtr lpMidiOutHdr, int cbMidiOutHdr);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798478(v=vs.85).aspx
        public delegate void MidiOutProc(IntPtr hmo, int wMsg, IntPtr dwInstance, IntPtr dwParam1, IntPtr dwParam2);

        // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798482(v=vs.85).aspx
        [DllImport("Winmm.dll", SetLastError = true)]
        public static extern int midiOutUnprepareHeader(IntPtr hmo, IntPtr lpMidiOutHdr, int cbMidiOutHdr);
    }

    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798467(v=vs.85).aspx
    [StructLayout(LayoutKind.Sequential)]
    internal struct MIDIOUTCAPS
    {
        public static readonly int Size = Marshal.SizeOf(typeof(MIDIOUTCAPS));

        private short wMid;
        private short wPid;
        private int vDriverVersion;
        [MarshalAs(UnmanagedType.ByValTStr, SizeConst = NativeMethods.MAXPNAMELEN)]
        private string szPname;
        private short wTechnology;
        private short wVoices;
        private short wNotes;
        private short wChannelMask;
        private int dwSupport;

        public int ManufacturerId
        {
            get { return wMid; }
        }
        public int ProductId
        {
            get { return wPid; }
        }
        public Version DriverVersion
        {
            get { return new Version((vDriverVersion >> 8) & 0xFF, vDriverVersion & 0xFF, 0, 0); }
        }
        public string Name
        {
            get { return szPname; }
        }
        public MidiOutputTechnology Technology
        {
            get { return (MidiOutputTechnology)wTechnology; }
        }
        public int Voices
        {
            get { return wVoices; }
        }
        public int Notes
        {
            get { return wNotes; }
        }
        public int ChannelMask
        {
            get { return wChannelMask & 0xFFFF; }
        }
        public MidiOutputSupport Support
        {
            get { return (MidiOutputSupport)dwSupport; }
        }
    }

    // http://msdn.microsoft.com/en-us/library/windows/desktop/dd798449(v=vs.85).aspx
    [StructLayout(LayoutKind.Sequential)]
    internal struct MIDIHDR
    {
        public static readonly int Size = Marshal.SizeOf(typeof(MIDIHDR));

        private IntPtr lpData;
        private int dwBufferLength; // keep this under 16KB
        private int dwBytesRecorded;
        private IntPtr dwUser;
        private int dwFlags;
        private IntPtr lpNext;
        private IntPtr reserved;
        private int dwOffset;
        private IntPtr dwReserved;

        public MIDIHDR(MidiSystemExclusiveMessage data)
        {
            // We need to get the bytes into unmanaged memory so the don't get moved
            IntPtr dataHandle = Marshal.AllocHGlobal(data.Count);
            Marshal.Copy(data.ToArray(), 0, dataHandle, data.Count);
            lpData = dataHandle;
            dwBufferLength = data.Count;
            dwBytesRecorded = data.Count;

            dwUser = IntPtr.Zero;
            dwFlags = 0;
            lpNext = IntPtr.Zero;
            reserved = IntPtr.Zero;
            dwOffset = 0;
            dwReserved = IntPtr.Zero;
        }

        public void Free()
        {
            Marshal.FreeHGlobal(lpData);
        }
    }

    #endregion Interop
}

Dave

Binging is like googling, it just feels dirtier.
Please take your VB.NET out of our nice case sensitive forum.
Astonish us. Be exceptional. (Pete O'Hanlon)

BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)



GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff7-Sep-12 1:36
Jumpin' Jeff7-Sep-12 1:36 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff7-Sep-12 12:42
Jumpin' Jeff7-Sep-12 12:42 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff7-Sep-12 15:04
Jumpin' Jeff7-Sep-12 15:04 
AnswerRe: C# MIDI controller interface. Pin
DaveyM697-Sep-12 22:07
professionalDaveyM697-Sep-12 22:07 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff8-Sep-12 15:18
Jumpin' Jeff8-Sep-12 15:18 
GeneralRe: C# MIDI controller interface. Pin
DaveyM699-Sep-12 0:03
professionalDaveyM699-Sep-12 0:03 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff10-Sep-12 1:49
Jumpin' Jeff10-Sep-12 1:49 
GeneralRe: C# MIDI controller interface. Pin
DaveyM6915-Sep-12 7:44
professionalDaveyM6915-Sep-12 7:44 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff15-Sep-12 8:58
Jumpin' Jeff15-Sep-12 8:58 
GeneralRe: C# MIDI controller interface. Pin
DaveyM6918-Sep-12 10:31
professionalDaveyM6918-Sep-12 10:31 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff19-Sep-12 5:57
Jumpin' Jeff19-Sep-12 5:57 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff28-Sep-12 9:19
Jumpin' Jeff28-Sep-12 9:19 
GeneralRe: C# MIDI controller interface. Pin
DaveyM6929-Sep-12 3:12
professionalDaveyM6929-Sep-12 3:12 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff29-Sep-12 9:42
Jumpin' Jeff29-Sep-12 9:42 
AnswerRe: C# MIDI controller interface. Pin
DaveyM6930-Sep-12 3:53
professionalDaveyM6930-Sep-12 3:53 
GeneralRe: C# MIDI controller interface. Pin
DaveyM697-Oct-12 2:42
professionalDaveyM697-Oct-12 2:42 
GeneralRe: C# MIDI controller interface. Pin
Jumpin' Jeff8-Oct-12 1:21
Jumpin' Jeff8-Oct-12 1:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.