📄 win_snd.c
字号:
// get MIDI device caps
//
if ((mmrRetVal = midiOutGetDevCaps (uMIDIDeviceID, &MidiOutCaps, sizeof(MIDIOUTCAPS))) !=
MMSYSERR_NOERROR) {
CONS_Printf ("midiOutGetCaps FAILED : \n");
MidiErrorMessageBox (mmrRetVal);
}
else
{
CONS_Printf ("MIDI product name: %s\n", MidiOutCaps.szPname);
switch (MidiOutCaps.wTechnology) {
case MOD_FMSYNTH: szTechnology = "FM Synth"; break;
case MOD_MAPPER: szTechnology = "Microsoft MIDI Mapper"; break;
case MOD_MIDIPORT: szTechnology = "MIDI hardware port"; break;
case MOD_SQSYNTH: szTechnology = "Square wave synthesizer"; break;
case MOD_SYNTH: szTechnology = "Synthesizer"; break;
default: szTechnology = "unknown"; break;
}
CONS_Printf ("MIDI technology: %s\n", szTechnology);
CONS_Printf ("MIDI caps:\n");
if (MidiOutCaps.dwSupport & MIDICAPS_CACHE)
CONS_Printf ("-Patch caching\n");
if (MidiOutCaps.dwSupport & MIDICAPS_LRVOLUME)
CONS_Printf ("-Separate left and right volume control\n");
if (MidiOutCaps.dwSupport & MIDICAPS_STREAM)
CONS_Printf ("-Direct support for midiStreamOut()\n");
if (MidiOutCaps.dwSupport & MIDICAPS_VOLUME)
CONS_Printf ("-Volume control\n");
bMidiCanSetVolume = ((MidiOutCaps.dwSupport & MIDICAPS_VOLUME)!=0);
}
#ifdef TESTCODE
I_InitAudioMixer ();
#endif
// initialisation of midicard by I_StartupSound
pMus2MidData = (char *)Z_Malloc (MIDBUFFERSIZE,PU_STATIC,NULL);
// ----------------------------------------------------------------------
// Midi2Stream initialization
// ----------------------------------------------------------------------
// create event for synch'ing the callback thread to main program thread
// when we will need it
hBufferReturnEvent = CreateEvent( NULL, FALSE, FALSE,
"DoomLegacy Midi Playback: Wait For Buffer Return" );
if( !hBufferReturnEvent )
{
I_GetLastErrorMsgBox();
nomusic = true;
return;
}
if ((mmrRetVal = midiStreamOpen(&hStream,
&uMIDIDeviceID,
(DWORD)1, (DWORD)MidiStreamCallback/*NULL*/,
(DWORD)0,
CALLBACK_FUNCTION /*CALLBACK_NULL*/)) != MMSYSERR_NOERROR)
{
CONS_Printf ("I_RegisterSong: midiStreamOpen FAILED\n");
MidiErrorMessageBox( mmrRetVal );
nomusic = true;
return;
}
// stream buffers are initially unallocated (set em NULL)
for (idx = 0; idx < NUM_STREAM_BUFFERS; idx++ )
ZeroMemory (&ciStreamBuffers[idx].mhBuffer, sizeof(MIDIHDR));
// ----------------------------------------------------------------------
// register exit code
I_AddExitFunc (I_ShutdownMusic);
bMusicStarted = true;
}
// ---------------
// I_ShutdownMusic
// ---------------
void I_ShutdownMusic(void)
{
DWORD idx;
MMRESULT mmrRetVal;
if (!bMusicStarted)
return;
CONS_Printf("I_ShutdownMusic: \n");
if (hStream)
{
I_StopSong (SPECIAL_HANDLE_CLEANMIDI);
}
Mid2StreamConverterCleanup();
Mid2StreamFreeBuffers();
// Free our stream buffers
for( idx = 0; idx < NUM_STREAM_BUFFERS; idx++ ) {
if( ciStreamBuffers[idx].mhBuffer.lpData )
{
GlobalFreePtr( ciStreamBuffers[idx].mhBuffer.lpData );
ciStreamBuffers[idx].mhBuffer.lpData = NULL;
}
}
if (hStream) {
if(( mmrRetVal = midiStreamClose( hStream )) != MMSYSERR_NOERROR )
MidiErrorMessageBox( mmrRetVal );
hStream = NULL;
}
CloseHandle( hBufferReturnEvent );
//free (pMus2MidData);
bMusicStarted = false;
}
// --------------------
// SetAllChannelVolumes
// Given a percent in tenths of a percent, sets volume on all channels to
// reflect the new value.
// --------------------
static void SetAllChannelVolumes( DWORD dwVolumePercent )
{
DWORD dwEvent, dwStatus, dwVol, idx;
MMRESULT mmrRetVal;
if( !bMidiPlaying )
return;
for( idx = 0, dwStatus = MIDI_CTRLCHANGE; idx < MAX_MIDI_IN_TRACKS; idx++, dwStatus++ )
{
dwVol = ( dwVolCache[idx] * dwVolumePercent ) / 1000;
//CONS_Printf ("channel %d vol %d\n", idx, dwVol);
dwEvent = dwStatus | ((DWORD)MIDICTRL_VOLUME << 8)
| ((DWORD)dwVol << 16);
if(( mmrRetVal = midiOutShortMsg( (HMIDIOUT)hStream, dwEvent ))
!= MMSYSERR_NOERROR )
{
MidiErrorMessageBox( mmrRetVal );
return;
}
}
}
// ----------------
// I_SetMusicVolume
// Set the midi output volume
// ----------------
void I_SetMusicVolume(int volume)
{
MMRESULT mmrRetVal;
int iVolume;
if (nomusic)
return;
if (bMidiCanSetVolume)
{
// method A
// current volume is 0-31, we need 0-0xFFFF in each word (left/right channel)
iVolume = (volume << 11) | (volume << 27);
if ((mmrRetVal = midiOutSetVolume ((HMIDIOUT)uMIDIDeviceID, iVolume)) != MMSYSERR_NOERROR) {
CONS_Printf ("I_SetMusicVolume: couldn't set volume\n");
MidiErrorMessageBox(mmrRetVal);
}
}
else
{
// method B
dwVolumePercent = (volume * 1000) / 32;
SetAllChannelVolumes (dwVolumePercent);
}
}
// ----------
// I_PlaySong
// Note: doesn't use the handle, would be useful to switch between mid's after
// some trigger (would do several RegisterSong, then PlaySong the chosen one)
// ----------
void I_PlaySong(int handle, int bLooping)
{
MMRESULT mmrRetVal;
if (nomusic)
return;
#ifdef DEBUGMIDISTREAM
CONS_Printf("I_PlaySong: looping %d\n", bLooping);
#endif
// unpause the song first if it was paused
if( bMidiPaused )
I_PauseSong( handle );
// Clear the status of our callback so it will handle
// MOM_DONE callbacks once more
uCallbackStatus = 0;
if(( mmrRetVal = midiStreamRestart( hStream )) != MMSYSERR_NOERROR )
{
MidiErrorMessageBox( mmrRetVal );
Mid2StreamFreeBuffers();
Mid2StreamConverterCleanup();
I_Error ("I_PlaySong: midiStreamRestart error");
}
bMidiPlaying = TRUE;
bMidiLooped = bLooping;
}
// -----------
// I_PauseSong
// calls midiStreamPause() to pause the midi playback
// -----------
void I_PauseSong (int handle)
{
if (nomusic)
return;
#ifdef DEBUGMIDISTREAM
CONS_Printf("I_PauseSong: \n");
#endif
if (!bMidiPaused) {
midiStreamPause( hStream );
bMidiPaused = true;
}
}
// ------------
// I_ResumeSong
// un-pause the midi song with midiStreamRestart
// ------------
void I_ResumeSong (int handle)
{
if (nomusic)
return;
#ifdef DEBUGMIDISTREAM
CONS_Printf("I_ResumeSong: \n");
#endif
if( bMidiPaused ) {
midiStreamRestart( hStream );
bMidiPaused = false;
}
}
// ----------
// I_StopSong
// ----------
// faB: -1999 is a special handle here, it means we stop the midi when exiting
// Legacy, this will do a midiOutReset() for a more 'sure' midi off.
void I_StopSong(int handle)
{
MMRESULT mmrRetVal;
if (nomusic)
return;
#ifdef DEBUGMIDISTREAM
CONS_Printf("I_StopSong: \n");
#endif
if (bMidiPlaying || (uCallbackStatus != STATUS_CALLBACKDEAD) )
{
bMidiPlaying = bMidiPaused = FALSE;
if( uCallbackStatus != STATUS_CALLBACKDEAD &&
uCallbackStatus != STATUS_WAITINGFOREND )
uCallbackStatus = STATUS_KILLCALLBACK;
//CONS_Printf ("a: %d\n",I_GetTime());
if(( mmrRetVal = midiStreamStop( hStream )) != MMSYSERR_NOERROR )
{
MidiErrorMessageBox( mmrRetVal );
return;
}
//faB: if we don't call midiOutReset() seems we have to stop the buffers
// ourselves (or it doesn't play anymore)
if (!bMidiPaused && (handle != SPECIAL_HANDLE_CLEANMIDI))
{
midiStreamPause( hStream );
}
//CONS_Printf ("b: %d\n",I_GetTime());
else
//faB: this damn call takes 1 second and a half !!! still do it on exit
// to be sure everything midi is cleaned as much as possible
if (handle == SPECIAL_HANDLE_CLEANMIDI) {
//
if(( mmrRetVal = midiOutReset( (HMIDIOUT)hStream )) != MMSYSERR_NOERROR )
{
MidiErrorMessageBox( mmrRetVal );
return;
}
}
//CONS_Printf ("c: %d\n",I_GetTime());
// Wait for the callback thread to release this thread, which it will do by
// calling SetEvent() once all buffers are returned to it
if( WaitForSingleObject( hBufferReturnEvent, DEBUG_CALLBACK_TIMEOUT )
== WAIT_TIMEOUT )
{
// Note, this is a risky move because the callback may be genuinely busy, but
// when we're debugging, it's safer and faster than freezing the application,
// which leaves the MIDI device locked up and forces a system reset...
CONS_Printf( "Timed out waiting for MIDI callback\n" );
uCallbackStatus = STATUS_CALLBACKDEAD;
}
//CONS_Printf ("d: %d\n",I_GetTime());
}
if( uCallbackStatus == STATUS_CALLBACKDEAD )
{
uCallbackStatus = 0;
Mid2StreamConverterCleanup();
Mid2StreamFreeBuffers();
//faB: we could close the stream here and re-open later to avoid
// a little quirk in mmsystem (see DirectX6 mstream note)
midiStreamClose(hStream);
midiStreamOpen(&hStream, &uMIDIDeviceID, (DWORD)1,
(DWORD)MidiStreamCallback/*NULL*/,
(DWORD)0, CALLBACK_FUNCTION /*CALLBACK_NULL*/);
}
}
// Is the song playing?
int I_QrySongPlaying (int handle)
{
if (nomusic)
return 0;
#ifdef DEBUGMIDISTREAM
CONS_Printf("I_QrySongPlaying: \n");
#endif
return (bMidiPlaying);
}
void I_UnRegisterSong(int handle)
{
if (nomusic)
return;
//faB: we might free here whatever is allocated per-music
// (but we don't cause I hate malloc's)
Mid2StreamConverterCleanup();
#ifdef DEBUGMIDISTREAM
CONS_Printf("I_UnregisterSong: \n");
#endif
}
// --------------
// I_RegisterSong
// Prepare a song for playback
// - if MUS, convert it to MIDI format
// - setup midi stream buffers, and activate the callback procedure
// which will continually fill the buffers with new data
// --------------
#ifdef DEBUGMIDISTREAM
void I_SaveMemToFile (unsigned char* pData, unsigned long iLength, char* sFileName); //win_sys.c
#endif
int I_RegisterSong(void* data,int len)
{
int iErrorCode;
char* pMidiFileData = NULL; // MIDI music buffer to be played or NULL
int iMus2MidSize; // size of Midi output data
if (nomusic)
return 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -