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

Last change on this file since 8706 was 8470, checked in by sandervl, 23 years ago

added debug wrappers (.def)

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