I found it difficult when I first started trying MIDI programming to get any decent documentation or a simple snippet of code to turn MIDI notes on and off. This Delphi source code allows you to control the Windows MIDI notes from within a Delphi application. Create a new unit _midi.pas and copy and paste the code contents below into it.
{
Instructions:
1) Call OpenMidiOut before playing any notes - this can be inside form.oncreate
2) Call TurnOnMidiNote to start playing a note
This can be called multiple times for "simultaneous" notes
3) Add some sort of delay for the notes. ie sleep() etc
4) Call TurnOffMidiNote to stop playing all playing note(s)
5) When done, call CloseMidiOut to allow other apps to access the midi port - this can be inside form.ondestroy
For percussion instruments there are custom TurnOnMidiPercussionNote and TurnOffSingleMidiPercussionNote procedures.
See the end of this unit for a list of which note value maps to which percussion instrument.
}
unit _midi;
interface
uses Windows,Messages,SysUtils,Classes,Graphics,Controls,
Forms,Dialogs,StdCtrls,mmsystem,registry;
function MidiAvailable:boolean;
procedure OpenMidiOut(ParentForm:TForm);
procedure TurnOnMidiNote(Note,Instrument,Volume,Channel,Panning:byte);
procedure TurnOffSingleMidiNote(Note,Channel:byte);
procedure TurnOnMidiPercussionNote(Note, Volume, Panning: byte);
procedure TurnOffSingleMidiPercussionNote(Note: byte);
procedure TurnOffAllMidiNotes;
procedure CloseMidiOut;
var MidiOutDev:HMIDIOUT; //global handle to midi device
MidiOpen:boolean; //refer to this variable to see if a midi device is currently open
implementation
function MidiAvailable:boolean;
begin
If (midiOutGetNumDevs()=0) then MidiAvailable:=false
else MidiAvailable:=true;
end;
procedure OpenMidiOut(ParentForm:TForm);
begin
midiOutOpen(@MidiOutDev,MIDI_MAPPER,ParentForm.Handle,0,CALLBACK_WINDOW);
MidiOpen:=true;
end;
//note = 0-127 - see table at bottom for values
//inst = 0-127 - see table at bottom for values
//vol = 0-127
//chan = 0-15
//pan = 0-127 0=only left 63=both 127=only right
procedure TurnOnMidiNote(Note,Instrument,Volume,Channel,Panning:byte);
begin
//tell midi device which instrument or patch to use
midiOutShortMsg(MidiOutDev,MAKEWORD($C0 OR Channel,Instrument));
//panning
midiOutShortMsg(midioutdev,strtoint('$'+inttohex(panning,2)+'0AB'+inttohex(channel,1)));
//tell midi device what note to play
midiOutShortMsg(MidiOutDev,MAKELONG(MAKEWORD($90 or Channel,Note),MAKEWORD(Volume,0)));
end;
procedure TurnOffSingleMidiNote(Note,Channel:byte);
begin
//tell midi device what note to play
midiOutShortMsg(MidiOutDev,MAKELONG(MAKEWORD($80 or Channel,Note),MAKEWORD(0,0)));
end;
procedure TurnOnMidiPercussionNote(Note, Volume, Panning: byte);
begin
//percussion instruments are channel 9
TurnOnMidiNote(Note, 0, Volume, 9, Panning);
end;
procedure TurnOffSingleMidiPercussionNote(Note: byte);
begin
//percussion instruments are channel 9
TurnOffSingleMidiNote(Note, 9);
end;
procedure TurnOffAllMidiNotes;
begin
//Reset the midi device
midiOutReset(MidiOutDev);
end;
procedure CloseMidiOut;
begin
//Close the midi device so anyone else can use it
midiOutClose(MidiOutDev);
MidiOpen:=false;
end;
{
//integer to note mapping
Oct# C C# D D# E F F# G G# A A# B
-1 0 1 2 3 4 5 6 7 8 9 10 11
0 12 13 14 15 16 17 18 19 20 21 22 23
1 24 25 26 27 28 29 30 31 32 33 34 35
2 36 37 38 39 40 41 42 43 44 45 46 47
3 48 49 50 51 52 53 54 55 56 57 58 59
4 60 61 62 63 64 65 66 67 68 69 70 71
5 72 73 74 75 76 77 78 79 80 81 82 83
6 84 85 86 87 88 89 90 91 92 93 94 95
7 96 97 98 99 100 101 102 103 104 105 106 107
8 108 109 110 111 112 113 114 115 116 117 118 119
9 120 121 122 123 124 125 126 127
//midi instruments - these can be put in a combobox for easy selection
Acoustic Grand Piano
Bright Acoustic Piano
Electric Grand Piano
Honky-tonk Piano
Electric Piano 1
Electric Piano 2
Harpsichord
Clavi
Celesta
Glockenspiel
Music Box
Vibraphone
Marimba
Xylophone
Tubular Bells
Dulcimer
Drawbar Organ
Percussive Organ
Rock Organ
Church Organ
Reed Organ
Accordion
Harmonica
Tango Accordion
Acoustic Guitar (nylon)
Acoustic Guitar (steel)
Electric Guitar (jazz)
Electric Guitar (clean)
Electric Guitar (muted)
Overdriven Guitar
Distortion Guitar
Guitar harmonics
Acoustic Bass
Electric Bass (finger)
Electric Bass (pick)
Fretless Bass
Slap Bass 1
Slap Bass 2
Synth Bass 1
Synth Bass 2
Violin
Viola
Cello
Contrabass
Tremolo Strings
Pizzicato Strings
Orchestral Harp
Timpani
String Ensemble 1
String Ensemble 2
SynthStrings 1
SynthStrings 2
Choir Aahs
Voice Oohs
Synth Voice
Orchestra Hit
Trumpet
Trombone
Tuba
Muted Trumpet
French Horn
Brass Section
SynthBrass 1
SynthBrass 2
Soprano Sax
Alto Sax
Tenor Sax
Baritone Sax
Oboe
English Horn
Bassoon
Clarinet
Piccolo
Flute
Recorder
Pan Flute
Blown Bottle
Shakuhachi
Whistle
Ocarina
Lead 1 (square)
Lead 2 (sawtooth)
Lead 3 (calliope)
Lead 4 (chiff)
Lead 5 (charang)
Lead 6 (voice)
Lead 7 (fifths)
Lead 8 (bass + lead)
Pad 1 (new age)
Pad 2 (warm)
Pad 3 (polysynth)
Pad 4 (choir)
Pad 5 (bowed)
Pad 6 (metallic)
Pad 7 (halo)
Pad 8 (sweep)
FX 1 (rain)
FX 2 (soundtrack)
FX 3 (crystal)
FX 4 (atmosphere)
FX 5 (brightness)
FX 6 (goblins)
FX 7 (echoes)
FX 8 (sci-fi)
Sitar
Banjo
Shamisen
Koto
Kalimba
Bag pipe
Fiddle
Shanai
Tinkle Bell
Agogo
Steel Drums
Woodblock
Taiko Drum
Melodic Tom
Synth Drum
Reverse Cymbal
Guitar Fret Noise
Breath Noise
Seashore
Bird Tweet
Telephone Ring
Helicopter
Applause
Gunshot
//percussion instruments
//note these are referenced starting at index 35 so if you
//use a combobox read it by combobox.itemindex+35 to get the correct
//integr to instrument mapping
35 Acoustic Bass Drum
36 Bass Drum 1
37 Side Stick
38 Acoustic Snare
39 Hand Clap
40 Electric Snare
41 Low Floor Tom
42 Closed Hi Hat
43 High Floor Tom
44 Pedal Hi-Hat
45 Low Tom
46 Open Hi-Hat
47 Low-Mid Tom
48 Hi Mid Tom
49 Crash Cymbal 1
50 High Tom
51 Ride Cymbal 1
52 Chinese Cymbal
53 Ride Bell
54 Tambourine
55 Splash Cymbal
56 Cowbell
57 Crash Cymbal 2
58 Vibraslap
59 Ride Cymbal 2
60 Hi Bongo
61 Low Bongo
62 Mute Hi Conga
63 Open Hi Conga
64 Low Conga
65 High Timbale
66 Low Timbale
67 High Agogo
68 Low Agogo
69 Cabasa
70 Maracas
71 Short Whistle
72 Long Whistle
73 Short Guiro
74 Long Guiro
75 Claves
76 Hi Wood Block
77 Low Wood Block
78 Mute Cuica
79 Open Cuica
80 Mute Triangle
81 Open Triangle
}
end.
This allows single or multiple notes to be played. Using these simple commands (all based on the mmsystem.pas unit that talks to the windows MMSYSTEM.DLL) is how I handled all the MIDI in GBK.
The unit now also contains support for the percussion instruments on MIDI channel 9 thanks to CM in the comments.
This code should also work with FPC/Lazarus.
Hopefully this helps anyone who is looking for a simple way to get MIDI support into their Delphi application.
Jason.