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

Last change on this file since 1011 was 1011, checked in by sandervl, 26 years ago

WinPostMsg calls changed into PostMessageA

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