2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: winmidi.c,v 1.1.1.1 2001-01-19 03:30:15 bradleyb Exp $";
17 #pragma on (unreferenced)
24 #define WIN32_LEAN_AND_MEAN
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 BOOL WMidi_NewStream = 0;
50 static BOOL WMidi_initialized = FALSE;
52 static DWORD wmidi_volume = 0x80008000;
53 static BOOL LoopSong = FALSE;
54 static BOOL MidiVolChanges = TRUE;
57 void wmidi_deamp_song(DWORD vol);
59 void CALLBACK wmidi_seq_callback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
62 // ----------------------------------------------------------------------------
63 // Sequencer Initialization and destruction
64 // ----------------------------------------------------------------------------
66 int wmidi_init(uint mmdev)
74 memset(&MSeq, 0, sizeof(SEQ));
76 WMidi_initialized = TRUE;
78 // Initialize stream buffers
79 MSeq.uState = SEQ_S_NOFILE;
87 if (seqAllocBuffers(&MSeq) != MMSYSERR_NOERROR)
90 // Setup sequencer some more
91 ui = midiOutGetDevCaps(mmdev, &midicaps, sizeof(midicaps));
92 if ( ui != MMSYSERR_NOERROR) {
93 mprintf((1, "WMIDI:(%x) Unable to find requested device.\n", MSeq.mmrcLastErr));
97 if ((midicaps.dwSupport & MIDICAPS_VOLUME) || (midicaps.dwSupport & MIDICAPS_LRVOLUME))
98 MidiVolChanges = TRUE;
99 else MidiVolChanges = FALSE;
101 MSeq.uDeviceID = mmdev;
103 // Now we must do a stupid Microsoft trick to determine whether we are
104 // using WAVE TABLE volume or OPL volume.
105 MSeq.uMCIDeviceID = wmidi_get_tech();
107 logentry("MIDI technology: %d.\n", MSeq.uMCIDeviceID);
117 Assert(WMidi_initialized == TRUE);
119 seqFreeBuffers(&MSeq);
121 WMidi_initialized = FALSE;
135 lres = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap",
136 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_EXECUTE,
138 if (lres != ERROR_SUCCESS) return 0;
141 lres = RegQueryValueEx(hKey, "CurrentInstrument", NULL, &type, key, &len);
142 if (lres != ERROR_SUCCESS) {
149 strcpy(buf, "System\\CurrentControlSet\\control\\MediaResources\\midi\\");
151 lres = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf,
152 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_EXECUTE,
154 if (lres != ERROR_SUCCESS) return 0;
157 lres = RegQueryValueEx(hKey, "Description", NULL, &type, buf, &len);
158 if (lres != ERROR_SUCCESS) {
164 // Okay, look for 'wave' or 'fm' or 'opl'
166 if (strstr(pstr, "wave")) return 1;
172 int wmidi_support_volchange() {
173 return (int)MidiVolChanges;
177 // ----------------------------------------------------------------------------
178 // High level midi song play/stop/pause interface
179 // ----------------------------------------------------------------------------
181 int wmidi_init_song(WMIDISONG *song)
187 if (MSeq.uState != SEQ_S_NOFILE) return 0;
189 Assert (song->data != NULL);
191 mmrc = seqStop(&MSeq);
192 if (mmrc != MMSYSERR_NOERROR)
194 mprintf((1, "WMIDI: Stop song failed.\n"));;
200 if (song->looping) LoopSong = TRUE;
201 else LoopSong = FALSE;
203 if (smfOpenFile(song->data, song->length, (HSMF *)&smf) != SMF_SUCCESS) return 0;
205 // song is confirmed to be a MIDI v1.0 compatible file
207 MSeq.dwTimeDivision = smf->dwTimeDivision;
208 MSeq.tkLength = smf->tkLength;
209 MSeq.cTrk = smf->dwTracks;
211 bufsize = min(MSeq.cbBuffer, smfGetStateMaxSize());
213 MSeq.uState = SEQ_S_OPENED;
226 preroll.tkEnd = MSeq.tkLength;
228 mprintf((1, "wmidi_play: beginning playback.\n"));
230 if ((mmrc = seqPreroll(&MSeq, &preroll)) != MMSYSERR_NOERROR) {
231 mprintf((1, "wmidi_play: preroll failed! (%x)\n", mmrc));
236 Assert(MSeq.hmidi != NULL);
238 // wmidi_deamp_song(wmidi_volume);
240 mmrc = midiOutSetVolume((HMIDIOUT)MSeq.hmidi, wmidi_volume);
241 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
242 midiOutGetVolume((HMIDIOUT)MSeq.hmidi, &vol);
244 if (seqStart(&MSeq) != MMSYSERR_NOERROR) return 0;
252 if (seqStop(&MSeq) != MMSYSERR_NOERROR) return 0;
259 if (MSeq.uState != SEQ_S_PAUSED) {
260 if (seqPause(&MSeq) != MMSYSERR_NOERROR) return 0;
267 if (MSeq.uState == SEQ_S_PAUSED) {
268 if (seqRestart(&MSeq) != MMSYSERR_NOERROR) return 0;
274 int wmidi_close_song()
279 if (SEQ_S_OPENED != MSeq.uState)
280 return MCIERR_UNSUPPORTED_FUNCTION;
284 if ((HSMF)NULL != MSeq.hSmf)
286 smfCloseFile(MSeq.hSmf);
287 MSeq.hSmf = (HSMF)NULL;
290 /* take care of any stream buffers or MIDI resources left open by
295 for (lpmh = MSeq.lpmhFree; lpmh; lpmh = lpmh->lpNext)
296 midiOutUnprepareHeader(MSeq.hmidi, lpmh, sizeof(MIDIHDR));
298 if (MSeq.lpmhPreroll)
299 midiOutUnprepareHeader(MSeq.hmidi, MSeq.lpmhPreroll, sizeof(MIDIHDR));
301 midiStreamClose(MSeq.hmidi);
305 MSeq.uState = SEQ_S_NOFILE;
311 static uint funky_vol_log_table [] = {
325 int wmidi_set_volume(uint volume)
332 Assert(volume < 128);
333 if (volume == 127) volume++;
337 if (!volume) vol = 0;
338 else if (MSeq.uMCIDeviceID == 1) // WAVETABLE
339 vol = funky_vol_log_table[volume]|0x00ff;
340 else { // OPL2/OPL3 and others
341 vol = volume * 0x2000;
351 // wmidi_deamp_song(wmidi_volume);
352 mmrc = midiOutSetVolume((HMIDIOUT)MSeq.hmidi, wmidi_volume);
353 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
354 midiOutGetVolume((HMIDIOUT)MSeq.hmidi, &vol);
361 #define MIDI_CTRLCHANGE ((BYTE)0xB0) // + ctrlr + value
362 #define MIDICTRL_VOLUME ((BYTE)0x07)
365 void wmidi_deamp_song(DWORD vol)
369 DWORD dwvol, dwstatus, dwevent;
374 vol = vol & 0x0000ffff;
376 ptvol = (float)(vol)*100.0/65536.0;
377 ptdvol = (DWORD)(ptvol);
379 mprintf((0, "Deamp = %d percent.\n", ptdvol));
381 for (i = 0, dwstatus = MIDI_CTRLCHANGE; i < 16; i++, dwstatus++)
383 dwvol = ( 100 * ptdvol ) / 1000;
384 dwevent = dwstatus | ((DWORD)MIDICTRL_VOLUME << 8)
385 | ((DWORD)dwvol << 16);
386 if(( mmrc= midiOutShortMsg( (HMIDIOUT)MSeq.hmidi, dwevent ))
387 != MMSYSERR_NOERROR )
389 mprintf((1, "WINMIDI::BAD MIDI VOLUME CHANGE!\n"));
397 /*****************************************************************************
399 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
400 * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
401 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
402 * A PARTICULAR PURPOSE.
404 * Copyright (C) 1993-1995 Microsoft Corporation. All Rights Reserved.
406 ******************************************************************************/
409 PRIVATE void FAR PASCAL seqMIDICallback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
410 PRIVATE MMRESULT FNLOCAL XlatSMFErr(SMFRESULT smfrc);
412 /***************************************************************************
416 * Allocate buffers for this instance.
418 ***************************************************************************/
419 MMRESULT FNLOCAL seqAllocBuffers(
422 DWORD dwEachBufferSize;
427 Assert(pSeq != NULL);
429 pSeq->uState = SEQ_S_NOFILE;
430 pSeq->lpmhFree = NULL;
431 pSeq->lpbAlloc = NULL;
432 pSeq->hSmf = (HSMF)NULL;
434 /* First make sure we can allocate the buffers they asked for
436 dwEachBufferSize = sizeof(MIDIHDR) + (DWORD)(pSeq->cbBuffer);
437 dwAlloc = dwEachBufferSize * (DWORD)(pSeq->cBuffer);
439 pSeq->lpbAlloc = GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE, dwAlloc);
440 if (NULL == pSeq->lpbAlloc)
441 return MCIERR_OUT_OF_MEMORY;
443 /* Initialize all MIDIHDR's and throw them into a free list
445 pSeq->lpmhFree = NULL;
447 lpbWork = pSeq->lpbAlloc;
448 for (i=0; i < pSeq->cBuffer; i++)
450 ((LPMIDIHDR)lpbWork)->lpNext = pSeq->lpmhFree;
452 ((LPMIDIHDR)lpbWork)->lpData = lpbWork + sizeof(MIDIHDR);
453 ((LPMIDIHDR)lpbWork)->dwBufferLength = pSeq->cbBuffer;
454 ((LPMIDIHDR)lpbWork)->dwBytesRecorded = 0;
455 ((LPMIDIHDR)lpbWork)->dwUser = (DWORD)(UINT)pSeq;
456 ((LPMIDIHDR)lpbWork)->dwFlags = 0;
458 pSeq->lpmhFree = (LPMIDIHDR)lpbWork;
460 lpbWork += dwEachBufferSize;
463 return MMSYSERR_NOERROR;
466 /***************************************************************************
470 * Free buffers for this instance.
472 ****************************************************************************/
473 VOID FNLOCAL seqFreeBuffers(
478 Assert(pSeq != NULL);
480 if (NULL != pSeq->lpbAlloc)
482 lpmh = (LPMIDIHDR)pSeq->lpbAlloc;
483 Assert(!(lpmh->dwFlags & MHDR_PREPARED));
485 GlobalFreePtr(pSeq->lpbAlloc);
490 /***************************************************************************
494 * Prepares the file for playback at the given position.
496 ****************************************************************************/
497 MMRESULT FNLOCAL seqPreroll(
502 MMRESULT mmrc = MMSYSERR_NOERROR;
503 MIDIPROPTIMEDIV mptd;
504 LPMIDIHDR lpmh = NULL;
505 LPMIDIHDR lpmhPreroll = NULL;
506 DWORD cbPrerollBuffer;
509 Assert(pSeq != NULL);
511 pSeq->mmrcLastErr = MMSYSERR_NOERROR;
513 if (pSeq->uState != SEQ_S_OPENED &&
514 pSeq->uState != SEQ_S_PREROLLED)
515 return MCIERR_UNSUPPORTED_FUNCTION;
517 pSeq->tkBase = lpPreroll->tkBase;
518 pSeq->tkEnd = lpPreroll->tkEnd;
522 // Recollect buffers from MMSYSTEM back into free queue
524 pSeq->uState = SEQ_S_RESET;
525 midiOutReset(pSeq->hmidi);
527 while (pSeq->uBuffersInMMSYSTEM)
531 pSeq->uBuffersInMMSYSTEM = 0;
532 pSeq->uState = SEQ_S_PREROLLING;
535 // We've successfully opened the file and all of the tracks; now
536 // open the MIDI device and set the time division.
538 // NOTE: seqPreroll is equivalent to seek; device might already be open
540 if (NULL == pSeq->hmidi)
542 uDeviceID = pSeq->uDeviceID;
543 if ((mmrc = midiStreamOpen(&pSeq->hmidi,
546 (DWORD)seqMIDICallback,
548 CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
551 goto seq_Preroll_Cleanup;
554 mptd.cbStruct = sizeof(mptd);
555 mptd.dwTimeDiv = pSeq->dwTimeDivision;
556 if ((mmrc = midiStreamProperty(
559 MIDIPROP_SET|MIDIPROP_TIMEDIV)) != MMSYSERR_NOERROR)
561 mprintf((1, "midiStreamProperty() -> %04X\n", (WORD)mmrc));
562 midiStreamClose(pSeq->hmidi);
564 mmrc = MCIERR_DEVICE_NOT_READY;
565 goto seq_Preroll_Cleanup;
569 mmrc = MMSYSERR_NOERROR;
572 // Allocate a preroll buffer. Then if we don't have enough room for
573 // all the preroll info, we make the buffer larger.
575 if (!pSeq->lpmhPreroll)
577 cbPrerollBuffer = 4096;
578 lpmhPreroll = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE,
583 cbPrerollBuffer = pSeq->cbPreroll;
584 lpmhPreroll = pSeq->lpmhPreroll;
587 lpmhPreroll->lpNext = pSeq->lpmhFree;
588 lpmhPreroll->lpData = (LPBYTE)lpmhPreroll + sizeof(MIDIHDR);
589 lpmhPreroll->dwBufferLength = cbPrerollBuffer - sizeof(MIDIHDR);
590 lpmhPreroll->dwBytesRecorded = 0;
591 lpmhPreroll->dwUser = (DWORD)(UINT)pSeq;
592 lpmhPreroll->dwFlags = 0;
596 smfrc = smfSeek(pSeq->hSmf, pSeq->tkBase, lpmhPreroll);
597 if( SMF_SUCCESS != smfrc )
599 if( ( SMF_NO_MEMORY != smfrc ) ||
600 ( cbPrerollBuffer >= 32768L ) )
602 mprintf((1, "smfSeek() returned %lu\n", (DWORD)smfrc));
604 GlobalFreePtr(lpmhPreroll);
605 pSeq->lpmhPreroll = NULL;
607 mmrc = XlatSMFErr(smfrc);
608 goto seq_Preroll_Cleanup;
610 else // Try to grow buffer.
612 cbPrerollBuffer *= 2;
613 lpmh = (LPMIDIHDR)GlobalReAllocPtr( lpmhPreroll, cbPrerollBuffer, 0 );
616 mprintf((1,"seqPreroll - realloc failed, aborting preroll.\n"));
617 mmrc = MCIERR_OUT_OF_MEMORY;
618 goto seq_Preroll_Cleanup;
622 lpmhPreroll->lpData = (LPBYTE)lpmhPreroll + sizeof(MIDIHDR);
623 lpmhPreroll->dwBufferLength = cbPrerollBuffer - sizeof(MIDIHDR);
625 pSeq->lpmhPreroll = lpmhPreroll;
626 pSeq->cbPreroll = cbPrerollBuffer;
629 } while( SMF_SUCCESS != smfrc );
631 if (MMSYSERR_NOERROR != (mmrc = midiOutPrepareHeader(pSeq->hmidi, lpmhPreroll, sizeof(MIDIHDR))))
633 mprintf((1, "midiOutPrepare(preroll) -> %lu!\n", (DWORD)mmrc));
635 mmrc = MCIERR_DEVICE_NOT_READY;
636 goto seq_Preroll_Cleanup;
639 ++pSeq->uBuffersInMMSYSTEM;
641 if (MMSYSERR_NOERROR != (mmrc = midiStreamOut(pSeq->hmidi, lpmhPreroll, sizeof(MIDIHDR))))
643 mprintf((1, "midiStreamOut(preroll) -> %lu!\n", (DWORD)mmrc));
645 mmrc = MCIERR_DEVICE_NOT_READY;
646 --pSeq->uBuffersInMMSYSTEM;
647 goto seq_Preroll_Cleanup;
649 mprintf((1,"seqPreroll: midiStreamOut(0x%x,0x%lx,%u) returned %u.\n",pSeq->hmidi,lpmhPreroll,sizeof(MIDIHDR),mmrc));
651 pSeq->fdwSeq &= ~SEQ_F_EOF;
652 while (pSeq->lpmhFree)
654 lpmh = pSeq->lpmhFree;
655 pSeq->lpmhFree = lpmh->lpNext;
657 smfrc = smfReadEvents(pSeq->hSmf, lpmh, pSeq->tkEnd);
658 if (SMF_SUCCESS != smfrc && SMF_END_OF_FILE != smfrc)
660 mprintf((1, "SFP: smfReadEvents() -> %u\n", (UINT)smfrc));
661 mmrc = XlatSMFErr(smfrc);
662 goto seq_Preroll_Cleanup;
665 if (MMSYSERR_NOERROR != (mmrc = midiOutPrepareHeader(pSeq->hmidi, lpmh, sizeof(*lpmh))))
667 mprintf((1, "SFP: midiOutPrepareHeader failed\n"));
668 goto seq_Preroll_Cleanup;
671 if (MMSYSERR_NOERROR != (mmrc = midiStreamOut(pSeq->hmidi, lpmh, sizeof(*lpmh))))
673 mprintf((1, "SFP: midiStreamOut failed\n"));
674 goto seq_Preroll_Cleanup;
677 ++pSeq->uBuffersInMMSYSTEM;
679 if (SMF_END_OF_FILE == smfrc)
681 pSeq->fdwSeq |= SEQ_F_EOF;
687 if (MMSYSERR_NOERROR != mmrc)
689 pSeq->uState = SEQ_S_OPENED;
690 pSeq->fdwSeq &= ~SEQ_F_WAITING;
694 pSeq->uState = SEQ_S_PREROLLED;
700 /***************************************************************************
704 * Starts playback at the current position.
706 ***************************************************************************/
707 MMRESULT FNLOCAL seqStart(
710 Assert(NULL != pSeq);
712 if (SEQ_S_PREROLLED != pSeq->uState)
714 mprintf((1, "seqStart(): State is wrong! [%u]\n", pSeq->uState));
715 return MCIERR_UNSUPPORTED_FUNCTION;
718 pSeq->uState = SEQ_S_PLAYING;
720 return midiStreamRestart(pSeq->hmidi);
723 /***************************************************************************
727 ***************************************************************************/
728 MMRESULT FNLOCAL seqPause(
731 Assert(NULL != pSeq);
733 if (SEQ_S_PLAYING != pSeq->uState)
734 return MCIERR_UNSUPPORTED_FUNCTION;
736 pSeq->uState = SEQ_S_PAUSED;
737 midiStreamPause(pSeq->hmidi);
739 return MMSYSERR_NOERROR;
742 /***************************************************************************
746 ***************************************************************************/
747 MMRESULT FNLOCAL seqRestart(
750 Assert(NULL != pSeq);
752 if (SEQ_S_PAUSED != pSeq->uState)
753 return MCIERR_UNSUPPORTED_FUNCTION;
755 pSeq->uState = SEQ_S_PLAYING;
756 midiStreamRestart(pSeq->hmidi);
758 return MMSYSERR_NOERROR;
761 /***************************************************************************
765 * Totally stops playback of an instance.
767 ***************************************************************************/
768 MMRESULT FNLOCAL seqStop(
771 Assert(NULL != pSeq);
773 /* Automatic success if we're already stopped
775 if (SEQ_S_PLAYING != pSeq->uState &&
776 SEQ_S_PAUSED != pSeq->uState)
778 pSeq->fdwSeq &= ~SEQ_F_WAITING;
779 return MMSYSERR_NOERROR;
782 pSeq->uState = SEQ_S_STOPPING;
783 pSeq->fdwSeq |= SEQ_F_WAITING;
785 if (MMSYSERR_NOERROR != (pSeq->mmrcLastErr = midiStreamStop(pSeq->hmidi)))
787 mprintf((1, "midiOutStop() returned %lu in seqStop()!\n", (DWORD)pSeq->mmrcLastErr));
789 pSeq->fdwSeq &= ~SEQ_F_WAITING;
790 return MCIERR_DEVICE_NOT_READY;
793 while (pSeq->uBuffersInMMSYSTEM)
796 return MMSYSERR_NOERROR;
799 /***************************************************************************
803 ***************************************************************************/
804 MMRESULT FNLOCAL seqTime(
811 Assert(pSeq != NULL);
813 if (SEQ_S_PLAYING != pSeq->uState &&
814 SEQ_S_PAUSED != pSeq->uState &&
815 SEQ_S_PREROLLING != pSeq->uState &&
816 SEQ_S_PREROLLED != pSeq->uState &&
817 SEQ_S_OPENED != pSeq->uState)
819 mprintf((1, "seqTime(): State wrong! [is %u]\n", pSeq->uState));
820 return MCIERR_UNSUPPORTED_FUNCTION;
824 if (SEQ_S_OPENED != pSeq->uState)
826 *pTicks = pSeq->tkBase;
827 if (SEQ_S_PREROLLED != pSeq->uState)
829 mmt.wType = TIME_TICKS;
830 mmr = midiStreamPosition(pSeq->hmidi, &mmt, sizeof(mmt));
831 if (MMSYSERR_NOERROR != mmr)
833 mprintf((1, "midiStreamPosition() returned %lu\n", (DWORD)mmr));
834 return MCIERR_DEVICE_NOT_READY;
837 *pTicks += mmt.u.ticks;
841 return MMSYSERR_NOERROR;
844 /***************************************************************************
846 * seqMillisecsToTicks
848 * Given a millisecond offset in the output stream, returns the associated
851 ***************************************************************************/
852 TICKS FNLOCAL seqMillisecsToTicks(
856 return smfMillisecsToTicks(pSeq->hSmf, msOffset);
859 /***************************************************************************
861 * seqTicksToMillisecs
863 * Given a tick offset in the output stream, returns the associated
864 * millisecond position.
866 ***************************************************************************/
867 DWORD FNLOCAL seqTicksToMillisecs(
871 return smfTicksToMillisecs(pSeq->hSmf, tkOffset);
874 /***************************************************************************
878 * Called by the system when a buffer is done
880 * dw1 - The buffer that has completed playback.
882 ***************************************************************************/
884 PRIVATE void FAR PASCAL seqMIDICallback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
886 LPMIDIHDR lpmh = (LPMIDIHDR)dw1;
892 if (uMsg != MOM_DONE)
895 Assert(NULL != lpmh);
897 pSeq = (PSEQ)(lpmh->dwUser);
899 Assert(pSeq != NULL);
901 --pSeq->uBuffersInMMSYSTEM;
903 if (pSeq->uState == SEQ_S_NOFILE)
904 mprintf((1, "seqCallback: No file!!\n"));
906 if (SEQ_S_RESET == pSeq->uState)
908 // We're recollecting buffers from MMSYSTEM
910 if (lpmh != pSeq->lpmhPreroll)
912 lpmh->lpNext = pSeq->lpmhFree;
913 pSeq->lpmhFree = lpmh;
920 if ((SEQ_S_STOPPING == pSeq->uState) || (pSeq->fdwSeq & SEQ_F_EOF))
923 ** Reached EOF, just put the buffer back on the free
926 if (lpmh != pSeq->lpmhPreroll)
928 lpmh->lpNext = pSeq->lpmhFree;
929 pSeq->lpmhFree = lpmh;
932 mprintf((1, "seqCallback: NULL MIDI HANDLE.\n"));
934 if (MMSYSERR_NOERROR != (mmrc = midiOutUnprepareHeader(pSeq->hmidi, lpmh, sizeof(*lpmh))))
936 mprintf((1, "midiOutUnprepareHeader failed in seqBufferDone! (%lu)\n", (DWORD)mmrc));
939 if (0 == pSeq->uBuffersInMMSYSTEM)
942 mprintf((1, "seqBufferDone: normal sequencer shutdown.\n"));
944 /* Totally done! Free device and notify.
946 midiStreamClose(pSeq->hmidi);
948 if ((SEQ_S_STOPPING == pSeq->uState) && (pSeq->fdwSeq & SEQ_F_EOF) && LoopSong) {
950 mprintf((1, "seqMIDICallback: cancelling loop.\n"));
953 pSeq->uState = SEQ_S_OPENED;
954 pSeq->mmrcLastErr = MMSYSERR_NOERROR;
955 pSeq->fdwSeq &= ~SEQ_F_WAITING;
957 if ((pSeq->fdwSeq & SEQ_F_EOF) && LoopSong && !stop_loop)
964 ** Not EOF yet; attempt to fill another buffer
968 smfrc = smfReadEvents(pSeq->hSmf, lpmh, pSeq->tkEnd);
975 case SMF_END_OF_FILE:
976 pSeq->fdwSeq |= SEQ_F_EOF;
981 mprintf((1, "smfReadEvents returned %lu in callback!\n", (DWORD)smfrc));
982 pSeq->uState = SEQ_S_STOPPING;
986 if (SMF_SUCCESS == smfrc)
988 ++pSeq->uBuffersInMMSYSTEM;
990 Assert(pSeq->hmidi != NULL);
992 // wmidi_deamp_song(wmidi_volume);
993 mmrc = midiOutSetVolume((HMIDIOUT)MIDI_MAPPER, wmidi_volume);
994 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
995 midiOutGetVolume((HMIDIOUT)MIDI_MAPPER, &vol);
997 mmrc = midiStreamOut(pSeq->hmidi, lpmh, sizeof(*lpmh));
999 if (MMSYSERR_NOERROR != mmrc)
1001 mprintf((1, "seqBufferDone(): midiStreamOut() returned %lu!\n", (DWORD)mmrc));
1003 --pSeq->uBuffersInMMSYSTEM;
1004 pSeq->uState = SEQ_S_STOPPING;
1005 --pSeq->uBuffersInMMSYSTEM;
1006 pSeq->uState = SEQ_S_STOPPING;
1013 /***************************************************************************
1017 * Translates an error from the SMF layer into an appropriate MCI error.
1019 ***************************************************************************/
1020 PRIVATE MMRESULT FNLOCAL XlatSMFErr(
1026 return MMSYSERR_NOERROR;
1029 return MCIERR_OUT_OF_MEMORY;
1031 case SMF_INVALID_FILE:
1032 case SMF_OPEN_FAILED:
1033 case SMF_INVALID_TRACK:
1034 return MCIERR_INVALID_FILE;
1037 return MCIERR_UNSUPPORTED_FUNCTION;