English 中文(简体)
Getting signals from a MIDI port in C#
原标题:
  • 时间:2010-01-02 10:12:17
  •  标签:
  • c#
  • midi

I bought a MIDI keyboard for my birthday. I found a program (MidiPiano) that gets signals from the MIDI input and translates it into music, but I d rather like to write one myself.

Where can I find documentation for doing such a task? The MIDI protocol is well documented, but not the MIDI ports.

I checked two projects from CodeProject (Project MIDI and C# MIDI Toolkit), but spent many hours without getting close to my goal.

A reference to a project will be fine, but please, only C#.

问题回答

You need to wrap all the needed functions listed at http://msdn.microsoft.com/en-us/library/dd757277(VS.85).aspx

It s not too difficult if you re just using short messages, things get a little more complicated if you want to do SysEx or output streaming.

All you need for a basic input Port is to get the valid input IDs (InputCount -1), pass a valid ID to Open, Start the input, receive the messages via a delegate... Stop the input and then finally close it. This is a very rough example of how this could be acheived - you will need to do some checking and be careful that the Port isn t collected before it s closed and the closed callback has happened or you will freeze your system!

Good luck!

namespace MIDI
{
    public class InputPort
    {
        private NativeMethods.MidiInProc midiInProc;
        private IntPtr handle;

        public InputPort()
        {
            midiInProc = new NativeMethods.MidiInProc(MidiProc);
            handle = IntPtr.Zero;
        }

        public static int InputCount
        {
            get { return NativeMethods.midiInGetNumDevs(); }
        }

        public bool Close()
        {
            bool result = NativeMethods.midiInClose(handle) 
                == NativeMethods.MMSYSERR_NOERROR;
            handle = IntPtr.Zero;
            return result;
        }

        public bool Open(int id)
        {
            return NativeMethods.midiInOpen(
                out handle,
                id,
                midiInProc,
                IntPtr.Zero,
                NativeMethods.CALLBACK_FUNCTION)
                    == NativeMethods.MMSYSERR_NOERROR;
        }

        public bool Start()
        {
            return NativeMethods.midiInStart(handle)
                == NativeMethods.MMSYSERR_NOERROR;
        }

        public bool Stop()
        {
            return NativeMethods.midiInStop(handle)
                == NativeMethods.MMSYSERR_NOERROR;
        }

        private void MidiProc(IntPtr hMidiIn,
            int wMsg,
            IntPtr dwInstance,
            int dwParam1,
            int dwParam2)
        {
            // Receive messages here
        }
    }

    internal static class NativeMethods
    {
        internal const int MMSYSERR_NOERROR = 0;
        internal const int CALLBACK_FUNCTION = 0x00030000;

        internal delegate void MidiInProc(
            IntPtr hMidiIn,
            int wMsg,
            IntPtr dwInstance,
            int dwParam1,
            int dwParam2);

        [DllImport("winmm.dll")]
        internal static extern int midiInGetNumDevs();

        [DllImport("winmm.dll")]
        internal static extern int midiInClose(
            IntPtr hMidiIn);

        [DllImport("winmm.dll")]
        internal static extern int midiInOpen(
            out IntPtr lphMidiIn,
            int uDeviceID,
            MidiInProc dwCallback,
            IntPtr dwCallbackInstance,
            int dwFlags);

        [DllImport("winmm.dll")]
        internal static extern int midiInStart(
            IntPtr hMidiIn);

        [DllImport("winmm.dll")]
        internal static extern int midiInStop(
            IntPtr hMidiIn);
    }
}

I m just in developing process of c# midi communication system. Sanford s midi toolkit is good but Leslie implementation has many improvement which makes code less readable. My code is as simple as possible. If you want you can join me. In a few days I publish fully working midi monitor. Just look at http://puremidi.codeplex.com/

I couldn t find much either, but like Josh says, Carl has definitely done quite a bit of work on MIDI, so maybe give him an email... he may even reply, but he is typically a VB.Net guy so unless someone has ported his stuff to C#?

For some other references that looked promising...

If you are looking for a pure C# solution... have a look at Alvas.Audio. It does look a bit high end for what you are asking, but may be of some help.

Also maybe project midi

With DryWetMIDI you can get events from a MIDI port with this code:

namespace InputDeviceExample
{
    class Program
    {
        private static IInputDevice _inputDevice;

        static void Main(string[] args)
        {
            _inputDevice = InputDevice.GetByName("Some MIDI device");
            _inputDevice.EventReceived += OnEventReceived;
            _inputDevice.StartEventsListening();

            Console.WriteLine("Input device is listening for events. Press any key to exit...");
            Console.ReadKey();

            (_inputDevice as IDisposable)?.Dispose();
        }

        private static void OnEventReceived(object sender, MidiEventReceivedEventArgs e)
        {
            var midiDevice = (MidiDevice)sender;
            Console.WriteLine($"Event received from  {midiDevice.Name}  at {DateTime.Now}: {e.Event}");
        }
    }
}

You can find more info in the Devices section of the library docs.

Use the C# Midi Toolkit to receive the midi information from your keyboard (connected to the midi in-port of you audio card). To create audio (music or tones) you need to generate a continues stream of digital audio data. You could start with the C# Synth Toolkit (same author as the midi toolkit) to write your own synth.

But you could also download a free (open source) sequencer program (audacity for instance) and use VST instrument plugins to do the job for you. There are a lot of free plugins available on the web.

I have solved this in a roundabout way by writing a Python script to transmit a UDP packet every time a note ON/OFF occurs on the MIDI keyboard.

MIDI over TCP/IP/UDP to be received inUnity3D with C#/.NET

That way the platform specific MIDI stuff is wrapped, and I can write platform agnostic C# code to pick up the UDP packet.





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签