6

I'm trying to build simple software to connect to a MIDI Output device on Windows in Unity and send MIDI data.

As to avoid re-inventing the wheel, I started with the use of the C# Midi Toolkit on CodeProject built with support for .NET 2.0.

The issue I'm having is that it works fine in the Unity editor but then fails in the standalone Windows build.

Here is the basic connection/play sound code:

    // Log devices
    int deviceCount = OutputDevice.DeviceCount;
    for (int i = 0; i < deviceCount; i++)
    {
        Debug.Log(string.Format("Detected MIDI Device with ID {0}:{1}", i, OutputDevice.GetDeviceCapabilities(i).name));
    }
    deviceID = 1;
    Debug.Log(string.Format("Connected to {0}", deviceID));
    // Connect to device
    device = new OutputDevice(deviceID);
    // Play Middle C
    device.Send(new ChannelMessage(ChannelCommand.NoteOn, 0, note, 127));

And in the standalone build I get the following exception:

OutputDeviceException: The specified device handle is invalid.

I looked through the source and noticed that the library is using Win32 handles to winmm.dll, I figured this might have something to do with it but not certain where to go from here.

Can anyone provide any insight in how to approach this? I'll probably look at alternatives built specifically for Unity but I'm interested in learning why something like this wouldn't work in the first place.

Naxin
  • 376
  • 2
  • 18
  • why do you use `deviceID = 1` it looks like examples are using 0 – Iłya Bursov Feb 28 '18 at 06:05
  • 0 is the Microsoft GS Wavetable Synth, I'm trying to connect to a seperate loopback MIDI Interface with the device ID of 1. Confirmed to be the case in standalone and editor using the logging code you see at the top – Naxin Feb 28 '18 at 06:10
  • Which statement fails? – CL. Feb 28 '18 at 08:06
  • The constructor for OutputDevice, which is where the library I'm using also attempts a connection to the device ID provided – Naxin Feb 28 '18 at 12:22
  • 1
    Have you tried using NAudio? – Shimmy Weitzhandler Mar 04 '18 at 10:08
  • No way! I'm already using NAudio in this project but didn't realise it had MIDI output capabilities. This question is more about learning why this approach hasn't worked but thanks for giving me a simple solution to the bigger problem :) – Naxin Mar 04 '18 at 10:18

2 Answers2

1

I don't know if this kind of problem, but the x86 definition of midiOutOpen function that this old codeproject code uses (OutputDevice.cs) is

[DllImport("winmm.dll")]
 50          private static extern int midiOutOpen(ref int handle, int deviceID,
 51              MidiOutProc proc, int instance, int flags);

While on Pinvoke I can find this definition:

[DllImport("winmm.dll")]
        static extern uint midiOutOpen(out IntPtr lphMidiOut, uint uDeviceID, IntPtr dwCallback, IntPtr dwInstance, uint dwFlags);

Maybe it is a platform problem.

anefeletos
  • 672
  • 7
  • 19
  • Very interesting, so you're suggesting the old Code Project example may have been built for an older Windows with different winmm.dll? I was testing this on Windows 10. – Naxin Oct 10 '18 at 00:05
  • It is the new x64 / x86 implementation with IntPtr. – anefeletos Oct 12 '18 at 12:12
0

You can take a look at how it's implemented in DryWetMIDI, for example: Output device.

Usage:

using Melanchall.DryWetMidi.Devices;
using Melanchall.DryWetMidi.Core;

// ...

using (var outputDevice = OutputDevice.GetByName("Output device")) // or GetById(1)
{
    outputDevice.SendEvent(new NoteOnEvent());
}
Maxim
  • 1,995
  • 1
  • 19
  • 24