source: trunk/src/winmm/midi.cpp

Last change on this file was 21927, checked in by dmik, 14 years ago

Fix build breaks with the newest GCC 4.4.6 from GIT.

In particular, GCC is now strict about matching the calling convention
of the prototype (argument) and the real function used.

File size: 30.0 KB
Line 
1/* $Id: midi.cpp,v 1.11 2003-07-16 15:47: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
40const char * getWinmmMsg( MMRESULT result )
41{
42 const 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 const 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 const char * theMsg = getWinmmMsg( wError );
263 if ( theMsg )
264 AsciiToUnicodeN( theMsg, lpText, cchText );
265 else
266 {
267 char errMsg[100];
268 sprintf( errMsg, "Unknown error number %d", wError );
269 AsciiToUnicodeN( errMsg, lpText, cchText );
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 const 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 const char * theMsg = getWinmmMsg( wError );
582 if ( theMsg )
583 AsciiToUnicodeN( theMsg, lpText, cchText );
584 else
585 {
586 char errMsg[100];
587 sprintf( errMsg, "Unknown error number %d", wError );
588 AsciiToUnicodeN( errMsg, lpText, cchText );
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 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 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.