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.
20 #define WIN32_LEAN_AND_MEAN
40 // ----------------------------------------------------------------------------
42 // ----------------------------------------------------------------------------
44 BOOL WMidi_NewStream = 0;
46 static BOOL WMidi_initialized = FALSE;
48 static DWORD wmidi_volume = 0x80008000;
49 static BOOL LoopSong = FALSE;
50 static BOOL MidiVolChanges = TRUE;
53 void wmidi_deamp_song(DWORD vol);
55 void CALLBACK wmidi_seq_callback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
58 // ----------------------------------------------------------------------------
59 // Sequencer Initialization and destruction
60 // ----------------------------------------------------------------------------
62 int wmidi_init(uint mmdev)
70 memset(&MSeq, 0, sizeof(SEQ));
72 WMidi_initialized = TRUE;
74 // Initialize stream buffers
75 MSeq.uState = SEQ_S_NOFILE;
83 if (seqAllocBuffers(&MSeq) != MMSYSERR_NOERROR)
86 // Setup sequencer some more
87 ui = midiOutGetDevCaps(mmdev, &midicaps, sizeof(midicaps));
88 if ( ui != MMSYSERR_NOERROR) {
89 mprintf((1, "WMIDI:(%x) Unable to find requested device.\n", MSeq.mmrcLastErr));
93 if ((midicaps.dwSupport & MIDICAPS_VOLUME) || (midicaps.dwSupport & MIDICAPS_LRVOLUME))
94 MidiVolChanges = TRUE;
95 else MidiVolChanges = FALSE;
97 MSeq.uDeviceID = mmdev;
99 // Now we must do a stupid Microsoft trick to determine whether we are
100 // using WAVE TABLE volume or OPL volume.
101 MSeq.uMCIDeviceID = wmidi_get_tech();
103 logentry("MIDI technology: %d.\n", MSeq.uMCIDeviceID);
113 Assert(WMidi_initialized == TRUE);
115 seqFreeBuffers(&MSeq);
117 WMidi_initialized = FALSE;
131 lres = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Multimedia\\MIDIMap",
132 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_EXECUTE,
134 if (lres != ERROR_SUCCESS) return 0;
137 lres = RegQueryValueEx(hKey, "CurrentInstrument", NULL, &type, key, &len);
138 if (lres != ERROR_SUCCESS) {
145 strcpy(buf, "System\\CurrentControlSet\\control\\MediaResources\\midi\\");
147 lres = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buf,
148 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_EXECUTE,
150 if (lres != ERROR_SUCCESS) return 0;
153 lres = RegQueryValueEx(hKey, "Description", NULL, &type, buf, &len);
154 if (lres != ERROR_SUCCESS) {
160 // Okay, look for 'wave' or 'fm' or 'opl'
162 if (strstr(pstr, "wave")) return 1;
168 int wmidi_support_volchange() {
169 return (int)MidiVolChanges;
173 // ----------------------------------------------------------------------------
174 // High level midi song play/stop/pause interface
175 // ----------------------------------------------------------------------------
177 int wmidi_init_song(WMIDISONG *song)
183 if (MSeq.uState != SEQ_S_NOFILE) return 0;
185 Assert (song->data != NULL);
187 mmrc = seqStop(&MSeq);
188 if (mmrc != MMSYSERR_NOERROR)
190 mprintf((1, "WMIDI: Stop song failed.\n"));;
196 if (song->looping) LoopSong = TRUE;
197 else LoopSong = FALSE;
199 if (smfOpenFile(song->data, song->length, (HSMF *)&smf) != SMF_SUCCESS) return 0;
201 // song is confirmed to be a MIDI v1.0 compatible file
203 MSeq.dwTimeDivision = smf->dwTimeDivision;
204 MSeq.tkLength = smf->tkLength;
205 MSeq.cTrk = smf->dwTracks;
207 bufsize = min(MSeq.cbBuffer, smfGetStateMaxSize());
209 MSeq.uState = SEQ_S_OPENED;
222 preroll.tkEnd = MSeq.tkLength;
224 mprintf((1, "wmidi_play: beginning playback.\n"));
226 if ((mmrc = seqPreroll(&MSeq, &preroll)) != MMSYSERR_NOERROR) {
227 mprintf((1, "wmidi_play: preroll failed! (%x)\n", mmrc));
232 Assert(MSeq.hmidi != NULL);
234 // wmidi_deamp_song(wmidi_volume);
236 mmrc = midiOutSetVolume((HMIDIOUT)MSeq.hmidi, wmidi_volume);
237 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
238 midiOutGetVolume((HMIDIOUT)MSeq.hmidi, &vol);
240 if (seqStart(&MSeq) != MMSYSERR_NOERROR) return 0;
248 if (seqStop(&MSeq) != MMSYSERR_NOERROR) return 0;
255 if (MSeq.uState != SEQ_S_PAUSED) {
256 if (seqPause(&MSeq) != MMSYSERR_NOERROR) return 0;
263 if (MSeq.uState == SEQ_S_PAUSED) {
264 if (seqRestart(&MSeq) != MMSYSERR_NOERROR) return 0;
270 int wmidi_close_song()
275 if (SEQ_S_OPENED != MSeq.uState)
276 return MCIERR_UNSUPPORTED_FUNCTION;
280 if ((HSMF)NULL != MSeq.hSmf)
282 smfCloseFile(MSeq.hSmf);
283 MSeq.hSmf = (HSMF)NULL;
286 /* take care of any stream buffers or MIDI resources left open by
291 for (lpmh = MSeq.lpmhFree; lpmh; lpmh = lpmh->lpNext)
292 midiOutUnprepareHeader(MSeq.hmidi, lpmh, sizeof(MIDIHDR));
294 if (MSeq.lpmhPreroll)
295 midiOutUnprepareHeader(MSeq.hmidi, MSeq.lpmhPreroll, sizeof(MIDIHDR));
297 midiStreamClose(MSeq.hmidi);
301 MSeq.uState = SEQ_S_NOFILE;
307 static uint funky_vol_log_table [] = {
321 int wmidi_set_volume(uint volume)
328 Assert(volume < 128);
329 if (volume == 127) volume++;
333 if (!volume) vol = 0;
334 else if (MSeq.uMCIDeviceID == 1) // WAVETABLE
335 vol = funky_vol_log_table[volume]|0x00ff;
336 else { // OPL2/OPL3 and others
337 vol = volume * 0x2000;
347 // wmidi_deamp_song(wmidi_volume);
348 mmrc = midiOutSetVolume((HMIDIOUT)MSeq.hmidi, wmidi_volume);
349 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
350 midiOutGetVolume((HMIDIOUT)MSeq.hmidi, &vol);
357 #define MIDI_CTRLCHANGE ((BYTE)0xB0) // + ctrlr + value
358 #define MIDICTRL_VOLUME ((BYTE)0x07)
361 void wmidi_deamp_song(DWORD vol)
365 DWORD dwvol, dwstatus, dwevent;
370 vol = vol & 0x0000ffff;
372 ptvol = (float)(vol)*100.0/65536.0;
373 ptdvol = (DWORD)(ptvol);
375 mprintf((0, "Deamp = %d percent.\n", ptdvol));
377 for (i = 0, dwstatus = MIDI_CTRLCHANGE; i < 16; i++, dwstatus++)
379 dwvol = ( 100 * ptdvol ) / 1000;
380 dwevent = dwstatus | ((DWORD)MIDICTRL_VOLUME << 8)
381 | ((DWORD)dwvol << 16);
382 if(( mmrc= midiOutShortMsg( (HMIDIOUT)MSeq.hmidi, dwevent ))
383 != MMSYSERR_NOERROR )
385 mprintf((1, "WINMIDI::BAD MIDI VOLUME CHANGE!\n"));
393 /*****************************************************************************
395 * THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
396 * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
397 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
398 * A PARTICULAR PURPOSE.
400 * Copyright (C) 1993-1995 Microsoft Corporation. All Rights Reserved.
402 ******************************************************************************/
405 PRIVATE void FAR PASCAL seqMIDICallback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2);
406 PRIVATE MMRESULT FNLOCAL XlatSMFErr(SMFRESULT smfrc);
408 /***************************************************************************
412 * Allocate buffers for this instance.
414 ***************************************************************************/
415 MMRESULT FNLOCAL seqAllocBuffers(
418 DWORD dwEachBufferSize;
423 Assert(pSeq != NULL);
425 pSeq->uState = SEQ_S_NOFILE;
426 pSeq->lpmhFree = NULL;
427 pSeq->lpbAlloc = NULL;
428 pSeq->hSmf = (HSMF)NULL;
430 /* First make sure we can allocate the buffers they asked for
432 dwEachBufferSize = sizeof(MIDIHDR) + (DWORD)(pSeq->cbBuffer);
433 dwAlloc = dwEachBufferSize * (DWORD)(pSeq->cBuffer);
435 pSeq->lpbAlloc = GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE, dwAlloc);
436 if (NULL == pSeq->lpbAlloc)
437 return MCIERR_OUT_OF_MEMORY;
439 /* Initialize all MIDIHDR's and throw them into a free list
441 pSeq->lpmhFree = NULL;
443 lpbWork = pSeq->lpbAlloc;
444 for (i=0; i < pSeq->cBuffer; i++)
446 ((LPMIDIHDR)lpbWork)->lpNext = pSeq->lpmhFree;
448 ((LPMIDIHDR)lpbWork)->lpData = lpbWork + sizeof(MIDIHDR);
449 ((LPMIDIHDR)lpbWork)->dwBufferLength = pSeq->cbBuffer;
450 ((LPMIDIHDR)lpbWork)->dwBytesRecorded = 0;
451 ((LPMIDIHDR)lpbWork)->dwUser = (DWORD)(UINT)pSeq;
452 ((LPMIDIHDR)lpbWork)->dwFlags = 0;
454 pSeq->lpmhFree = (LPMIDIHDR)lpbWork;
456 lpbWork += dwEachBufferSize;
459 return MMSYSERR_NOERROR;
462 /***************************************************************************
466 * Free buffers for this instance.
468 ****************************************************************************/
469 VOID FNLOCAL seqFreeBuffers(
474 Assert(pSeq != NULL);
476 if (NULL != pSeq->lpbAlloc)
478 lpmh = (LPMIDIHDR)pSeq->lpbAlloc;
479 Assert(!(lpmh->dwFlags & MHDR_PREPARED));
481 GlobalFreePtr(pSeq->lpbAlloc);
486 /***************************************************************************
490 * Prepares the file for playback at the given position.
492 ****************************************************************************/
493 MMRESULT FNLOCAL seqPreroll(
498 MMRESULT mmrc = MMSYSERR_NOERROR;
499 MIDIPROPTIMEDIV mptd;
500 LPMIDIHDR lpmh = NULL;
501 LPMIDIHDR lpmhPreroll = NULL;
502 DWORD cbPrerollBuffer;
505 Assert(pSeq != NULL);
507 pSeq->mmrcLastErr = MMSYSERR_NOERROR;
509 if (pSeq->uState != SEQ_S_OPENED &&
510 pSeq->uState != SEQ_S_PREROLLED)
511 return MCIERR_UNSUPPORTED_FUNCTION;
513 pSeq->tkBase = lpPreroll->tkBase;
514 pSeq->tkEnd = lpPreroll->tkEnd;
518 // Recollect buffers from MMSYSTEM back into free queue
520 pSeq->uState = SEQ_S_RESET;
521 midiOutReset(pSeq->hmidi);
523 while (pSeq->uBuffersInMMSYSTEM)
527 pSeq->uBuffersInMMSYSTEM = 0;
528 pSeq->uState = SEQ_S_PREROLLING;
531 // We've successfully opened the file and all of the tracks; now
532 // open the MIDI device and set the time division.
534 // NOTE: seqPreroll is equivalent to seek; device might already be open
536 if (NULL == pSeq->hmidi)
538 uDeviceID = pSeq->uDeviceID;
539 if ((mmrc = midiStreamOpen(&pSeq->hmidi,
542 (DWORD)seqMIDICallback,
544 CALLBACK_FUNCTION)) != MMSYSERR_NOERROR)
547 goto seq_Preroll_Cleanup;
550 mptd.cbStruct = sizeof(mptd);
551 mptd.dwTimeDiv = pSeq->dwTimeDivision;
552 if ((mmrc = midiStreamProperty(
555 MIDIPROP_SET|MIDIPROP_TIMEDIV)) != MMSYSERR_NOERROR)
557 mprintf((1, "midiStreamProperty() -> %04X\n", (WORD)mmrc));
558 midiStreamClose(pSeq->hmidi);
560 mmrc = MCIERR_DEVICE_NOT_READY;
561 goto seq_Preroll_Cleanup;
565 mmrc = MMSYSERR_NOERROR;
568 // Allocate a preroll buffer. Then if we don't have enough room for
569 // all the preroll info, we make the buffer larger.
571 if (!pSeq->lpmhPreroll)
573 cbPrerollBuffer = 4096;
574 lpmhPreroll = (LPMIDIHDR)GlobalAllocPtr(GMEM_MOVEABLE|GMEM_SHARE,
579 cbPrerollBuffer = pSeq->cbPreroll;
580 lpmhPreroll = pSeq->lpmhPreroll;
583 lpmhPreroll->lpNext = pSeq->lpmhFree;
584 lpmhPreroll->lpData = (LPBYTE)lpmhPreroll + sizeof(MIDIHDR);
585 lpmhPreroll->dwBufferLength = cbPrerollBuffer - sizeof(MIDIHDR);
586 lpmhPreroll->dwBytesRecorded = 0;
587 lpmhPreroll->dwUser = (DWORD)(UINT)pSeq;
588 lpmhPreroll->dwFlags = 0;
592 smfrc = smfSeek(pSeq->hSmf, pSeq->tkBase, lpmhPreroll);
593 if( SMF_SUCCESS != smfrc )
595 if( ( SMF_NO_MEMORY != smfrc ) ||
596 ( cbPrerollBuffer >= 32768L ) )
598 mprintf((1, "smfSeek() returned %lu\n", (DWORD)smfrc));
600 GlobalFreePtr(lpmhPreroll);
601 pSeq->lpmhPreroll = NULL;
603 mmrc = XlatSMFErr(smfrc);
604 goto seq_Preroll_Cleanup;
606 else // Try to grow buffer.
608 cbPrerollBuffer *= 2;
609 lpmh = (LPMIDIHDR)GlobalReAllocPtr( lpmhPreroll, cbPrerollBuffer, 0 );
612 mprintf((1,"seqPreroll - realloc failed, aborting preroll.\n"));
613 mmrc = MCIERR_OUT_OF_MEMORY;
614 goto seq_Preroll_Cleanup;
618 lpmhPreroll->lpData = (LPBYTE)lpmhPreroll + sizeof(MIDIHDR);
619 lpmhPreroll->dwBufferLength = cbPrerollBuffer - sizeof(MIDIHDR);
621 pSeq->lpmhPreroll = lpmhPreroll;
622 pSeq->cbPreroll = cbPrerollBuffer;
625 } while( SMF_SUCCESS != smfrc );
627 if (MMSYSERR_NOERROR != (mmrc = midiOutPrepareHeader(pSeq->hmidi, lpmhPreroll, sizeof(MIDIHDR))))
629 mprintf((1, "midiOutPrepare(preroll) -> %lu!\n", (DWORD)mmrc));
631 mmrc = MCIERR_DEVICE_NOT_READY;
632 goto seq_Preroll_Cleanup;
635 ++pSeq->uBuffersInMMSYSTEM;
637 if (MMSYSERR_NOERROR != (mmrc = midiStreamOut(pSeq->hmidi, lpmhPreroll, sizeof(MIDIHDR))))
639 mprintf((1, "midiStreamOut(preroll) -> %lu!\n", (DWORD)mmrc));
641 mmrc = MCIERR_DEVICE_NOT_READY;
642 --pSeq->uBuffersInMMSYSTEM;
643 goto seq_Preroll_Cleanup;
645 mprintf((1,"seqPreroll: midiStreamOut(0x%x,0x%lx,%u) returned %u.\n",pSeq->hmidi,lpmhPreroll,sizeof(MIDIHDR),mmrc));
647 pSeq->fdwSeq &= ~SEQ_F_EOF;
648 while (pSeq->lpmhFree)
650 lpmh = pSeq->lpmhFree;
651 pSeq->lpmhFree = lpmh->lpNext;
653 smfrc = smfReadEvents(pSeq->hSmf, lpmh, pSeq->tkEnd);
654 if (SMF_SUCCESS != smfrc && SMF_END_OF_FILE != smfrc)
656 mprintf((1, "SFP: smfReadEvents() -> %u\n", (UINT)smfrc));
657 mmrc = XlatSMFErr(smfrc);
658 goto seq_Preroll_Cleanup;
661 if (MMSYSERR_NOERROR != (mmrc = midiOutPrepareHeader(pSeq->hmidi, lpmh, sizeof(*lpmh))))
663 mprintf((1, "SFP: midiOutPrepareHeader failed\n"));
664 goto seq_Preroll_Cleanup;
667 if (MMSYSERR_NOERROR != (mmrc = midiStreamOut(pSeq->hmidi, lpmh, sizeof(*lpmh))))
669 mprintf((1, "SFP: midiStreamOut failed\n"));
670 goto seq_Preroll_Cleanup;
673 ++pSeq->uBuffersInMMSYSTEM;
675 if (SMF_END_OF_FILE == smfrc)
677 pSeq->fdwSeq |= SEQ_F_EOF;
683 if (MMSYSERR_NOERROR != mmrc)
685 pSeq->uState = SEQ_S_OPENED;
686 pSeq->fdwSeq &= ~SEQ_F_WAITING;
690 pSeq->uState = SEQ_S_PREROLLED;
696 /***************************************************************************
700 * Starts playback at the current position.
702 ***************************************************************************/
703 MMRESULT FNLOCAL seqStart(
706 Assert(NULL != pSeq);
708 if (SEQ_S_PREROLLED != pSeq->uState)
710 mprintf((1, "seqStart(): State is wrong! [%u]\n", pSeq->uState));
711 return MCIERR_UNSUPPORTED_FUNCTION;
714 pSeq->uState = SEQ_S_PLAYING;
716 return midiStreamRestart(pSeq->hmidi);
719 /***************************************************************************
723 ***************************************************************************/
724 MMRESULT FNLOCAL seqPause(
727 Assert(NULL != pSeq);
729 if (SEQ_S_PLAYING != pSeq->uState)
730 return MCIERR_UNSUPPORTED_FUNCTION;
732 pSeq->uState = SEQ_S_PAUSED;
733 midiStreamPause(pSeq->hmidi);
735 return MMSYSERR_NOERROR;
738 /***************************************************************************
742 ***************************************************************************/
743 MMRESULT FNLOCAL seqRestart(
746 Assert(NULL != pSeq);
748 if (SEQ_S_PAUSED != pSeq->uState)
749 return MCIERR_UNSUPPORTED_FUNCTION;
751 pSeq->uState = SEQ_S_PLAYING;
752 midiStreamRestart(pSeq->hmidi);
754 return MMSYSERR_NOERROR;
757 /***************************************************************************
761 * Totally stops playback of an instance.
763 ***************************************************************************/
764 MMRESULT FNLOCAL seqStop(
767 Assert(NULL != pSeq);
769 /* Automatic success if we're already stopped
771 if (SEQ_S_PLAYING != pSeq->uState &&
772 SEQ_S_PAUSED != pSeq->uState)
774 pSeq->fdwSeq &= ~SEQ_F_WAITING;
775 return MMSYSERR_NOERROR;
778 pSeq->uState = SEQ_S_STOPPING;
779 pSeq->fdwSeq |= SEQ_F_WAITING;
781 if (MMSYSERR_NOERROR != (pSeq->mmrcLastErr = midiStreamStop(pSeq->hmidi)))
783 mprintf((1, "midiOutStop() returned %lu in seqStop()!\n", (DWORD)pSeq->mmrcLastErr));
785 pSeq->fdwSeq &= ~SEQ_F_WAITING;
786 return MCIERR_DEVICE_NOT_READY;
789 while (pSeq->uBuffersInMMSYSTEM)
792 return MMSYSERR_NOERROR;
795 /***************************************************************************
799 ***************************************************************************/
800 MMRESULT FNLOCAL seqTime(
807 Assert(pSeq != NULL);
809 if (SEQ_S_PLAYING != pSeq->uState &&
810 SEQ_S_PAUSED != pSeq->uState &&
811 SEQ_S_PREROLLING != pSeq->uState &&
812 SEQ_S_PREROLLED != pSeq->uState &&
813 SEQ_S_OPENED != pSeq->uState)
815 mprintf((1, "seqTime(): State wrong! [is %u]\n", pSeq->uState));
816 return MCIERR_UNSUPPORTED_FUNCTION;
820 if (SEQ_S_OPENED != pSeq->uState)
822 *pTicks = pSeq->tkBase;
823 if (SEQ_S_PREROLLED != pSeq->uState)
825 mmt.wType = TIME_TICKS;
826 mmr = midiStreamPosition(pSeq->hmidi, &mmt, sizeof(mmt));
827 if (MMSYSERR_NOERROR != mmr)
829 mprintf((1, "midiStreamPosition() returned %lu\n", (DWORD)mmr));
830 return MCIERR_DEVICE_NOT_READY;
833 *pTicks += mmt.u.ticks;
837 return MMSYSERR_NOERROR;
840 /***************************************************************************
842 * seqMillisecsToTicks
844 * Given a millisecond offset in the output stream, returns the associated
847 ***************************************************************************/
848 TICKS FNLOCAL seqMillisecsToTicks(
852 return smfMillisecsToTicks(pSeq->hSmf, msOffset);
855 /***************************************************************************
857 * seqTicksToMillisecs
859 * Given a tick offset in the output stream, returns the associated
860 * millisecond position.
862 ***************************************************************************/
863 DWORD FNLOCAL seqTicksToMillisecs(
867 return smfTicksToMillisecs(pSeq->hSmf, tkOffset);
870 /***************************************************************************
874 * Called by the system when a buffer is done
876 * dw1 - The buffer that has completed playback.
878 ***************************************************************************/
880 PRIVATE void FAR PASCAL seqMIDICallback(HMIDISTRM hms, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
882 LPMIDIHDR lpmh = (LPMIDIHDR)dw1;
888 if (uMsg != MOM_DONE)
891 Assert(NULL != lpmh);
893 pSeq = (PSEQ)(lpmh->dwUser);
895 Assert(pSeq != NULL);
897 --pSeq->uBuffersInMMSYSTEM;
899 if (pSeq->uState == SEQ_S_NOFILE)
900 mprintf((1, "seqCallback: No file!!\n"));
902 if (SEQ_S_RESET == pSeq->uState)
904 // We're recollecting buffers from MMSYSTEM
906 if (lpmh != pSeq->lpmhPreroll)
908 lpmh->lpNext = pSeq->lpmhFree;
909 pSeq->lpmhFree = lpmh;
916 if ((SEQ_S_STOPPING == pSeq->uState) || (pSeq->fdwSeq & SEQ_F_EOF))
919 ** Reached EOF, just put the buffer back on the free
922 if (lpmh != pSeq->lpmhPreroll)
924 lpmh->lpNext = pSeq->lpmhFree;
925 pSeq->lpmhFree = lpmh;
928 mprintf((1, "seqCallback: NULL MIDI HANDLE.\n"));
930 if (MMSYSERR_NOERROR != (mmrc = midiOutUnprepareHeader(pSeq->hmidi, lpmh, sizeof(*lpmh))))
932 mprintf((1, "midiOutUnprepareHeader failed in seqBufferDone! (%lu)\n", (DWORD)mmrc));
935 if (0 == pSeq->uBuffersInMMSYSTEM)
938 mprintf((1, "seqBufferDone: normal sequencer shutdown.\n"));
940 /* Totally done! Free device and notify.
942 midiStreamClose(pSeq->hmidi);
944 if ((SEQ_S_STOPPING == pSeq->uState) && (pSeq->fdwSeq & SEQ_F_EOF) && LoopSong) {
946 mprintf((1, "seqMIDICallback: cancelling loop.\n"));
949 pSeq->uState = SEQ_S_OPENED;
950 pSeq->mmrcLastErr = MMSYSERR_NOERROR;
951 pSeq->fdwSeq &= ~SEQ_F_WAITING;
953 if ((pSeq->fdwSeq & SEQ_F_EOF) && LoopSong && !stop_loop)
960 ** Not EOF yet; attempt to fill another buffer
964 smfrc = smfReadEvents(pSeq->hSmf, lpmh, pSeq->tkEnd);
971 case SMF_END_OF_FILE:
972 pSeq->fdwSeq |= SEQ_F_EOF;
977 mprintf((1, "smfReadEvents returned %lu in callback!\n", (DWORD)smfrc));
978 pSeq->uState = SEQ_S_STOPPING;
982 if (SMF_SUCCESS == smfrc)
984 ++pSeq->uBuffersInMMSYSTEM;
986 Assert(pSeq->hmidi != NULL);
988 // wmidi_deamp_song(wmidi_volume);
989 mmrc = midiOutSetVolume((HMIDIOUT)MIDI_MAPPER, wmidi_volume);
990 if (mmrc != MMSYSERR_NOERROR) mprintf((1, "MIDI VOL ERR: %d\n", mmrc));
991 midiOutGetVolume((HMIDIOUT)MIDI_MAPPER, &vol);
993 mmrc = midiStreamOut(pSeq->hmidi, lpmh, sizeof(*lpmh));
995 if (MMSYSERR_NOERROR != mmrc)
997 mprintf((1, "seqBufferDone(): midiStreamOut() returned %lu!\n", (DWORD)mmrc));
999 --pSeq->uBuffersInMMSYSTEM;
1000 pSeq->uState = SEQ_S_STOPPING;
1001 --pSeq->uBuffersInMMSYSTEM;
1002 pSeq->uState = SEQ_S_STOPPING;
1009 /***************************************************************************
1013 * Translates an error from the SMF layer into an appropriate MCI error.
1015 ***************************************************************************/
1016 PRIVATE MMRESULT FNLOCAL XlatSMFErr(
1022 return MMSYSERR_NOERROR;
1025 return MCIERR_OUT_OF_MEMORY;
1027 case SMF_INVALID_FILE:
1028 case SMF_OPEN_FAILED:
1029 case SMF_INVALID_TRACK:
1030 return MCIERR_INVALID_FILE;
1033 return MCIERR_UNSUPPORTED_FUNCTION;