aboutsummaryrefslogtreecommitdiff
path: root/portmidi/pm_haiku
diff options
context:
space:
mode:
Diffstat (limited to 'portmidi/pm_haiku')
-rw-r--r--portmidi/pm_haiku/pmhaiku.cpp473
1 files changed, 473 insertions, 0 deletions
diff --git a/portmidi/pm_haiku/pmhaiku.cpp b/portmidi/pm_haiku/pmhaiku.cpp
new file mode 100644
index 0000000..0c592f1
--- /dev/null
+++ b/portmidi/pm_haiku/pmhaiku.cpp
@@ -0,0 +1,473 @@
1/* pmhaiku.cpp -- PortMidi os-dependent code */
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <vector>
6#include <MidiConsumer.h>
7#include <MidiEndpoint.h>
8#include <MidiProducer.h>
9#include <MidiRoster.h>
10#include <MidiSynth.h>
11#include "portmidi.h"
12#include "pmutil.h"
13#include "pminternal.h"
14
15namespace {
16 struct PmInputConsumer : BMidiLocalConsumer {
17 PmInputConsumer(PmInternal *midi) :
18 BMidiLocalConsumer("PortMidi input consumer"),
19 midi(midi)
20 {
21 }
22
23
24 void Data(uchar *data, size_t length, bool atomic, bigtime_t time)
25 {
26 if (!atomic)
27 return; // should these be also supported?
28
29 if (data[0] == B_SYS_EX_START) {
30 pm_read_bytes(midi, data, length, time / 1000);
31 } else {
32 PmEvent event;
33 switch (length) {
34 case 1:
35 event.message = Pm_Message(data[0], 0, 0);
36 break;
37 case 2:
38 event.message = Pm_Message(data[0], data[1], 0);
39 break;
40 case 3:
41 event.message = Pm_Message(data[0], data[1], data[2]);
42 break;
43 default:
44 printf("Unexpected message length for short message, got %" B_PRIuSIZE "\n", length);
45 break;
46 }
47 event.timestamp = time / 1000;
48 pm_read_short(midi, &event);
49 }
50 }
51
52 private:
53 PmInternal *midi;
54 };
55
56 struct PmOutputInfo {
57 BMidiLocalProducer *producer;
58 std::vector<unsigned char> sysexBuffer;
59 };
60
61 struct PmSynthOutputInfo {
62 BMidiSynth midiSynth;
63 std::vector<unsigned char> sysexBuffer;
64 };
65
66
67 PmTimestamp synchronize(PmInternal *midi)
68 {
69 return 0;
70 }
71
72
73 PmError in_open(PmInternal *midi, void *driverInfo)
74 {
75 int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
76 BMidiProducer *producer = BMidiRoster::FindProducer(endpointID);
77 if (!producer)
78 return pmInvalidDeviceId;
79 PmInputConsumer *consumer = new PmInputConsumer(midi);
80 status_t status = producer->Connect(consumer);
81 if (status != B_OK) {
82 consumer->Release();
83 producer->Release();
84 strcpy(pm_hosterror_text, strerror(status));
85 pm_hosterror = TRUE;
86 return pmHostError;
87 }
88 midi->api_info = consumer;
89 producer->Release();
90 return pmNoError;
91 }
92
93
94 PmError in_abort(PmInternal *midi)
95 {
96 return pmNoError;
97 }
98
99
100 PmError in_close(PmInternal *midi)
101 {
102 int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
103 BMidiProducer *producer = BMidiRoster::FindProducer(endpointID);
104 if (!producer)
105 return pmInvalidDeviceId;
106 PmInputConsumer *consumer = (PmInputConsumer*)midi->api_info;
107 status_t status = producer->Disconnect(consumer);
108 if (status != B_OK) {
109 consumer->Release();
110 producer->Release();
111 strcpy(pm_hosterror_text, strerror(status));
112 pm_hosterror = TRUE;
113 return pmHostError;
114 }
115 consumer->Release();
116 midi->api_info = NULL;
117 producer->Release();
118 return pmNoError;
119 }
120
121
122 PmError out_open(PmInternal *midi, void *driverInfo)
123 {
124 int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
125 BMidiConsumer *consumer = BMidiRoster::FindConsumer(endpointID);
126 if (!consumer)
127 return pmInvalidDeviceId;
128 BMidiLocalProducer *producer = new BMidiLocalProducer("PortMidi output producer");
129 status_t status = producer->Connect(consumer);
130 if (status != B_OK) {
131 consumer->Release();
132 producer->Release();
133 strcpy(pm_hosterror_text, strerror(status));
134 pm_hosterror = TRUE;
135 return pmHostError;
136 }
137 PmOutputInfo *info = new PmOutputInfo;
138 info->producer = producer;
139 midi->api_info = info;
140 consumer->Release();
141 return pmNoError;
142 }
143
144
145 PmError out_abort(PmInternal *midi)
146 {
147 return pmNoError;
148 }
149
150
151 PmError out_close(PmInternal *midi)
152 {
153 int32 endpointID = (int32)(intptr_t)pm_descriptors[midi->device_id].descriptor;
154 BMidiConsumer *consumer = BMidiRoster::FindConsumer(endpointID);
155 if (!consumer)
156 return pmInvalidDeviceId;
157 PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
158 status_t status = info->producer->Disconnect(consumer);
159 if (status != B_OK) {
160 consumer->Release();
161 midi->api_info = NULL;
162 info->producer->Release();
163 delete info;
164 strcpy(pm_hosterror_text, strerror(status));
165 pm_hosterror = TRUE;
166 return pmHostError;
167 }
168 consumer->Release();
169 midi->api_info = NULL;
170 info->producer->Release();
171 delete info;
172 return pmNoError;
173 }
174
175
176 PmError write_short(PmInternal *midi, PmEvent *buffer)
177 {
178 PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
179 uchar data[3];
180 data[0] = Pm_MessageStatus(buffer->message);
181 data[1] = Pm_MessageData1(buffer->message);
182 data[2] = Pm_MessageData2(buffer->message);
183 size_t length = pm_midi_length(data[0]);
184
185 info->producer->SprayData(data, length, true, buffer->timestamp * 1000);
186
187 // TODO: handle latency != 0
188 return pmNoError;
189 }
190
191
192 PmError begin_sysex(PmInternal *midi, PmTimestamp timestamp)
193 {
194 PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
195 info->sysexBuffer.clear();
196 return pmNoError;
197 }
198
199
200 PmError end_sysex(PmInternal *midi, PmTimestamp timestamp)
201 {
202 PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
203 info->producer->SpraySystemExclusive(&info->sysexBuffer[0], info->sysexBuffer.size(), timestamp * 1000);
204 info->sysexBuffer.clear();
205 return pmNoError;
206 }
207
208
209 PmError write_byte(PmInternal *midi, unsigned char byte, PmTimestamp timestamp)
210 {
211 PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
212 info->sysexBuffer.push_back(byte);
213 return pmNoError;
214 }
215
216
217 PmError write_realtime(PmInternal *midi, PmEvent *buffer)
218 {
219 PmOutputInfo *info = (PmOutputInfo*)midi->api_info;
220 info->producer->SpraySystemRealTime(Pm_MessageStatus(buffer->message), buffer->timestamp * 1000);
221 return pmNoError;
222 }
223
224
225 PmError synth_open(PmInternal *midi, void *driverInfo)
226 {
227 PmSynthOutputInfo *info = new PmSynthOutputInfo;
228 info->midiSynth.EnableInput(true, true);
229 midi->api_info = info;
230 return pmNoError;
231 }
232
233
234 PmError synth_abort(PmInternal *midi)
235 {
236 return pmNoError;
237 }
238
239
240 PmError synth_close(PmInternal *midi)
241 {
242 PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
243 delete info;
244 midi->api_info = NULL;
245 return pmNoError;
246 }
247
248
249 PmError write_short_synth(PmInternal *midi, PmEvent *buffer)
250 {
251 PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
252 uchar data[3];
253 data[0] = Pm_MessageStatus(buffer->message);
254 data[1] = Pm_MessageData1(buffer->message);
255 data[2] = Pm_MessageData2(buffer->message);
256
257 switch(data[0] & 0xf0) {
258 case B_NOTE_OFF:
259 info->midiSynth.NoteOff((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
260 break;
261 case B_NOTE_ON:
262 info->midiSynth.NoteOn((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
263 break;
264 case B_KEY_PRESSURE:
265 info->midiSynth.KeyPressure((data[0] & 0x0f + 1), data[1], data[2], buffer->timestamp);
266 break;
267 case B_CONTROL_CHANGE:
268 info->midiSynth.ControlChange((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
269 break;
270 case B_PROGRAM_CHANGE:
271 info->midiSynth.ProgramChange((data[0] & 0x0f) + 1, data[1], buffer->timestamp);
272 break;
273 case B_CHANNEL_PRESSURE:
274 info->midiSynth.ChannelPressure((data[0] & 0x0f) + 1, data[1], buffer->timestamp);
275 break;
276 case B_PITCH_BEND:
277 info->midiSynth.PitchBend((data[0] & 0x0f) + 1, data[1], data[2], buffer->timestamp);
278 break;
279 }
280
281 // TODO: handle latency != 0
282 return pmNoError;
283 }
284
285
286 PmError begin_sysex_synth(PmInternal *midi, PmTimestamp timestamp)
287 {
288 PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
289 info->sysexBuffer.clear();
290 return pmNoError;
291 }
292
293
294 PmError end_sysex_synth(PmInternal *midi, PmTimestamp timestamp)
295 {
296 PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
297 info->midiSynth.SystemExclusive(&info->sysexBuffer[0], info->sysexBuffer.size(), timestamp);
298 info->sysexBuffer.clear();
299 return pmNoError;
300 }
301
302
303 PmError write_byte_synth(PmInternal *midi, unsigned char byte, PmTimestamp timestamp)
304 {
305 PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
306 info->sysexBuffer.push_back(byte);
307 return pmNoError;
308 }
309
310
311 PmError write_realtime_synth(PmInternal *midi, PmEvent *buffer)
312 {
313 PmSynthOutputInfo *info = (PmSynthOutputInfo*)midi->api_info;
314 info->midiSynth.SystemRealTime(Pm_MessageStatus(buffer->message), buffer->timestamp);
315 return pmNoError;
316 }
317
318
319 PmError write_flush(PmInternal *midi, PmTimestamp timestamp)
320 {
321 return pmNoError;
322 }
323
324
325 unsigned int check_host_error(PmInternal *midi)
326 {
327 return 0;
328 }
329
330
331 pm_fns_node pm_in_dictionary = {
332 none_write_short,
333 none_sysex,
334 none_sysex,
335 none_write_byte,
336 none_write_short,
337 none_write_flush,
338 synchronize,
339 in_open,
340 in_abort,
341 in_close,
342 success_poll,
343 check_host_error
344 };
345
346 pm_fns_node pm_out_dictionary = {
347 write_short,
348 begin_sysex,
349 end_sysex,
350 write_byte,
351 write_realtime,
352 write_flush,
353 synchronize,
354 out_open,
355 out_abort,
356 out_close,
357 none_poll,
358 check_host_error
359 };
360
361
362 pm_fns_node pm_synth_dictionary = {
363 write_short_synth,
364 begin_sysex_synth,
365 end_sysex_synth,
366 write_byte_synth,
367 write_realtime_synth,
368 write_flush,
369 synchronize,
370 synth_open,
371 synth_abort,
372 synth_close,
373 none_poll,
374 check_host_error
375 };
376
377
378 PmError create_virtual(int is_input, const char *name, void *driverInfo)
379 {
380 BMidiEndpoint *endpoint = is_input ? (BMidiEndpoint*)new BMidiLocalProducer(name) : new BMidiLocalConsumer(name);
381 if (!endpoint->IsValid()) {
382 endpoint->Release();
383 strcpy(pm_hosterror_text, "Endpoint could not be created");
384 pm_hosterror = TRUE;
385 return pmHostError;
386 }
387 status_t status = endpoint->Register();
388 if (status != B_OK) {
389 endpoint->Release();
390 strcpy(pm_hosterror_text, strerror(status));
391 pm_hosterror = TRUE;
392 return pmHostError;
393 }
394 return pm_add_device(const_cast<char*>("Haiku MIDI kit"), name, is_input, TRUE, (void*)(intptr_t)endpoint->ID(), is_input ? &pm_in_dictionary : &pm_out_dictionary);
395 }
396
397 PmError delete_virtual(PmDeviceID id)
398 {
399 int32 endpointID = (int32)(intptr_t)pm_descriptors[id].descriptor;
400 BMidiEndpoint *endpoint = BMidiRoster::FindEndpoint(endpointID);
401 //TODO: handle connected producers and consumers
402 status_t status = endpoint->Unregister();
403 // release twice to actually free the endpoint (FindEndpoint increases the ref-count)
404 endpoint->Release();
405 endpoint->Release();
406 if (status != B_OK) {
407 strcpy(pm_hosterror_text, strerror(status));
408 pm_hosterror = TRUE;
409 return pmHostError;
410 }
411 return pmNoError;
412 }
413}
414
415extern "C" {
416 void pm_init()
417 {
418 pm_add_interf(const_cast<char*>("Haiku MIDI kit"), create_virtual, delete_virtual);
419
420 pm_add_device(const_cast<char*>("Haiku MIDI kit"), "Soft Synth", FALSE, FALSE, NULL, &pm_synth_dictionary);
421
422 int32 id = 0;
423 BMidiEndpoint *endpoint;
424
425 while ((endpoint = BMidiRoster::NextEndpoint(&id)) != NULL) {
426 bool isInput = endpoint->IsProducer();
427 pm_add_device(const_cast<char*>("Haiku MIDI kit"), endpoint->Name(), isInput, FALSE, (void*)(intptr_t)id, isInput ? &pm_in_dictionary : &pm_out_dictionary);
428 endpoint->Release();
429 }
430 }
431
432
433 void pm_term()
434 {
435 int i;
436 for (i = 0; i < pm_descriptor_len; i++) {
437 PmInternal *midi = pm_descriptors[i].pm_internal;
438 if (midi && midi->api_info) {
439 // device is still open, close it
440 (*midi->dictionary->close)(midi);
441 }
442 if (pm_descriptors[i].pub.is_virtual && !pm_descriptors[i].deleted) {
443 delete_virtual(i);
444 }
445 }
446 }
447
448
449 PmDeviceID Pm_GetDefaultInputDeviceID()
450 {
451 Pm_Initialize();
452 return pm_default_input_device_id;
453 }
454
455
456 PmDeviceID Pm_GetDefaultOutputDeviceID()
457 {
458 Pm_Initialize();
459 return pm_default_output_device_id;
460 }
461
462
463 void *pm_alloc(size_t s)
464 {
465 return malloc(s);
466 }
467
468
469 void pm_free(void *ptr)
470 {
471 free(ptr);
472 }
473}