MIDI

A version of this page is also available for

Windows Embedded CE 6.0 R3

4/8/2010

The following table shows the MIDI capabilities that are supported.

Capability Description

Instruments

Sine wave generation, no other instruments.

Polyphony

No limit on the number of midi streams. Number of concurrent notes per stream limited by the capabilities of the driver, and is set to 32 for all sample drivers.

In practice, the total number of notes will be limited by the power of the CPU. Most devices should be capable of playing eight to ten notes concurrently.

Messages

Only note on, note off, and all notes off.

Timing

Sample accurate.

Extensions

Supports arbitrary frequency tone generation and tempo changes.

The waveform audio API supports MIDI through the WAVE_FORMAT_MIDI wave format. To play MIDI notes, open the waveform audio device by calling the function waveOutOpen and providing a pointer to a WAVEFORMAT_MIDI structure and casting it to a WAVEFORMATEX structure. Use the value WAVE_FORMAT_MIDI to identify that the data being sent is MIDI data.

You then start passing buffers to the driver using waveOutWrite, just as you would for regular waveform audio data. Send MIDI data to the driver in a buffer that consists of an array of WAVEFORMAT_MIDI_MESSAGE structures.

The waveform audio driver will automatically take care of the timing and sequencing for each MIDI message. This approach should be satisfactory for most applications. If, however, you find that you need to do your own MIDI sequencing, then you can send MIDI messages directly to the audio driver by calling waveOutMessage and sending the deprecated message MM_MOM_MIDIMESSAGE. The driver handles MIDI messages send with MM_MOM_MIDIMESSAGE as soon as they are received. This means that the application is the sole source of timing and sequencing control for all MIDI messages sent in this way, which can be difficult to implement.

Code Example

The following code shows an application that plays a simple scale of eight MIDI notes.

#define DEFINE_GUIDS 1
#include "windows.h"
#include "stdio.h"
#include "wfmtmidi.h"

unsigned char Scale[8] = {63,65,67,68,70,72,74,75};
HANDLE hEvent;

void CALLBACK waveOutProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance,
                          DWORD dwParam1, DWORD dwParam2){
    if (uMsg==WOM_DONE){
        SetEvent(hEvent);
    }
    return;
}

int _tmain(int argc, TCHAR *argv[]) {
    // Code to play a simple 8-note scale.

    // Create an event to signal when playback is done
    hEvent=CreateEvent( NULL,TRUE,FALSE,NULL);

    // Build a MIDI waveformat header
    WAVEFORMAT_MIDI wfm;
    memset(&wfm,0,sizeof(wfm));
    wfm.wfx.wFormatTag=WAVE_FORMAT_MIDI;
    wfm.wfx.nChannels=1;
    wfm.wfx.nBlockAlign=sizeof(WAVEFORMAT_MIDI_MESSAGE);
    wfm.wfx.cbSize=WAVEFORMAT_MIDI_EXTRASIZE;

    // These fields adjust the interpretation of DeltaTicks,
    // and thus the rate of playback
    wfm.USecPerQuarterNote=1000000;   // Set to 1 second. Note driver
                                      // will default to 500000 if we set
                                      // this to 0
    wfm.TicksPerQuarterNote=100;      // Set to 100. Note driver will
                                      // default to 96 if we set this to 0
    MMRESULT Result;
    HWAVEOUT hWaveOut;

    // Open the waveout device
    Result = waveOutOpen(&hWaveOut, WAVE_MAPPER, (LPWAVEFORMATEX)&wfm,
                         (DWORD)waveOutProc, 0, CALLBACK_FUNCTION);

    if (Result!=MMSYSERR_NOERROR){
        return -1;
    }

    // Build a MIDI buffer with 16 MIDI messages.
    int i,j;
    WAVEFORMAT_MIDI_MESSAGE MidiMessage[16];
    for (i=0,j=0;i<8;i++,j+=2) {
        // Wait 1 second : 
        // (DeltaTicks * (UsecPerQuarterNote / TicksPerQuarterNote))
        MidiMessage[j].DeltaTicks=100;      
        MidiMessage[j].MidiMsg=0x1F0090 | ((Scale[i])<<8);   // Note on
        MidiMessage[j+1].DeltaTicks=100;                // Wait 1 second
        MidiMessage[j+1].MidiMsg=0x1F0080 | ((Scale[i])<<8); // Note off
    }

    WAVEHDR WaveHdr;
    WaveHdr.lpData = (LPSTR)&MidiMessage;
    WaveHdr.dwBufferLength = sizeof(MidiMessage);
    WaveHdr.dwFlags = 0;
    Result = waveOutPrepareHeader(hWaveOut,&WaveHdr,sizeof(WaveHdr));

    // Play the data
    Result = waveOutWrite(hWaveOut,&WaveHdr,sizeof(WaveHdr));

    // Wait for playback to complete
    WaitForSingleObject(hEvent,INFINITE);

    // Cleanup
    Result = waveOutUnprepareHeader(hWaveOut,&WaveHdr,sizeof(WaveHdr));
    Result = waveOutClose(hWaveOut);
    return 0;
}

See Also

Concepts

Using the Waveform Audio Interface