MIDI on Windows

Author: Donya Quick
Last modified: 31-Dec-2015

Note: this page is intended specifically for Euterpea 1.1.1. If you are not using Euterpea or are using a later version of it, please see one of the following pages instead:

Windows 10 users: please see the notes at the section at the bottom of this page for information on getting playback to work.


 

Introduction

Working with MIDI on Windows can be a tricky thing when one wants to go beyond simply playing MIDI files and using the play and test functions in Euterpea. Four topics are covered here:

 

Getting MIDI Output

Usually Windows comes with a default MIDI synthesizer that will show up as the default MIDI output device. However, if you are unable to use Euterpea’s “play” function due to lack of a MIDI output device (which is rare, but nevertheless possible), you can use the solutions later on this page for minimizing playback latency via another synthesizer or you can use this version of JavaOx, a small program that routs MIDI messages and allows the user to send to Java’s on synthesizer. To run JavaOx, you will need a Java Runtime Environment. You will also need a virtual MIDI port such as LoopBe1. You can then define a custom function to play to this port as follows:


> import Euterpea.ExperimentalPlay
> import Euterpea.IO.MIDI.MidiIO
...
> playDev :: (Performable a, NFData a) => Int -> Music a -> IO ()
> playDev dev = playC defParams{devID = Just $ unsafeOutputID dev}

where x is the device ID number as shown by the devices :: IO () function – run it in GHCi to list all available MIDI devices and their numbers. You can then set JavaOx to take input from the virtual MIDI port and send it to Gervill, which is Java’s synthesizer. Note that this approach is simple, but it will not give you low latency. In fact, the latency will be about as bad as when using the the Microsoft synthesizer that is typically bundled with Windows. If you need low latency solutions, skip to the section on Minimizing Playback Latency.

For the best possible timing during playback of finite Music values, you may also wish to use the strict option in the arguments to playC:

> playDev :: (Performable a, NFData a) => Int -> Music a -> IO ()
> playDev dev = playC defParams{devID = Just $ unsafeOutputID dev, strict=True}

However, be aware that this will hang on infinite values, since the Music value is evaluated fully before attempting playback.

 

Getting MIDI Input

Windows comes with a MIDI synthesizer, the Microsoft GS Wavetable Synth. This synthesizer allows the playback of MIDI files and will play any MIDI events streamed to it in real-time (albeit with horrible lag, which will be addressed later). However, there is no way to take input from this synthesizer, and there are no other MIDI input devices by default. Many modern MIDI hardware devices that connect by USB, such as small keyboards, will show up as a MIDI input device once installed. However, there are also software alternatives that allow for MIDI input from a virtual keyboard. One software-only solution is to do the following:

  1. Install a virtual MIDI port like LoopBe1 (1 port) or LoopMIDI (multiple ports possible). Let’s call this virtual port Port1.
  2. Install a virtual MIDI keyboard like Proxima Controller.
  3. To be totally safe and minimize troubleshooting, reboot before you try any MIDI I/O, even if it looks like it should work.
  4. Set the virtual keyboard (Proxima Controller) to send output to Port1.
  5. In your primary program of interest, such as a Euterpea MUI, you can now take input from Port1 and send output to the MS Wavetable Synth.

This will allow basic MIDI I/O. However, you will hear a noticeable delay between pressing a key in a program like Proxima Controller (or on a hardware keyboard for that matter) and hearing any output, even if sending events directly to the MS Wavetable Synth rather than through a virtual MIDI port first.

You only need one virtual port for taking input. LoopBe1 givese you a single port that is very easy to use and automatically runs in the background when Windows starts; it is the easiest solution for anything requiring only one port. LoopMIDI allows more ports, which can be necessary for achieving low-latency MIDI I/O as described later on, but you have to set up the ports manually and specify whether you want it to auto-start. Note: when using a virtual MIDI port, make sure that you don’t set the port to send and receive from itself. With LoopBe1, you will get a feedback error and the program will mute itself (which has to be fixed via the icon in the system tray).

Minimizing Playback Latency

The MS Wavetable synth often exhibits a delay of 100ms or more between the time an event is sent and when any sound starts. The delay is quite noticable on most machines. Unfortunately, there is no way to fix the latency with that synth. The only way to lower MIDI I/O latency without a hardware synthesizer is to get a different software synth that gives you some control over the audio drivers it uses – which must be low-latency drivers. Getting a different synth is pretty easy, since there are some good freeware/shareware programs for it, namely SFZ, SFZ+ (which is free, but you have to sign up and then “buy” it as a $0 product), CoolSoft’s VirtualMIDISynth, and SyFonOne.

All of those programs make use of a virtual instrument format called SoundFonts, or sf2, which was developed by Creative Labs. An sf2 file is a collection of instruments mapped to different patch numbers. Because sf2 files can be quite large, they are often stored in the compressed sfark format. SyFonOne comes with a sample sf2 file, but SFZ and SFZ+ do not. You can get some sf2 files from HERE. Some PCI/PCIe sound cards have built-in support for sf2 and can provide low-latency playback without the use of additional software synthesizers (the current list of compatible devices is at the bottom of this page).

The driver situation is more complicated, since programs like SFZ/SFZ+ and SyFonOne require ASIO drivers for good performance (ASIO = Audio Stream I/O, a particular protocol), and on-board sound almost never comes with that type of driver. Most high-end audio interfaces have ASIO or other low-latency drivers. For example, the M-Audio FastTrack series and the Tascam US series audio interfaces come with their own ASIO drivers. Some cheaper options like the Behringer U-Control series also support ASIO.

There is also a nice program called ASIO4All that will work with the synths described so far and any audio device with WDM drivers (present on most Windows machines). This program gives very good performance even with on-board sound in the absence of an expensive audio rig. However, it has one significant limitation: it requires exclusive use of an audio device. So, for example, you can’t use ASIO4All with a software synth at the same time as playing something in Windows Media Player if you only have one audio device. Still, ASIO4All is one of the easiest options for achieving better playback latency without extra hardware, and it is only problematic in special cases where a device has to be shared between several programs simultaneously. This limitation is not unique to ASIO4All, and some low-latency audio interfaces are also single-client. The ASIO Multiclient Wrapper is one option to achieve multi-client playback in these situations.

Here is an example setup using ASIO4All:

  1. Install a virtual MIDI port as described in the previous section. We’ll call it Port2.
  2. Install ASIO4All.
  3. Install SyFonOne and reboot.
  4. Open SyFonOne, tick the ASIO box under the options window (sometimes it’s a good idea to actually close SyFonOne after this change and open it again), take input from Port2 and hit “play.”
  5. Send MIDI events to Port2 to hear playback. In a Euterpea MUI, Port2 should be the output device.

You may need to fiddle with the settings in ASIO4All for a few minutes if it fails to have the correct things enabled and disabled the first time it runs. The devices usually have ambiguous names like “HD Output 1,” so it can be hard to know what should be on/off on some systems when there are multiple devices listed.

NOTE: see how Port2 already has something sending to it and receiving from it in the setup above? This means that you can’t use it to do MIDI input as well from other software like Proxima Controller. If you need to do MIDI input from such a program and have low latency with the method described above, then you need to use a multi-port option like LoopMIDI, since LoopBe1 will not let you do all of those things simultaneously.

Another solution for this issue if you have a hardware MIDI interface with its own ASIO drivers is to have one virtual MIDI port (like LoopBe1) and one MIDI cable that sends from the hardware interface back into itself. The hardware interface should show up as an input and output device, so you can send from ProximaController to a MUI with a virtual port and then send from the MUI to a synth with the hardware interface (or similarly with the virtual and hardware ports reversed). Connecting a device to itself may seem like an ugly hack, but the performance can actually be really good.

So, what about hardware that has low-latency drivers that aren’t ASIO? Some systems have WDM or MME drivers that really can perform well. If you know that your hardware should be capable of good performance with the drivers it has, then you can use JACK to trick programs like the soft-synths described above into using your non-ASIO drivers anyway. JACK wraps your existing drivers and presents an ASIO interface to other software. If you want to do this, you can set up JACK as follows:

  1. Install JACK and reboot. Then, open the Jack Control executable.
  2. Under the Setup window’s options, you want the server prefix to be “jackd -S”, the driver to be “portaudio”, and the interface to be your driver of choice. Save the settings and close the setup window but don’t close the main window.
  3. Start the audio server with the “Start” button. You will need to keep this running while you use your soft-synth. Your synth may crash if JACK is closed before the synth is. If JACK crashes or gives an error when you try to start the server, check that there are no other programs trying to use the same audio device.
  4. Open your soft-synth and you should now see JACK (by the name JackRouter) as an ASIO option.

Setting the Default MIDI Output Device

Windows XP: easy! Go into the recording and playback devices and select the option you want.

Windows Vista and 7: the XP option no longer exists, but the functionality does. There are several tools out there for doing this, such as PLW MIDI Mapper and Vista MIDI. Both actually work on Windows 7 as well as Vista despite their names, but you may need to run the programs as an administrator and/or reboot before the changes will take effect.

Windows 8, 8.1, and 10: sorry, but you are most likely out of luck for setting the default synthesizer within Windows. CoolSoft’s VirtualMIDISynth lets you set the default output for WindowsMediaPlayer on Windows 8/8.1, but there is currently no more general solution than that. Default MIDI output devices can only be changed within software that allows such a setting, like a DAW or a Euterpea MUI that uses the selectOutput widget. Note: this does NOT mean that you cannot set a different synthesizer within other software packages. Most music software lets you do this unless it is quite old (such as pre-WinXP). If you have software like Sibelius, Finale, Cakewalk, Cubase, etc., you can definitely set the default output but you have do it within the program rather than via Windows settings. Euterpea also has support for device-specific playback as described further up on this page.

Playback on Windows 10

For Euterpea users, the “play” function may not work on Windows 10 without installing some extra software. There appear to be known problems with the default synth on Windows 10 that may be related to or even the underlying cuase of Euterpea’s “play” problem. Doing a Windows Update may also correct the issue, as the problem appears to no longer exist with fresh installations as of December, 2015.

However, if “play” does not work for you, the easiest solution is to install Coolsoft’s VirtualMIDISynth (make sure you get the latest version). Installing this synth should allow the “play” function to work correctly. The Coolsoft synth also becomes an output device option for MUIs and is configurable to have much lower latency than the default Windows synth, making it a useful tool even aside from bug fixes.

Alternatively, if you have another synthesizer and a virtual MIDI port installed, you can use the “devices” function in Euterpea.ExperimentalPlay to look up device numbers and then play to something other than the defaults (which are usually the MS Wavetable Synth or MS MIDI Mapper) with the following:


> module PlayDev where
> import Euterpea
> import Euterpea.ExperimentalPlay
> import Euterpea.IO.MIDI.MidiIO
> playDev x = playC defParams{devID=Just$unsafeOutputID x}

where x is the number of the device you wish to send MIDI output to.

Comments are closed.