1 module wasapi.midi;
2 
3 version(Windows):
4 
5 import core.sys.windows.mmsystem;
6 import wasapi.comutils;
7 
8 class MidiOutDeviceDesc {
9     uint index;
10     string name;
11     uint technology;
12     ushort channelMask;
13 
14     MidiOutDevice open() {
15         MidiOutDevice res = new MidiOutDevice(this);
16         if (!res.open())
17             return null;
18         return res;
19     }
20 }
21 
22 class MidiOutDevice {
23     private HMIDIOUT handle;
24     private MIDIHDR hdr;
25     protected MidiOutDeviceDesc desc;
26     protected bool closed = true;
27     protected bool hdrPrepared;
28     protected this(MidiOutDeviceDesc desc) {
29         this.desc = desc;
30     }
31     void sendEvent(ubyte b1) {
32         midiOutShortMsg(handle, b1);
33     }
34     void sendEvent(ubyte b1, ubyte b2) {
35         midiOutShortMsg(handle, b1 | (cast(uint)b2 << 8));
36     }
37     void sendEvent(ubyte b1, ubyte b2, ubyte b3) {
38         midiOutShortMsg(handle, b1 | (cast(uint)b2 << 8) | (cast(uint)b3 << 16));
39     }
40     void sendEvent(ubyte b1, ubyte b2, ubyte b3, ubyte b4) {
41         midiOutShortMsg(handle, b1 | (cast(uint)b2 << 8) | (cast(uint)b3 << 16) | (cast(uint)b4 << 24));
42     }
43     protected bool open() {
44         if (midiOutOpen(&handle, desc.index, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR)
45             return false;
46         closed = false;
47         if (midiOutPrepareHeader(handle, &hdr, MIDIHDR.sizeof) != MMSYSERR_NOERROR) {
48             close();
49             return false;
50         }
51         hdrPrepared = true;
52         return true;
53     }
54     void close() {
55         if (closed)
56             return;
57         if (handle) {
58             if (hdrPrepared) {
59                 midiOutUnprepareHeader(handle, &hdr, MIDIHDR.sizeof);
60                 hdrPrepared = false;
61             }
62             midiOutReset(handle);
63             midiOutClose(handle);
64             handle = null;
65         }
66         closed = true;
67     }
68     ~this() {
69         close();
70     }
71 }
72 
73 immutable uint DEFAULT_MIDI_DEVICE = uint.max;
74 
75 class MidiProvider {
76     @property uint inputDevCount() {
77         return midiInGetNumDevs();
78     }
79     @property uint outDevCount() {
80         return midiOutGetNumDevs();
81     }
82 
83     MidiOutDeviceDesc getOutputDevice(uint index = DEFAULT_MIDI_DEVICE) {
84         import std.utf;
85         if (index == DEFAULT_MIDI_DEVICE)
86             index = MIDI_MAPPER;
87         MIDIOUTCAPS caps;
88         if (midiOutGetDevCaps(index, &caps, MIDIOUTCAPS.sizeof) != MMSYSERR_NOERROR)
89             return null;
90         MidiOutDeviceDesc res = new MidiOutDeviceDesc();
91         res.index = index;
92         res.name = fromWstringz(caps.szPname.ptr).toUTF8;
93         res.technology = caps.wTechnology;
94         res.channelMask = caps.wChannelMask;
95         return res;
96     }
97 }
98