1 module derelict.portmidi.portmidi;
2 
3 private {
4     import derelict.util.loader;
5     import derelict.util.system;
6 
7     static if(Derelict_OS_Windows)
8         enum libNames = "libPortMidi.dll";
9 
10     else static if(Derelict_OS_Mac)
11         enum libNames = "libportmidi.dylib, /usr/local/lib/libportmidi.dylib";
12 
13     else static if(Derelict_OS_Posix)
14         enum libNames = "libportmidi.so, /usr/local/lib/libportmidi.so";
15         
16     else
17         static assert(0, "Need to implement libportmidi libNames for this operating system.");
18 }
19 
20 enum int PM_DEFAULT_SYSEX_BUFFER_SIZE = 1024;
21 
22 enum int HDRLENGTH = 50;
23 enum uint PM_HOST_ERROR_MSG_LEN = 256;
24 enum int pmNoDevice = -1;
25 
26 enum {
27     PM_FILT_ACTIVE = (1 << 0x0E),
28     PM_FILT_SYSEX = (1 << 0x00),
29     PM_FILT_CLOCK = (1 << 0x08),
30     PM_FILT_PLAY = ((1 << 0x0A) | (1 << 0x0C) | (1 << 0x0B)),
31     PM_FILT_TICK = (1 << 0x09),
32     PM_FILT_FD = (1 << 0x0D),
33     PM_FILT_UNDEFINED = PM_FILT_FD,
34     PM_FILT_RESET = (1 << 0X0F),
35     PM_FILT_REALTIME = PM_FILT_ACTIVE | PM_FILT_SYSEX | PM_FILT_CLOCK |
36                         PM_FILT_PLAY | PM_FILT_UNDEFINED | PM_FILT_RESET | PM_FILT_TICK,
37 
38     PM_FILT_NOTE = ((1 << 0x19) | (1 << 0x18)),
39     PM_FILT_CHANNEL_AFTERTOUCH = (1 << 0x1D),
40     PM_FILT_POLY_AFTERTOUCH = (1 << 0x1A),
41     PM_FILT_AFTERTOUCH = PM_FILT_CHANNEL_AFTERTOUCH | PM_FILT_POLY_AFTERTOUCH,
42     PM_FILT_PROGRAM = (1 << 0x1C),
43     PM_FILT_CONTROL = (1 << 0x1B),
44     PM_FILT_PITCHBEND = (1 << 0x1E),
45     PM_FILT_MTC = (1 << 0x01),
46     PM_FILT_SONG_POSITION = (1 << 0x02),
47     PM_FILT_SONG_SELECT = (1 << 0x03),
48     PM_FILT_TUNE = (1 << 0x06),
49     PM_FILT_SYSTEMCOMMON = (PM_FILT_MTC | PM_FILT_SONG_POSITION | PM_FILT_SONG_SELECT | PM_FILT_TUNE)   
50 }
51 
52 alias PmError = int;
53 
54 enum : PmError {
55     pmNoError = 0,
56     pmHostError = -10000,
57     pmInvalidDeviceId,
58     pmInsufficientMemory,
59     pmBufferTooSmall,
60     pmBufferOverflow,
61     pmBadPtr,
62     pmBadData,
63     pmInternalError,
64     pmBufferMaxSize
65 }
66 
67 alias PortMidiStream = void;
68 alias PmStream = PortMidiStream;
69 alias PmDeviceID = int;
70 alias PmTimestamp = long;
71 alias PmMessage = long;
72 
73 //From pmutil.h
74 alias PmQueue = void;
75 
76 extern(C) nothrow alias PmTimeProcPtr = PmTimestamp* function(void* time_info);
77 
78 struct PmDeviceInfo {
79     int structVersion;
80     const char* interf;
81     const char* name;
82     int input;
83     int output;
84     int opened;
85 }
86 
87 struct PmEvent
88 {
89     PmMessage message;
90     PmTimestamp timestamp;
91 }
92 
93 //Replicates behavior of the following line in portmidi.h:
94 //#define PmBefore(t1,t2) ((t1-t2) < 0)
95 bool PmBefore(T)(T t1, T t2) {
96     return t1 - t2 < 0;
97 }
98 
99 //Replicates the behavior of the following line in portmidi.h:
100 //#define Pm_Channel(channel) (1<<(channel))
101 int Pm_Channel(int channel) {
102     return 1 << channel;
103 }
104 
105 //Replicates the Pm_Message* macros in portmidi.h
106 PmMessage Pm_Message(long status, long data1, long data2) {
107     return ((data2 << 16) & 0xff0000) | ((data1 << 8) & 0xff00) | (status & 0xff);
108 }
109 
110 long Pm_MessageStatus(PmMessage msg) {
111     return msg & 0xff;
112 }
113 
114 long Pm_MessageData1(PmMessage msg) {
115     return (msg >> 8) & 0xff;
116 }
117 
118 long Pm_MessageData2(PmMessage msg) {
119     return (msg >> 16) & 0xff;
120 }
121 
122 extern(C) @nogc nothrow {
123     alias da_Pm_Initialize = PmError function();
124     alias da_Pm_Terminate = PmError function();
125     alias da_Pm_HasHostError = int function(PortMidiStream* stream);
126     alias da_Pm_GetErrorText = const(char)* function(PmError errnum);
127     alias da_Pm_GetHostErrorText = const(char)* function(char* msg, uint len);
128     alias da_Pm_CountDevices = int function();
129     alias da_Pm_GetDefaultInputDeviceID = PmDeviceID function();
130     alias da_Pm_GetDefaultOutputDeviceID = PmDeviceID function();
131     alias da_Pm_GetDeviceInfo = const(PmDeviceInfo)* function(PmDeviceID id);
132 
133     alias da_Pm_OpenInput = PmError function(   PortMidiStream** stream,
134                                                 PmDeviceID inputDevice,
135                                                 void* inputDriverInfo,
136                                                 long bufferSize,
137                                                 PmTimeProcPtr time_proc,
138                                                 void* time_info);
139 
140     alias da_Pm_OpenOutput = PmError function(   PortMidiStream** stream,
141                                                 PmDeviceID outputDevice,
142                                                 void* outputDriverInfo,
143                                                 long bufferSize,
144                                                 PmTimeProcPtr time_proc,
145                                                 void* time_info,
146                                                 long latency);
147 
148     alias da_Pm_SetFilter = PmError function(PortMidiStream* stream, long filters);
149     alias da_Pm_SetChannelMask = PmError function(PortMidiStream* stream, int mask);
150     alias da_Pm_Abort = PmError function(PortMidiStream* stream);
151     alias da_Pm_Close = PmError function(PortMidiStream* stream);
152     alias da_Pm_Read = int function(PortMidiStream* stream, PmEvent* buffer, long length);
153     alias da_Pm_Poll = PmError function(PortMidiStream* stream);
154     alias da_Pm_Write = PmError function(PortMidiStream* stream, PmEvent* buffer, long length);
155     alias da_Pm_WriteShort = PmError function(PortMidiStream* stream, PmTimestamp when, long msg);
156     alias da_Pm_WriteSysEx = PmError function(PortMidiStream* stream, PmTimestamp when, ubyte* msg);
157 
158     //From pmutil.h
159     alias da_Pm_QueueCreate = PmQueue* function(long num_msgs, int bytes_per_msg);
160     alias da_Pm_QueueDestroy = PmError function(PmQueue* queue);
161     alias da_Pm_Dequeue = PmError function(PmQueue* queue, void* msg);
162     alias da_Pm_Enqueue = PmError function(PmQueue* queue, void* msg);
163     alias da_Pm_QueueFull = int function(PmQueue* queue);
164     alias da_Pm_QueueEmpty = int function(PmQueue* queue);
165     alias da_Pm_QueuePeek = void* function(PmQueue* queue);
166     alias da_Pm_SetOverflow = PmError function(PmQueue* queue);
167 }
168 
169 __gshared {
170     da_Pm_Initialize Pm_Initialize;
171     da_Pm_Terminate Pm_Terminate;
172     da_Pm_HasHostError Pm_HasHostError;
173     da_Pm_GetErrorText Pm_GetErrorText;
174     da_Pm_GetHostErrorText Pm_GetHostErrorText;
175     da_Pm_CountDevices Pm_CountDevices;
176     da_Pm_GetDefaultInputDeviceID Pm_GetDefaultInputDeviceID;
177     da_Pm_GetDefaultOutputDeviceID Pm_GetDefaultOutputDeviceID;
178     da_Pm_GetDeviceInfo Pm_GetDeviceInfo;
179     da_Pm_OpenInput Pm_OpenInput;
180     da_Pm_OpenOutput Pm_OpenOutput;
181     da_Pm_SetFilter Pm_SetFilter;
182     da_Pm_SetChannelMask Pm_SetChannelMask;
183     da_Pm_Abort Pm_Abort;
184     da_Pm_Close Pm_Close;
185     da_Pm_Read Pm_Read;
186     da_Pm_Poll Pm_Poll;
187     da_Pm_Write Pm_Write;
188     da_Pm_WriteShort Pm_WriteShort;
189     da_Pm_WriteSysEx Pm_WriteSysEx;
190 
191     //From pmutil.h
192     da_Pm_QueueCreate Pm_QueueCreate;
193     da_Pm_QueueDestroy Pm_QueueDestroy;
194     da_Pm_Dequeue Pm_Dequeue;
195     da_Pm_Enqueue Pm_Enqueue;
196     da_Pm_QueueFull Pm_QueueFull;
197     da_Pm_QueueEmpty Pm_QueueEmpty;
198     da_Pm_QueuePeek Pm_QueuePeek;
199     da_Pm_SetOverflow Pm_SetOverflow;
200 
201 }
202 
203 class DerelictPortMidiLoader : SharedLibLoader {
204     public this() {
205         super(libNames);
206     }
207     
208     protected override void loadSymbols() {
209         bindFunc(cast(void**)&Pm_Initialize, "Pm_Initialize");
210         bindFunc(cast(void**)&Pm_Terminate, "Pm_Terminate");
211         bindFunc(cast(void**)&Pm_HasHostError, "Pm_HasHostError");
212         bindFunc(cast(void**)&Pm_GetErrorText, "Pm_GetErrorText");
213         bindFunc(cast(void**)&Pm_GetHostErrorText, "Pm_GetHostErrorText");
214         bindFunc(cast(void**)&Pm_CountDevices, "Pm_CountDevices");
215         bindFunc(cast(void**)&Pm_GetDefaultInputDeviceID, "Pm_GetDefaultInputDeviceID");
216         bindFunc(cast(void**)&Pm_GetDefaultOutputDeviceID, "Pm_GetDefaultOutputDeviceID");
217         bindFunc(cast(void**)&Pm_GetDeviceInfo, "Pm_GetDeviceInfo");
218         bindFunc(cast(void**)&Pm_OpenInput, "Pm_OpenInput");
219         bindFunc(cast(void**)&Pm_OpenOutput, "Pm_OpenOutput");
220         bindFunc(cast(void**)&Pm_SetFilter, "Pm_SetFilter");
221         bindFunc(cast(void**)&Pm_SetChannelMask, "Pm_SetChannelMask");
222         bindFunc(cast(void**)&Pm_Abort, "Pm_Abort");
223         bindFunc(cast(void**)&Pm_Close, "Pm_Close");
224         bindFunc(cast(void**)&Pm_Read, "Pm_Read");
225         bindFunc(cast(void**)&Pm_Poll, "Pm_Poll");
226         bindFunc(cast(void**)&Pm_Write, "Pm_Write");
227         bindFunc(cast(void**)&Pm_WriteShort, "Pm_WriteShort");
228         bindFunc(cast(void**)&Pm_WriteSysEx, "Pm_WriteSysEx");
229 
230         //From pmutil.h
231         bindFunc(cast(void**)&Pm_QueueCreate, "Pm_QueueCreate");
232         bindFunc(cast(void**)&Pm_QueueDestroy, "Pm_QueueDestroy");
233         bindFunc(cast(void**)&Pm_Dequeue, "Pm_Dequeue");
234         bindFunc(cast(void**)&Pm_Enqueue, "Pm_Enqueue");
235         bindFunc(cast(void**)&Pm_QueueFull, "Pm_QueueFull");
236         bindFunc(cast(void**)&Pm_QueueEmpty, "Pm_QueueEmpty");
237         bindFunc(cast(void**)&Pm_QueuePeek, "Pm_QueuePeek");
238         bindFunc(cast(void**)&Pm_SetOverflow, "Pm_SetOverflow");
239     }
240 }
241 
242 __gshared DerelictPortMidiLoader DerelictPortMidi;
243 
244 shared static this() {
245     DerelictPortMidi = new DerelictPortMidiLoader;
246 }
247