source: trunk/src/winmm/midi.cpp@ 668

Last change on this file since 668 was 668, checked in by phaller, 26 years ago

Fix: added SetWin32TIB wrappers to callback functions

File size: 30.8 KB
Line 
1/* $Id: midi.cpp,v 1.5 1999-08-24 21:21:11 phaller Exp $ */
2
3/*
4 * RTMIDI code
5 *
6 * Copyright 1998 Joel Troster
7 *
8 *
9 * Project Odin Software License can be found in LICENSE.TXT
10 *
11 */
12
13
14/****************************************************************************
15 * Includes *
16 ****************************************************************************/
17
18#include <os2win.h>
19#include <mmsystem.h>
20#include <odinwrap.h>
21#include <process.h>
22#include <stdio.h>
23#include <string.h>
24#include <unicode.h>
25
26#include "midi.hpp"
27#include <winos2def.h>
28#include <wprocess.h>
29
30ODINDEBUGCHANNEL(WINMM-MIDI)
31
32/*
33 Work to do:
34 - Some entrys allow a device ID to stand in for a handle, allow that.
35 - Output of long messages
36 - Midi Streams
37*/
38
39char * getWinmmMsg( MMRESULT result )
40{
41 char * ret;
42 switch ( result )
43 {
44 case MMSYSERR_ERROR:
45 ret = "Unspecified error";
46 break;
47 case MMSYSERR_BADDEVICEID:
48 ret = "Device ID out of range";
49 break;
50 case MMSYSERR_NOTENABLED:
51 ret = "driver failed enable";
52 break;
53 case MMSYSERR_ALLOCATED:
54 ret = "device already allocated";
55 break;
56 case MMSYSERR_INVALHANDLE:
57 ret = "device handle is invalid";
58 break;
59 case MMSYSERR_NODRIVER:
60 ret = "no device driver present";
61 break;
62 case MMSYSERR_NOMEM:
63 ret = "memory allocation error";
64 break;
65 case MMSYSERR_NOTSUPPORTED:
66 ret = "function isn't supported";
67 break;
68 case MMSYSERR_BADERRNUM:
69 ret = "error value out of range";
70 break;
71 case MMSYSERR_INVALFLAG:
72 ret = "invalid flag passed";
73 break;
74 case MMSYSERR_INVALPARAM:
75 ret = "invalid parameter passed";
76 break;
77 case MMSYSERR_HANDLEBUSY:
78 ret = "handle being used simultaneously on another thread";
79 break;
80 case MMSYSERR_INVALIDALIAS:
81 ret = "specified alias not found";
82 break;
83 case MMSYSERR_BADDB:
84 ret = "bad registry database";
85 break;
86 case MMSYSERR_KEYNOTFOUND:
87 ret = "registry key not found";
88 break;
89 case MMSYSERR_READERROR:
90 ret = "registry read error";
91 break;
92 case MMSYSERR_WRITEERROR:
93 ret = "registry write error";
94 break;
95 case MMSYSERR_DELETEERROR:
96 ret = "registry delete error";
97 break;
98 case MMSYSERR_VALNOTFOUND:
99 ret = "registry value not found";
100 break;
101 case MMSYSERR_NODRIVERCB:
102 ret = "driver does not call DriverCallback";
103 break;
104 case MIDIERR_NODEVICE:
105 ret = "Midi Mapper not Implemented yet.";
106 break;
107 default:
108 ret = NULL;
109 break;
110 }
111 return ret;
112}
113
114/******************************************************************************/
115ODINFUNCTION3(MMRESULT, midiConnect,
116 HMIDI, hMidiIn,
117 HMIDIOUT, hMidiOut,
118 LPVOID, pReserved)
119{
120 // TODO: Implement using instance connections
121 dprintf(("WINMM:midiConnect -- not Implemented\n" ));
122 MMRESULT rc;
123 MidiOut * midiOut = MidiOut::find( hMidiOut );
124 if ( midiOut )
125 {
126 MidiIn * midiIn = MidiIn::find( hMidiIn );
127 if ( midiIn )
128 rc = MMSYSERR_NOTSUPPORTED;
129 else
130 rc = MMSYSERR_INVALHANDLE;
131 }
132 else
133 rc = MMSYSERR_INVALHANDLE;
134 return rc;
135}
136
137/******************************************************************************/
138ODINFUNCTION3(MMRESULT, midiDisconnect,
139 HMIDI, hMidiIn,
140 HMIDIOUT, hMidiOut,
141 LPVOID, pReserved)
142{
143 // TODO: Implement using instance connections
144 dprintf(("WINMM:midiDisconnect -- not Implemented\n" ));
145 MMRESULT rc;
146 MidiOut * midiOut = MidiOut::find( hMidiOut );
147 if ( midiOut )
148 {
149 MidiIn * midiIn = MidiIn::find( hMidiIn );
150 if ( midiIn )
151 rc = MMSYSERR_NOTSUPPORTED;
152 else
153 rc = MMSYSERR_INVALHANDLE;
154 }
155 else
156 rc = MMSYSERR_INVALHANDLE;
157 return rc;
158}
159
160/******************************************************************************/
161ODINFUNCTION3(MMRESULT, midiInAddBuffer,
162 HMIDIIN, hMidiIn,
163 LPMIDIHDR, lpMidiInHdr,
164 UINT, cbMidiInHdr)
165{
166 dprintf(("WINMM:midiInAddBuffer -- not Implemented\n" ));
167 MMRESULT rc;
168 MidiIn * midiIn = MidiIn::find( hMidiIn );
169 if ( midiIn )
170 {
171 rc = MMSYSERR_NOTSUPPORTED;
172 }
173 else
174 rc = MMSYSERR_INVALHANDLE;
175 return rc;
176}
177
178/******************************************************************************/
179ODINFUNCTION1(MMRESULT, midiInClose,
180 HMIDIIN, hMidiIn)
181{
182 dprintf(("WINMM:midiInClose -- partially Implemented\n" ));
183 MMRESULT rc;
184 MidiIn * midiIn = MidiIn::find( hMidiIn );
185 if ( midiIn )
186 {
187 delete midiIn;
188 rc = MMSYSERR_NOERROR;
189 }
190 else
191 rc = MMSYSERR_INVALHANDLE;
192 return rc;
193}
194
195/******************************************************************************/
196ODINFUNCTION3(MMRESULT, midiInGetDevCapsA,
197 UINT, uDeviceId,
198 LPMIDIINCAPSA, midiInCaps,
199 UINT, sMidiInCaps)
200{
201 dprintf(("WINMM:midiInGetDevCapsA(%u)\n", uDeviceId ));
202 MMRESULT rc;
203 if ( sMidiInCaps == 0 )
204 rc = MMSYSERR_NOERROR;
205 else
206 {
207 IMidiInstance * theInst = IRTMIDI->inInstance( uDeviceId );
208 if ( theInst )
209 {
210 midiInCaps->wMid = 0; // Manufacturer ID
211 midiInCaps->wPid = 0; // Product ID
212 midiInCaps->vDriverVersion = 0x0001; // Driver Version
213 strncpy( midiInCaps->szPname, theInst->name(), MAXPNAMELEN );
214 midiInCaps->dwSupport = 0;
215 rc = MMSYSERR_NOERROR;
216 }
217 else
218 rc = MMSYSERR_BADDEVICEID;
219 }
220 return rc;
221}
222
223
224/******************************************************************************/
225ODINFUNCTION3(MMRESULT, midiInGetDevCapsW,
226 UINT, uDeviceId,
227 LPMIDIINCAPSW, midiInCaps,
228 UINT, sMidiInCaps )
229{
230 dprintf(("WINMM:midiInGetDevCapsA(%u)\n", uDeviceId ));
231 MMRESULT rc;
232 if ( sMidiInCaps == 0 )
233 rc = MMSYSERR_NOERROR;
234 else
235 {
236 IMidiInstance * theInst = IRTMIDI->inInstance( uDeviceId );
237 if ( theInst )
238 {
239 midiInCaps->wMid = 0; // Manufacturer ID
240 midiInCaps->wPid = 0; // Product ID
241 midiInCaps->vDriverVersion = 0x0001; // Driver Version
242 char name[ MAXPNAMELEN ];
243 strncpy( name, theInst->name(), MAXPNAMELEN );
244 AsciiToUnicode( name, midiInCaps->szPname );
245 midiInCaps->dwSupport = 0;
246 rc = MMSYSERR_NOERROR;
247 }
248 else
249 rc = MMSYSERR_BADDEVICEID;
250 }
251 return rc;
252}
253
254/******************************************************************************/
255ODINFUNCTION3(MMRESULT, midiInGetErrorTextA,
256 MMRESULT, wError,
257 LPSTR, lpText,
258 UINT, cchText)
259{
260 dprintf(("WINMM:midiInGetErrorTextA(%d)\n", wError ));
261 char * theMsg = getWinmmMsg( wError );
262 if ( theMsg )
263 strncpy( lpText, theMsg, cchText );
264 else
265 {
266 char errMsg[100];
267 sprintf( errMsg, "Unknown error number %d", wError );
268 strncpy( lpText, errMsg, cchText );
269 }
270 return MMSYSERR_NOERROR;
271}
272
273/******************************************************************************/
274ODINFUNCTION3(MMRESULT, midiInGetErrorTextW,
275 MMRESULT, wError,
276 LPWSTR, lpText,
277 UINT, cchText)
278{
279 dprintf(("WINMM:midiInGetErrorTextW(%d)\n", wError ));
280 char * theMsg = getWinmmMsg( wError );
281 if ( theMsg )
282 AsciiToUnicode( theMsg, lpText );
283 else
284 {
285 char errMsg[100];
286 sprintf( errMsg, "Unknown error number %d", wError );
287 AsciiToUnicode( errMsg, lpText );
288 }
289 return MMSYSERR_NOERROR;
290}
291
292/******************************************************************************/
293ODINFUNCTION2(MMRESULT, midiInGetID,
294 HMIDIIN, hMidiIn,
295 LPUINT, puDeviceID)
296{
297 dprintf(("WINMM:midiInGetID\n" ));
298 MMRESULT rc;
299 MidiIn * midiIn = MidiIn::find( hMidiIn );
300 if ( midiIn )
301 {
302 *puDeviceID = midiIn->device();
303 dprintf((" device(%d)\n", *puDeviceID ));
304 rc = MMSYSERR_NOERROR;
305 }
306 else
307 rc = MMSYSERR_INVALHANDLE;
308 return rc;
309}
310
311/******************************************************************************/
312ODINFUNCTION4(UINT, midiInMessage,
313 HMIDIIN, hmi,
314 UINT, msg,
315 DWORD, dw1,
316 DWORD, dw2)
317{
318 dprintf(("WINMM:midiInMessage -- not Implemented\n" ));
319 return 0;
320}
321
322/******************************************************************************/
323ODINFUNCTION0(UINT, midiInGetNumDevs)
324{
325 UINT i = IRTMIDI->numInInstances();
326 return i;
327}
328
329/******************************************************************************/
330ODINFUNCTION5(MMRESULT, midiInOpen,
331 LPHMIDIIN, lphMidiIn,
332 UINT, uDeviceId,
333 DWORD, dwCallback,
334 DWORD, dwCallbackInstance,
335 DWORD, dwflags)
336{
337 dprintf(("WINMM:midiInOpen(%d) -- partial Implementation\n", uDeviceId ));
338 dprintf((" dwflags(%lx)\n", dwflags ));
339 MMRESULT rc;
340 // Create a MidiIn
341 MidiIn * midiIn = new MidiIn( uDeviceId );
342 if ( midiIn )
343 {
344 *lphMidiIn = (HMIDIIN)midiIn;
345
346 midiIn->setCallback( dwCallback, dwCallbackInstance, dwflags );
347
348 rc = midiIn->open();
349 }
350 else
351 rc = MMSYSERR_BADDEVICEID;
352 return rc;
353}
354
355/******************************************************************************/
356ODINFUNCTION3(MMRESULT, midiInPrepareHeader,
357 HMIDIIN, hMidiIn,
358 LPMIDIHDR, lpMidiInHdr,
359 UINT, cbMidiInHdr)
360{
361 dprintf(("WINMM:midiInPrepareHeader -- not Implemented\n" ));
362 MMRESULT rc;
363 MidiIn * midiIn = MidiIn::find( hMidiIn );
364 if ( midiIn )
365 {
366 rc = MMSYSERR_NOTSUPPORTED;
367 }
368 else
369 rc = MMSYSERR_INVALHANDLE;
370 return rc;
371 return MMSYSERR_INVALHANDLE;
372}
373
374/******************************************************************************/
375ODINFUNCTION1(MMRESULT, midiInReset,
376 HMIDIIN, hMidiIn)
377{
378 dprintf(("WINMM:midiInReset -- not Implemented\n" ));
379 MMRESULT rc;
380 MidiIn * midiIn = MidiIn::find( hMidiIn );
381 if ( midiIn )
382 {
383 rc = MMSYSERR_NOERROR;
384 }
385 else
386 rc = MMSYSERR_INVALHANDLE;
387 return rc;
388}
389
390/******************************************************************************/
391ODINFUNCTION1(MMRESULT, midiInStart,
392 HMIDIIN, hMidiIn)
393{
394 dprintf(("WINMM:midiInStart\n" ));
395 MMRESULT rc;
396 MidiIn * midiIn = MidiIn::find( hMidiIn );
397 if ( midiIn )
398 {
399 rc = midiIn->start();
400 }
401 else
402 rc = MMSYSERR_INVALHANDLE;
403 return rc;
404}
405
406/******************************************************************************/
407ODINFUNCTION1(MMRESULT, midiInStop,
408 HMIDIIN, hMidiIn)
409{
410 dprintf(("WINMM:midiInStop\n" ));
411 MMRESULT rc;
412 MidiIn * midiIn = MidiIn::find( hMidiIn );
413 if ( midiIn )
414 {
415 rc = midiIn->stop();
416 }
417 else
418 rc = MMSYSERR_INVALHANDLE;
419 return rc;
420}
421
422/******************************************************************************/
423ODINFUNCTION3(MMRESULT, midiInUnprepareHeader,
424 HMIDIIN, hMidiIn,
425 LPMIDIHDR, lpMidiInHdr,
426 UINT, cbMidiInHdr)
427{
428 dprintf(("WINMM:midiInUnPrepareHeader -- not Implemented\n" ));
429 MMRESULT rc;
430 MidiIn * midiIn = MidiIn::find( hMidiIn );
431 if ( midiIn )
432 {
433 rc = MMSYSERR_NOTSUPPORTED;
434 }
435 else
436 rc = MMSYSERR_INVALHANDLE;
437 return rc;
438}
439
440/******************************************************************************/
441ODINFUNCTION4(MMRESULT, midiOutCacheDrumPatches,
442 HMIDIOUT, hMidiOut,
443 UINT, wPatch,
444 WORD *, lpKeyArray,
445 UINT, wFlags)
446{
447 // Valid only for an Internal synth. So we won't do it for now.
448 dprintf(("WINMM:midiOutCacheDrumPatches\n" ));
449 MMRESULT rc;
450 MidiOut * midiOut = MidiOut::find( hMidiOut );
451 if ( midiOut )
452 {
453 rc = MMSYSERR_NOTSUPPORTED;
454 }
455 else
456 rc = MMSYSERR_INVALHANDLE;
457 return rc;
458}
459
460/******************************************************************************/
461ODINFUNCTION4(MMRESULT, midiOutCachePatches,
462 HMIDIOUT, hMidiOut,
463 UINT, wBank,
464 WORD *, lpPatchArray,
465 UINT, wFlags)
466{
467 // Valid only for an Internal synth. So we won't do it for now.
468 dprintf(("WINMM:midiOutCachePatches\n" ));
469 MMRESULT rc;
470 MidiOut * midiOut = MidiOut::find( hMidiOut );
471 if ( midiOut )
472 {
473 rc = MMSYSERR_NOTSUPPORTED;
474 }
475 else
476 rc = MMSYSERR_INVALHANDLE;
477 return rc;
478}
479
480/******************************************************************************/
481ODINFUNCTION1(MMRESULT, midiOutClose,
482 HMIDIOUT, hMidiOut)
483{
484 dprintf(("WINMM:midiOutClose - partially implemented\n" ));
485 // TODO: Check if buffers are still playing and return MIDIERR_STILLPLAYING
486 MMRESULT rc;
487 MidiOut * midiOut = MidiOut::find( hMidiOut );
488 if ( midiOut )
489 {
490 delete midiOut;
491 rc = MMSYSERR_NOERROR;
492 }
493 else
494 rc = MMSYSERR_INVALHANDLE;
495 return rc;
496}
497
498/******************************************************************************/
499ODINFUNCTION3(MMRESULT, midiOutGetDevCapsA,
500 UINT, uDeviceId,
501 LPMIDIOUTCAPSA, midiOutCaps,
502 UINT, sMidiOutCaps )
503{
504 // TODO: Actually fill in the important fields
505 dprintf(("WINMM:midiOutGetDevCapsA(%u)\n", uDeviceId ));
506 MMRESULT rc;
507 if ( sMidiOutCaps == 0 )
508 rc = MMSYSERR_NOERROR;
509 else
510 if ( uDeviceId == 0xFFFF || uDeviceId == 0xFFFFFFFF )
511 {
512 // We got here a Midi Mapper
513 midiOutCaps->wMid = 0; // Manufacturer ID
514 midiOutCaps->wPid = 0; // Product ID
515 midiOutCaps->vDriverVersion = 0x0001; // Driver Version
516 strncpy( midiOutCaps->szPname, "MIDI Mapper", MAXPNAMELEN );
517 midiOutCaps->wTechnology = MOD_MAPPER;
518 midiOutCaps->wVoices = 0;
519 midiOutCaps->wNotes = 0;
520 midiOutCaps->wChannelMask = 0;
521 midiOutCaps->dwSupport = MIDICAPS_VOLUME
522 | MIDICAPS_LRVOLUME;
523 rc = MMSYSERR_NOERROR;
524 }
525 else
526 {
527 IMidiInstance * theInst = IRTMIDI->outInstance( uDeviceId );
528 if ( theInst )
529 {
530 // need to fill in capabilities of the MIDI Device
531 midiOutCaps->wMid = 0; // Manufacturer ID
532 midiOutCaps->wPid = 0; // Product ID
533 midiOutCaps->vDriverVersion = 0x0001; // Driver Version
534 strncpy( midiOutCaps->szPname, theInst->name(), MAXPNAMELEN );
535 midiOutCaps->wTechnology = MOD_MIDIPORT;
536 midiOutCaps->wVoices = 0;
537 midiOutCaps->wNotes = 0;
538 midiOutCaps->wChannelMask = 0;
539 midiOutCaps->dwSupport = MIDICAPS_VOLUME
540 | MIDICAPS_LRVOLUME;
541 rc = MMSYSERR_NOERROR;
542 }
543 else
544 rc = MMSYSERR_BADDEVICEID;
545 }
546 return rc;
547}
548
549/******************************************************************************/
550ODINFUNCTION3(MMRESULT, midiOutGetDevCapsW,
551 UINT, uDeviceId,
552 LPMIDIOUTCAPSW, midiOutCaps,
553 UINT, sMidiOutCaps )
554{
555 // TODO: Actually fill in the important fields
556 dprintf(("WINMM:midiOutGetDevCapsW(%u)- partially implemented\n", uDeviceId ));
557 MMRESULT rc;
558 if ( sMidiOutCaps == 0 )
559 rc = MMSYSERR_NOERROR;
560 else
561 if ( uDeviceId == 0xFFFF || uDeviceId == 0xFFFFFFFF )
562 {
563 // We got here a Midi Mapper
564 midiOutCaps->wMid = 0; // Manufacturer ID
565 midiOutCaps->wPid = 0; // Product ID
566 midiOutCaps->vDriverVersion = 0x0001; // Driver Version
567 AsciiToUnicode( "MIDI Mapper", midiOutCaps->szPname );
568 midiOutCaps->wTechnology = MOD_MAPPER;
569 midiOutCaps->wVoices = 0;
570 midiOutCaps->wNotes = 0;
571 midiOutCaps->wChannelMask = 0;
572 midiOutCaps->dwSupport = MIDICAPS_VOLUME
573 | MIDICAPS_LRVOLUME;
574 rc = MMSYSERR_NOERROR;
575 }
576 else
577 {
578 IMidiInstance * theInst = IRTMIDI->outInstance( uDeviceId );
579 if ( theInst )
580 {
581 // need to fill in capabilities of the MIDI Device
582 midiOutCaps->wMid = 0; // Manufacturer ID
583 midiOutCaps->wPid = 0; // Product ID
584 midiOutCaps->vDriverVersion = 0x0001; // Driver Version
585 char name[ MAXPNAMELEN ];
586 strncpy( name, theInst->name(), MAXPNAMELEN );
587 AsciiToUnicode( name, midiOutCaps->szPname );
588 midiOutCaps->wTechnology = MOD_MIDIPORT;
589 midiOutCaps->wVoices = 0;
590 midiOutCaps->wNotes = 0;
591 midiOutCaps->wChannelMask = 0;
592 midiOutCaps->dwSupport = MIDICAPS_VOLUME
593 | MIDICAPS_LRVOLUME;
594 rc = MMSYSERR_NOERROR;
595 }
596 else
597 rc = MMSYSERR_BADDEVICEID;
598 }
599 return rc;
600}
601
602/******************************************************************************/
603ODINFUNCTION3(MMRESULT, midiOutGetErrorTextA,
604 MMRESULT, wError,
605 LPSTR, lpText,
606 UINT, cchText)
607{
608 dprintf(("WINMM:midiOutGetErrorTextA(%d)\n", wError ));
609 char * theMsg = getWinmmMsg( wError );
610 if ( theMsg )
611 strncpy( lpText, theMsg, cchText );
612 else
613 {
614 char errMsg[100];
615 sprintf( errMsg, "Unknown error number %d", wError );
616 strncpy( lpText, errMsg, cchText );
617 }
618 return MMSYSERR_NOERROR;
619}
620
621/******************************************************************************/
622ODINFUNCTION3(MMRESULT, midiOutGetErrorTextW,
623 MMRESULT, wError,
624 LPWSTR, lpText,
625 UINT, cchText)
626{
627 dprintf(("WINMM:midiOutGetErrorTextW(%d) - need to translate\n", wError ));
628 char * theMsg = getWinmmMsg( wError );
629 if ( theMsg )
630 AsciiToUnicode( theMsg, lpText );
631 else
632 {
633 char errMsg[100];
634 sprintf( errMsg, "Unknown error number %d", wError );
635 AsciiToUnicode( errMsg, lpText );
636 }
637 return MMSYSERR_NOERROR;
638}
639
640/******************************************************************************/
641ODINFUNCTION2(MMRESULT, midiOutGetID,
642 HMIDIOUT, hMidiOut,
643 LPUINT, puDeviceID)
644{
645 dprintf(("WINMM:midiOutGetID\n" ));
646 MMRESULT rc;
647 MidiOut * midiOut = MidiOut::find( hMidiOut );
648 if ( midiOut )
649 {
650 *puDeviceID = midiOut->device();
651 rc = MMSYSERR_NOERROR;
652 }
653 else
654 rc = MMSYSERR_INVALHANDLE;
655 return rc;
656}
657
658/******************************************************************************/
659ODINFUNCTION0(UINT, midiOutGetNumDevs)
660{
661 UINT i = IRTMIDI->numOutInstances();
662 return i;
663}
664
665/******************************************************************************/
666ODINFUNCTION2(MMRESULT, midiOutGetVolume,
667 HMIDIOUT, hMidiOut,
668 LPDWORD, lpdwVolume)
669{
670 MMRESULT rc;
671 MidiOut * midiOut = MidiOut::find( hMidiOut );
672 if ( midiOut )
673 {
674 *lpdwVolume = midiOut->getVolume();
675 rc = MMSYSERR_NOERROR;
676 }
677 else
678 rc = MMSYSERR_INVALHANDLE;
679 return rc;
680}
681
682/******************************************************************************/
683ODINFUNCTION3(MMRESULT, midiOutLongMsg,
684 HMIDIOUT, hMidiOut,
685 LPMIDIHDR, lpMidiOutHdr,
686 UINT, cbMidiOutHdr)
687{
688 // TODO: Implement this
689 // - Buffer must be "prepared" first.
690 // - send async or sync, use callback (MOM_DONE) when done and mark buffer as done
691 dprintf(("WINMM:midiOutLongMsg -- not Implemented\n" ));
692 MMRESULT rc;
693 MidiOut * midiOut = MidiOut::find( hMidiOut );
694 if ( midiOut )
695 {
696 rc = MMSYSERR_NOTSUPPORTED;
697 }
698 else
699 rc = MMSYSERR_INVALHANDLE;
700 return rc;
701}
702
703/******************************************************************************/
704ODINFUNCTION4(UINT, midiOutMessage,
705 HMIDIOUT, hMidiOut,
706 UINT, msg,
707 DWORD, dw1,
708 DWORD, dw2)
709{
710 // TODO: Need to find out wha drivers actually return.
711 dprintf(("WINMM:midiOutMessage -- not Implemented\n" ));
712 return 0;
713}
714
715/******************************************************************************/
716ODINFUNCTION5(MMRESULT, midiOutOpen,
717 LPHMIDIOUT, lphMidiOut,
718 UINT, uDeviceId,
719 DWORD, dwCallback,
720 DWORD, dwCallbackInstance,
721 DWORD, dwflags)
722{
723 // TODO: - Handle thread callback, if any program really needs it
724 // Note uDeviceId of MIDIMAPPER is special ID for MIDI Mapper
725
726 dprintf(("WINMM:midiOutOpen(%lX)\n", uDeviceId ));
727 dprintf((" dwflags(%lx)\n", dwflags ));
728 MMRESULT rc;
729 MidiOut * midiOut;
730 // Create a MidiOut
731 if ( uDeviceId == 0xFFFF || uDeviceId == 0xFFFFFFFF )
732 {
733 dprintf((" open of Midi Mapper requested\n"));
734 midiOut = new MidiMapper();
735 }
736 else
737 {
738 if ( uDeviceId < IRTMIDI->numOutInstances() )
739 midiOut = new MidiOut( uDeviceId );
740 else
741 midiOut = NULL;
742 }
743 if ( midiOut )
744 {
745 *lphMidiOut = (HMIDIOUT)midiOut;
746
747 midiOut->setCallback( dwCallback, dwCallbackInstance, dwflags );
748
749 rc = midiOut->open();
750 }
751 else
752 rc = MMSYSERR_BADDEVICEID;
753 return rc;
754}
755
756/******************************************************************************/
757ODINFUNCTION3(MMRESULT, midiOutPrepareHeader,
758 HMIDIOUT, hMidiOut,
759 LPMIDIHDR, lpMidiOutHdr,
760 UINT, cbMidiOutHdr)
761{
762 // TODO: Either implement or treat as a NOOP as we may not need to "prepare"
763 // for RTMIDI.
764 dprintf(("WINMM:midiOutPrepareHeader -- not Implemented\n" ));
765 MMRESULT rc;
766 MidiOut * midiOut = MidiOut::find( hMidiOut );
767 if ( midiOut )
768 {
769 rc = MMSYSERR_NOTSUPPORTED;
770 }
771 else
772 rc = MMSYSERR_INVALHANDLE;
773 return rc;
774}
775
776/******************************************************************************/
777ODINFUNCTION1(MMRESULT, midiOutReset,
778 HMIDIOUT, hMidiOut)
779{
780 // TODO: - return pending output buffers to callback
781 // - Send a note off for each note on each channel
782 // - Turn off sustain controller on each channel
783 dprintf(("WINMM:midiOutReset -- not Implemented\n" ));
784 MMRESULT rc;
785 MidiOut * midiOut = MidiOut::find( hMidiOut );
786 if ( midiOut )
787 {
788 return MMSYSERR_NOERROR;
789 }
790 else
791 rc = MMSYSERR_INVALHANDLE;
792 return rc;
793}
794
795/******************************************************************************/
796ODINFUNCTION2(MMRESULT, midiOutSetVolume,
797 HMIDIOUT, hMidiOut,
798 DWORD, dwVolume)
799{
800 dprintf(("WINMM:midiOutSetVolume\n" ));
801 MMRESULT rc;
802 MidiOut * midiOut = MidiOut::find( hMidiOut );
803 if ( midiOut )
804 {
805 midiOut->sendVolume( dwVolume );
806 rc = MMSYSERR_NOERROR;
807 }
808 else
809 rc = MMSYSERR_INVALHANDLE;
810 return rc;
811}
812
813/******************************************************************************/
814ODINFUNCTION2(MMRESULT, midiOutShortMsg,
815 HMIDIOUT, hMidiOut,
816 DWORD, dwMsg)
817{
818 dprintf(("WINMM:midiOutShortMsg(%X)\n", dwMsg ));
819 MMRESULT rc;
820 MidiOut * midiOut = MidiOut::find( hMidiOut );
821 if ( midiOut )
822 {
823 midiOut->sendMessage( dwMsg );
824 rc = MMSYSERR_NOERROR;
825 }
826 else
827 rc = MMSYSERR_INVALHANDLE;
828 return rc;
829}
830
831/******************************************************************************/
832ODINFUNCTION3(MMRESULT, midiOutUnprepareHeader,
833 HMIDIOUT, hMidiOut,
834 LPMIDIHDR, lpMidiOutHdr,
835 UINT, cbMidiOutHdr)
836{
837 // TODO: - return MIDIERR_STILLPLAYING if buffer is playing
838 // - otherwise there is no need to unprepare
839 dprintf(("WINMM:midiOutUnprepareHeader -- not Implemented\n" ));
840 MMRESULT rc;
841 MidiOut * midiOut = MidiOut::find( hMidiOut );
842 if ( midiOut )
843 {
844 rc = MMSYSERR_NOTSUPPORTED;
845 }
846 else
847 rc = MMSYSERR_INVALHANDLE;
848 return rc;
849}
850
851// TO ADD: midiStream Close, Open, Out, Pause, Position, Property, Restart, Stop
852
853/******************************************************************************/
854/* Midi Classes to interface to RTMidi */
855/******************************************************************************/
856Midi::Midi( UINT uDeviceId )
857 :iDeviceId( uDeviceId )
858 ,iHwdInstance( NULL )
859 ,iAppInstance( NULL )
860 ,iCallbackFunction( 0 )
861 ,iCallbackWindow( 0 )
862 ,iCallbackInstance( )
863{
864}
865
866Midi::~Midi()
867{
868}
869
870void Midi::setCallback( DWORD dwCallback,
871 DWORD dwCallbackInstance,
872 DWORD dwflags )
873{
874 iCallbackInstance = dwCallbackInstance;
875
876 // What kind of callback?
877 if ( (dwflags & CALLBACK_TYPEMASK) == CALLBACK_WINDOW )
878 iCallbackWindow = (HWND)dwCallback;
879 else
880 if ( (dwflags & CALLBACK_TYPEMASK) == CALLBACK_FUNCTION )
881 iCallbackFunction = (LPDRVCALLBACK)dwCallback;
882}
883
884void Midi::callback( UINT msg, DWORD p1, DWORD p2)
885{
886 USHORT selTIB;
887
888 dprintf(("WINMM: callback %x %lx %lx\n", msg, p1, p2 ));
889
890 if ( iCallbackFunction )
891 {
892 selTIB = SetWin32TIB();
893 iCallbackFunction( (ULONG)this, msg, iCallbackInstance, p1, p2 );
894 SetFS(selTIB);
895 }
896 else
897 if ( iCallbackWindow )
898 {
899 WinPostMsg( iCallbackWindow, msg, (MPARAM)p1, (MPARAM)p2 );
900 }
901}
902
903
904static void _Optlink TimerInHandler(void *);
905
906MidiIn * MidiIn::iFirst = NULL;
907
908MidiIn::MidiIn( UINT uDeviceId )
909 : Midi( uDeviceId )
910 , iNext( NULL )
911{
912 // Create application instance
913 iAppInstance = new IAppMidiInstance( MIDI_INST_ATTR_CAN_RECV );
914 // Lookup Hardware instance
915 iHwdInstance = IRTMIDI->inInstance( uDeviceId );
916 // Add us to the linked list
917 iNext = iFirst;
918 iFirst = this;
919}
920
921MidiIn* MidiIn::find( HMIDIIN theMidiIn )
922{
923 dprintf(( " MidiIn::find(%X)\n", theMidiIn ));
924 for( MidiIn * m = iFirst; m; m->iNext )
925 {
926 if ( m == (MidiIn*)theMidiIn )
927 return m;
928 }
929 return NULL;
930}
931
932MidiIn* MidiIn::find( UINT uDeviceId )
933{
934 for( MidiIn * m = iFirst; m; m->iNext )
935 {
936 if ( m->device() == uDeviceId )
937 return m;
938 }
939 return NULL;
940}
941
942MidiIn::~MidiIn()
943{
944 // Remove from linked list
945 if ( iFirst == this )
946 iFirst = iNext;
947 else
948 {
949 for ( MidiIn* m = iFirst; m; m->iNext )
950 {
951 if ( m->iNext == this )
952 {
953 m->iNext = iNext;
954 break;
955 }
956 }
957 }
958}
959
960MMRESULT MidiIn::open()
961{
962 // Enable Appl instance to receive and the hardware instance to send
963 iAppInstance->enableReceive( TRUE );
964 iHwdInstance->enableSend( TRUE );
965
966 // Link the two instances
967 iHwdInstance->addLink( iAppInstance );
968 callback( MIM_OPEN, 0, 0 );
969 return MMSYSERR_NOERROR;
970}
971
972MMRESULT MidiIn::close()
973{
974 // Disable the link
975 iHwdInstance->removeLink( iAppInstance );
976 callback( MIM_CLOSE, 0, 0 );
977 return MMSYSERR_NOERROR;
978}
979
980MMRESULT MidiIn::start()
981{
982 iRunning = TRUE;
983 iStartTime = IRTMIDI->currentTime();
984 iThreadId = _beginthread(TimerInHandler, NULL, 0x4000, (void *)this);
985 dprintf(("WINMM: MidiIn::start %lx\n", iThreadId ));
986 return MMSYSERR_NOERROR;
987}
988
989void MidiIn::getMessages()
990{
991 dprintf(("WINMM: MidiIn::getMessages\n" ));
992 while( iRunning )
993 {
994 ULONG msgTime;
995 ULONG msg;
996 ULONG rc;
997 rc = iAppInstance->getMessage( &msgTime, &msg );
998 if ( iRunning )
999 {
1000 if ( rc == 0 )
1001 {
1002 callback( MIM_DATA, msg, msgTime-iStartTime );
1003 }
1004 else
1005 {
1006 dprintf(("WINMM: MidiIn::getMessages(%s)\n", IRTMIDI->RCExplanation() ));
1007 }
1008 }
1009 }
1010 dprintf(("WINMM: MidiIn stopped\n"));
1011}
1012
1013MMRESULT MidiIn::stop()
1014{
1015 // Here we will stop the thread by posting the stop flag and then
1016 // sending a zero message to ensure it sees the flag
1017 iRunning = FALSE;
1018
1019 MINSTANCE stopper;
1020 (*IRTMIDI->MidiCreateInstance)( IRTMIDI->applicationClass(), &stopper, "stopper", 0 );
1021 (*IRTMIDI->MidiEnableInstance)( stopper, MIDI_ENABLE_SEND );
1022 (*IRTMIDI->MidiAddLink)( stopper, iAppInstance->instance(), 0, 0 );
1023 MESSAGE msg;
1024 msg.ulSourceInstance = stopper;
1025 msg.ulTime = 0;
1026 msg.ulTrack = 0;
1027 msg.msg.ulMessage = 0xf7fffff0;
1028 (*IRTMIDI->MidiSendMessages)( &msg, 1, 0 );
1029 (*IRTMIDI->MidiRemoveLink)( stopper, iAppInstance->instance(), 0, 0 );
1030 (*IRTMIDI->MidiDisableInstance)( stopper, MIDI_DISABLE_SEND );
1031 (*IRTMIDI->MidiDeleteInstance)( stopper, 0 );
1032
1033 // Sleep to let it stop
1034 DosSleep( 10l );
1035
1036 return MMSYSERR_NOERROR;
1037}
1038
1039static void _Optlink TimerInHandler(void *vMidiIn)
1040{
1041 unsigned long rc=0;
1042 MidiIn * midiIn = (MidiIn*)vMidiIn;
1043 midiIn->getMessages();
1044 _endthread();
1045}
1046
1047MidiOut * MidiOut::iFirst = NULL;
1048
1049MidiOut::MidiOut( UINT uDeviceId )
1050 : Midi( uDeviceId )
1051 , iNext( NULL )
1052{
1053 // Create application instance
1054 if ( uDeviceId == 0xFFFF || uDeviceId == 0xFFFFFFFF )
1055 {
1056 dprintf((" MidiOut::mapper(%X)\n", uDeviceId ));
1057 iAppInstance = 0;
1058 iHwdInstance = 0;
1059 }
1060 else
1061 {
1062 iAppInstance = new IAppMidiInstance( MIDI_INST_ATTR_CAN_SEND );
1063 iHwdInstance = IRTMIDI->outInstance( uDeviceId );
1064 dprintf(( "WINMM: MidiOut::MidiOut(%s)\n",iHwdInstance->name()));
1065 }
1066 // Add us to the linked list
1067 iNext = iFirst;
1068 iFirst = this;
1069}
1070
1071MidiOut* MidiOut::find( HMIDIOUT theMidiOut )
1072{
1073 dprintf(( " MidiOut::find(%X)\n", theMidiOut ));
1074 for( MidiOut * m = iFirst; m; m->iNext )
1075 {
1076 if ( m == (MidiOut*)theMidiOut )
1077 return m;
1078 }
1079 return NULL;
1080}
1081
1082MidiOut* MidiOut::find( UINT uDeviceId )
1083{
1084 for( MidiOut * m = iFirst; m; m->iNext )
1085 {
1086 if ( m->device() == uDeviceId )
1087 return m;
1088 }
1089 return NULL;
1090}
1091
1092MidiOut::~MidiOut()
1093{
1094 // Remove from linked list
1095 if ( iFirst == this )
1096 iFirst = iNext;
1097 else
1098 {
1099 for ( MidiOut* m = iFirst; m; m->iNext )
1100 {
1101 if ( m->iNext == this )
1102 {
1103 m->iNext = iNext;
1104 break;
1105 }
1106 }
1107 }
1108}
1109
1110MMRESULT MidiOut::open()
1111{
1112 dprintf(( "WINMM: MidiOut::open(%s)\n",iHwdInstance->name()));
1113 // Enable Appl instance to send and the hwd instance to receive
1114 iAppInstance->enableSend( TRUE );
1115 iHwdInstance->enableReceive( TRUE );
1116
1117 // Link the two instances
1118 iAppInstance->addLink( iHwdInstance );
1119 callback( MOM_OPEN, 0, 0 );
1120 return MMSYSERR_NOERROR;
1121}
1122
1123MMRESULT MidiOut::close()
1124{
1125 dprintf(( "WINMM: MidiOut::close(%s)\n",iHwdInstance->name()));
1126 iAppInstance->removeLink( iHwdInstance );
1127 callback( MOM_CLOSE, 0, 0 );
1128 return MMSYSERR_NOERROR;
1129}
1130
1131MMRESULT MidiOut::sendMessage( DWORD inMsg ) const
1132{
1133 dprintf(( "WINMM: MidiOut::sendMessage(%s)%X\n",iHwdInstance->name(),inMsg ));
1134 iAppInstance->sendMessage( inMsg );
1135 ULONG rc = IRTMIDI->lastRC();
1136 if ( rc )
1137 { dprintf(("MidiOut:send failure(%s)", IRTMIDI->RCExplanation() )); }
1138 return MMSYSERR_NOERROR;
1139}
1140
1141MMRESULT MidiOut::sendSysexMessage( BYTE* inMsg, ULONG msgLen ) const
1142{
1143 dprintf(( "WINMM: MidiOut::sendSysexMessage(%s) %d bytes\n",iHwdInstance->name(),msgLen ));
1144 iAppInstance->sendSysexMessage( inMsg, msgLen );
1145 ULONG rc = IRTMIDI->lastRC();
1146 if ( rc )
1147 { dprintf(("MidiOut:send failure(%s)", IRTMIDI->RCExplanation() )); }
1148 return MMSYSERR_NOERROR;
1149}
1150
1151DWORD MidiOut::getVolume() const
1152{
1153 return iVolume;
1154}
1155
1156MMRESULT MidiOut::sendVolume( DWORD volume ) const
1157{
1158 dprintf(( "WINMM: MidiOut::sendVolume(%s) %lX bytes\n",iHwdInstance->name(), volume));
1159 ((MidiOut*)this)->iVolume = volume;
1160 BYTE msg[10];
1161 msg[0] = 0xF0;
1162 msg[1] = 0x00;
1163 msg[2] = 0x00;
1164 msg[3] = 0x3A;
1165 msg[4] = 0x03;
1166 msg[5] = 0x09;
1167 msg[6] = 0x0000FFFF & volume; // left vol
1168 msg[7] = 0x0000FFFF & (volume >> 16); // right vol
1169 msg[8] = 0x00;
1170 msg[9] = 0xf7;
1171 return sendSysexMessage( msg, 10 );
1172}
1173
1174MidiMapper::MidiMapper()
1175 : MidiOut( 0xFFFFFFFF )
1176{
1177}
1178
1179MidiMapper::~MidiMapper()
1180{
1181}
1182
1183MMRESULT MidiMapper::open()
1184{
1185 // Do nothing for now
1186 return MMSYSERR_NOERROR;
1187}
1188
1189MMRESULT MidiMapper::close()
1190{
1191 // Do nothing for now
1192 return MMSYSERR_NOERROR;
1193}
1194
1195MMRESULT MidiMapper::sendMessage( DWORD inMsg ) const
1196{
1197 // Do nothing for now
1198 return MMSYSERR_NOERROR;
1199}
1200
1201MMRESULT MidiMapper::sendSysexMessage( BYTE* inMsg, ULONG msgLen ) const
1202{
1203 // Do nothing for now
1204 return MMSYSERR_NOERROR;
1205}
1206
1207
Note: See TracBrowser for help on using the repository browser.