/* * $Header: /H2 Mission Pack/midi.c 3 2/12/98 12:26a Jmonroe $ */ #include #include #include #include #include #include "midstuff.h" #include "midi.h" #include "quakedef.h" BOOL bMidiInited,bFileOpen, bPlaying, bBuffersPrepared; BOOL bPaused, bLooped; UINT uMIDIDeviceID = MIDI_MAPPER, uCallbackStatus; int nCurrentBuffer, nEmptyBuffers; DWORD dwBufferTickLength, dwTempoMultiplier, dwCurrentTempo, dwProgressBytes; DWORD dwVolumePercent, dwVolCache[NUM_CHANNELS]; HMIDISTRM hStream; CONVERTINFO ciStreamBuffers[NUM_STREAM_BUFFERS]; // From mstrconv.c extern INFILESTATE ifs; // Private to this module... static HANDLE hBufferReturnEvent; static void FreeBuffers(void); void MidiErrorMessageBox(MMRESULT mmr) { char temp[1024]; midiOutGetErrorText(mmr,temp,sizeof(temp)); Con_Printf("%s\n",temp); } void MIDI_Play_f (void) { if (Cmd_Argc () == 2) { MIDI_Play(Cmd_Argv(1)); } } void MIDI_Stop_f (void) { MIDI_Stop(); } void MIDI_Pause_f (void) { MIDI_Pause(); } void MIDI_Loop_f (void) { if (Cmd_Argc () == 2) { if (strcmpi(Cmd_Argv(1),"on") == 0 || strcmpi(Cmd_Argv(1),"1") == 0) MIDI_Loop(1); else if (strcmpi(Cmd_Argv(1),"off") == 0 || strcmpi(Cmd_Argv(1),"0") == 0) MIDI_Loop(0); else if (strcmpi(Cmd_Argv(1),"toggle") == 0) MIDI_Loop(2); } if (bLooped) Con_Printf("MIDI music will be looped\n"); else Con_Printf("MIDI music will not be looped\n"); } void MIDI_Volume_f (void) { if (Cmd_Argc () == 2) { dwVolumePercent = atol(Cmd_Argv(1))*65535/100; midiOutSetVolume(hStream,(dwVolumePercent<<16)+dwVolumePercent); /* dwVolumePercent = atol(Cmd_Argv(1))*10; SetAllChannelVolumes(dwVolumePercent);*/ } else { Con_Printf("MIDI volume is %d\n", dwVolumePercent/(65535/100)); } } BOOL MIDI_Init(void) { MMRESULT mmrRetVal; hBufferReturnEvent = CreateEvent(NULL,FALSE,FALSE,"Wait For Buffer Return"); if(COM_CheckParm("-nomidi")) { bMidiInited = 0; return FALSE; } mmrRetVal = midiStreamOpen(&hStream,&uMIDIDeviceID,(DWORD)1,(DWORD)MidiProc,(DWORD)0,CALLBACK_FUNCTION); if(mmrRetVal != MMSYSERR_NOERROR ) { bMidiInited = 0; MidiErrorMessageBox( mmrRetVal ); return FALSE; } Cmd_AddCommand ("midi_play", MIDI_Play_f); Cmd_AddCommand ("midi_stop", MIDI_Stop_f); Cmd_AddCommand ("midi_pause", MIDI_Pause_f); Cmd_AddCommand ("midi_loop", MIDI_Loop_f); Cmd_AddCommand ("midi_volume", MIDI_Volume_f); dwTempoMultiplier = 100; dwVolumePercent = 0xffff; bFileOpen = FALSE; bPlaying = FALSE; bLooped = TRUE; bPaused = FALSE; bBuffersPrepared = FALSE; uCallbackStatus = 0; bMidiInited = 1; return TRUE; } void MIDI_Play(char *Name) { MMRESULT mmrRetVal; char Temp[100]; char *Data; if (!bMidiInited) //don't try to play if there is no midi return; sprintf(Temp, "midi/%s.mid", Name); MIDI_Stop(); if (StreamBufferSetup(Temp)) { Con_Printf("Couldn't load midi file %s\n",Temp); } else { bFileOpen = TRUE; Con_Printf("Playing midi file %s\n",Temp); uCallbackStatus = 0; mmrRetVal = midiStreamRestart(hStream); if (mmrRetVal != MMSYSERR_NOERROR) { MidiErrorMessageBox(mmrRetVal); return; } midiOutSetVolume(hStream, (dwVolumePercent<<16)+dwVolumePercent); bPlaying = TRUE; } } void MIDI_Pause(void) { if(bPaused) midiStreamRestart(hStream); else midiStreamPause(hStream); bPaused = !bPaused; } void MIDI_Loop(int NewValue) { if (NewValue == 2) bLooped = !bLooped; else bLooped = NewValue; } void MIDI_Stop(void) { MMRESULT mmrRetVal; if(bFileOpen || bPlaying)// || uCallbackStatus != STATUS_CALLBACKDEAD) { bPlaying = bPaused = FALSE; if (uCallbackStatus != STATUS_CALLBACKDEAD && uCallbackStatus != STATUS_WAITINGFOREND) uCallbackStatus = STATUS_KILLCALLBACK; mmrRetVal = midiStreamStop(hStream); if (mmrRetVal != MMSYSERR_NOERROR) { MidiErrorMessageBox(mmrRetVal); return; } mmrRetVal = midiOutReset((HMIDIOUT)hStream); if(mmrRetVal != MMSYSERR_NOERROR) { MidiErrorMessageBox(mmrRetVal); return; } if(WaitForSingleObject(hBufferReturnEvent,DEBUG_CALLBACK_TIMEOUT) == WAIT_TIMEOUT) { //Con_Printf("Timed out waiting for MIDI callback\n"); uCallbackStatus = STATUS_CALLBACKDEAD; } } if (uCallbackStatus == STATUS_CALLBACKDEAD) { uCallbackStatus = 0; if (bFileOpen) { ConverterCleanup(); FreeBuffers(); if (hStream) { mmrRetVal = midiStreamClose(hStream); if (mmrRetVal != MMSYSERR_NOERROR) { MidiErrorMessageBox(mmrRetVal); } hStream = NULL; } bFileOpen = FALSE; } } } void MIDI_Cleanup(void) { MMRESULT mmrRetVal; MIDI_Stop(); CloseHandle(hBufferReturnEvent); if(hStream) { mmrRetVal = midiStreamClose(hStream); if(mmrRetVal != MMSYSERR_NOERROR) { MidiErrorMessageBox(mmrRetVal); } hStream = NULL; } } /*****************************************************************************/ /* FreeBuffers() */ /* */ /* This function unprepares and frees all our buffers -- something we must */ /* do to work around a bug in MMYSYSTEM that prevents a device from playing */ /* back properly unless it is closed and reopened after each stop. */ /*****************************************************************************/ void FreeBuffers(void) { DWORD idx; MMRESULT mmrRetVal; if(bBuffersPrepared) { for(idx=0;idxlpData + pmh->dwOffset); if (MIDIEVENT_TYPE( pme->dwEvent ) == MIDI_CTRLCHANGE) { if (MIDIEVENT_DATA1( pme->dwEvent ) == MIDICTRL_VOLUME_LSB) { DebugPrint( "Got an LSB volume event" ); break; } if (MIDIEVENT_DATA1( pme->dwEvent ) != MIDICTRL_VOLUME) break; // Mask off the channel number and cache the volume data byte dwVolCache[ MIDIEVENT_CHANNEL( pme->dwEvent )] = MIDIEVENT_VOLUME( pme->dwEvent ); // Post a message so that the main program knows to counteract // the effects of the volume event in the stream with its own // generated event which reflects the proper trackbar position. /* PostMessage( hWndMain, WM_MSTREAM_UPDATEVOLUME,MIDIEVENT_CHANNEL( pme->dwEvent ), 0L );*/ } break; default: break; } return; } /****************************************************************************/ /* SetAllChannelVolumes() */ /* */ /* Given a percent in tenths of a percent, sets volume on all channels to */ /* reflect the new value. */ /****************************************************************************/ void SetAllChannelVolumes(DWORD dwVolumePercent) { DWORD dwEvent, dwStatus, dwVol, idx; MMRESULT mmrRetVal; /* if(!bPlaying) return;*/ for(idx=0,dwStatus=MIDI_CTRLCHANGE;idx