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

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

* empty log message *

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