⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 win_snd.c

📁 The source code of Doom legacy for windows
💻 C
📖 第 1 页 / 共 5 页
字号:
    
    // 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 + -