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

Last change on this file since 4 was 4, checked in by ktk, 26 years ago

Import

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