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

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

Added new logging feature + fixed waveout query format bug

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