12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085 |
- /*
- ===========================================================================
- Doom 3 BFG Edition GPL Source Code
- Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
- Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "Precompiled.h"
- #include "globaldata.h"
- //
- // DESCRIPTION:
- // System interface for sound.
- //
- //-----------------------------------------------------------------------------
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <math.h>
- #include <sys/types.h>
- #include <fcntl.h>
- // Timer stuff. Experimental.
- #include <time.h>
- #include <signal.h>
- #include "z_zone.h"
- #include "i_system.h"
- #include "i_sound.h"
- #include "m_argv.h"
- #include "m_misc.h"
- #include "w_wad.h"
- #include "d_main.h"
- #include "doomdef.h"
- #include "../timidity/timidity.h"
- #include "../timidity/controls.h"
- #include "sound/snd_local.h"
- #include <xaudio2.h>
- #include <x3daudio.h>
- #pragma warning ( disable : 4244 )
- #define MIDI_CHANNELS 2
- #if 1
- #define MIDI_RATE 22050
- #define MIDI_SAMPLETYPE XAUDIOSAMPLETYPE_8BITPCM
- #define MIDI_FORMAT AUDIO_U8
- #define MIDI_FORMAT_BYTES 1
- #else
- #define MIDI_RATE 48000
- #define MIDI_SAMPLETYPE XAUDIOSAMPLETYPE_16BITPCM
- #define MIDI_FORMAT AUDIO_S16MSB
- #define MIDI_FORMAT_BYTES 2
- #endif
- IXAudio2SourceVoice* pMusicSourceVoice;
- MidiSong* doomMusic;
- byte* musicBuffer;
- int totalBufferSize;
- HANDLE hMusicThread;
- bool waitingForMusic;
- bool musicReady;
- typedef struct tagActiveSound_t {
- IXAudio2SourceVoice* m_pSourceVoice; // Source voice
- X3DAUDIO_DSP_SETTINGS m_DSPSettings;
- X3DAUDIO_EMITTER m_Emitter;
- X3DAUDIO_CONE m_Cone;
- int id;
- int valid;
- int start;
- int player;
- bool localSound;
- mobj_t *originator;
- } activeSound_t;
- // cheap little struct to hold a sound
- typedef struct {
- int vol;
- int player;
- int pitch;
- int priority;
- mobj_t *originator;
- mobj_t *listener;
- } soundEvent_t;
- // array of all the possible sounds
- // in split screen we only process the loudest sound of each type per frame
- soundEvent_t soundEvents[128];
- extern int PLAYERCOUNT;
- // Real volumes
- const float GLOBAL_VOLUME_MULTIPLIER = 0.5f;
- float x_SoundVolume = GLOBAL_VOLUME_MULTIPLIER;
- float x_MusicVolume = GLOBAL_VOLUME_MULTIPLIER;
- // The actual lengths of all sound effects.
- static int lengths[NUMSFX];
- activeSound_t activeSounds[NUM_SOUNDBUFFERS] = {0};
- int S_initialized = 0;
- bool Music_initialized = false;
- // XAUDIO
- float g_EmitterAzimuths [] = { 0.f };
- static int numOutputChannels = 0;
- static bool soundHardwareInitialized = false;
- X3DAUDIO_HANDLE X3DAudioInstance;
- X3DAUDIO_LISTENER doom_Listener;
- //float localSoundVolumeEntries[] = { 0.f, 0.f, 0.9f, 0.5f, 0.f, 0.f };
- float localSoundVolumeEntries[] = { 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f };
- void I_InitSoundChannel( int channel, int numOutputChannels_ );
- /*
- ======================
- getsfx
- ======================
- */
- // This function loads the sound data from the WAD lump,
- // for single sound.
- //
- void* getsfx ( char* sfxname, int* len )
- {
- unsigned char* sfx;
- unsigned char* sfxmem;
- int size;
- char name[20];
- int sfxlump;
- float scale = 1.0f;
- // Get the sound data from the WAD, allocate lump
- // in zone memory.
- sprintf(name, "ds%s", sfxname);
- // Scale down the plasma gun, it clips
- if ( strcmp( sfxname, "plasma" ) == 0 ) {
- scale = 0.75f;
- }
- if ( strcmp( sfxname, "itemup" ) == 0 ) {
- scale = 1.333f;
- }
- // If sound requested is not found in current WAD, use pistol as default
- if ( W_CheckNumForName(name) == -1 )
- sfxlump = W_GetNumForName("dspistol");
- else
- sfxlump = W_GetNumForName(name);
- // Sound lump headers are 8 bytes.
- const int SOUND_LUMP_HEADER_SIZE_IN_BYTES = 8;
- size = W_LumpLength( sfxlump ) - SOUND_LUMP_HEADER_SIZE_IN_BYTES;
- sfx = (unsigned char*)W_CacheLumpNum( sfxlump, PU_CACHE_SHARED );
- const unsigned char * sfxSampleStart = sfx + SOUND_LUMP_HEADER_SIZE_IN_BYTES;
- // Allocate from zone memory.
- //sfxmem = (float*)DoomLib::Z_Malloc( size*(sizeof(float)), PU_SOUND_SHARED, 0 );
- sfxmem = (unsigned char*)malloc( size * sizeof(unsigned char) );
- // Now copy, and convert to Xbox360 native float samples, do initial volume ramp, and scale
- for ( int i=0; i<size; i++ ) {
- sfxmem[i] = sfxSampleStart[i];// * scale;
- }
- // Remove the cached lump.
- Z_Free( sfx );
- // Set length.
- *len = size;
- // Return allocated padded data.
- return (void *) (sfxmem);
- }
- /*
- ======================
- I_SetChannels
- ======================
- */
- void I_SetChannels() {
- // Original Doom set up lookup tables here
- }
- /*
- ======================
- I_SetSfxVolume
- ======================
- */
- void I_SetSfxVolume(int volume) {
- x_SoundVolume = ((float)volume / 15.f) * GLOBAL_VOLUME_MULTIPLIER;
- }
- /*
- ======================
- I_GetSfxLumpNum
- ======================
- */
- //
- // Retrieve the raw data lump index
- // for a given SFX name.
- //
- int I_GetSfxLumpNum(sfxinfo_t* sfx)
- {
- char namebuf[9];
- sprintf(namebuf, "ds%s", sfx->name);
- return W_GetNumForName(namebuf);
- }
- /*
- ======================
- I_StartSound2
- ======================
- */
- // Starting a sound means adding it
- // to the current list of active sounds
- // in the internal channels.
- // As the SFX info struct contains
- // e.g. a pointer to the raw data,
- // it is ignored.
- // As our sound handling does not handle
- // priority, it is ignored.
- // Pitching (that is, increased speed of playback) is set
- //
- int I_StartSound2 ( int id, int player, mobj_t *origin, mobj_t *listener_origin, int pitch, int priority ) {
- if ( !soundHardwareInitialized ) {
- return id;
- }
-
- int i;
- XAUDIO2_VOICE_STATE state;
- activeSound_t* sound = 0;
- int oldest = 0, oldestnum = -1;
- // these id's should not overlap
- if ( id == sfx_sawup || id == sfx_sawidl || id == sfx_sawful || id == sfx_sawhit || id == sfx_stnmov ) {
- // Loop all channels, check.
- for (i=0 ; i < NUM_SOUNDBUFFERS ; i++)
- {
- sound = &activeSounds[i];
- if (sound->valid && ( sound->id == id && sound->player == player ) ) {
- I_StopSound( sound->id, player );
- break;
- }
- }
- }
- // find a valid channel, or one that has finished playing
- for (i = 0; i < NUM_SOUNDBUFFERS; ++i) {
- sound = &activeSounds[i];
-
- if (!sound->valid)
- break;
- if (!oldest || oldest > sound->start) {
- oldestnum = i;
- oldest = sound->start;
- }
- sound->m_pSourceVoice->GetState( &state );
- if ( state.BuffersQueued == 0 ) {
- break;
- }
- }
- // none found, so use the oldest one
- if (i == NUM_SOUNDBUFFERS)
- {
- i = oldestnum;
- sound = &activeSounds[i];
- }
- // stop the sound with a FlushPackets
- sound->m_pSourceVoice->Stop();
- sound->m_pSourceVoice->FlushSourceBuffers();
- // Set up packet
- XAUDIO2_BUFFER Packet = { 0 };
- Packet.Flags = XAUDIO2_END_OF_STREAM;
- Packet.AudioBytes = lengths[id];
- Packet.pAudioData = (BYTE*)S_sfx[id].data;
- Packet.PlayBegin = 0;
- Packet.PlayLength = 0;
- Packet.LoopBegin = XAUDIO2_NO_LOOP_REGION;
- Packet.LoopLength = 0;
- Packet.LoopCount = 0;
- Packet.pContext = NULL;
- // Set voice volumes
- sound->m_pSourceVoice->SetVolume( x_SoundVolume );
- // Set voice pitch
- sound->m_pSourceVoice->SetFrequencyRatio( 1 + ((float)pitch-128.f)/95.f );
- // Set initial spatialization
- if ( origin && origin != listener_origin ) {
- // Update Emitter Position
- sound->m_Emitter.Position.x = (float)(origin->x >> FRACBITS);
- sound->m_Emitter.Position.y = 0.f;
- sound->m_Emitter.Position.z = (float)(origin->y >> FRACBITS);
- // Calculate 3D positioned speaker volumes
- DWORD dwCalculateFlags = X3DAUDIO_CALCULATE_MATRIX;
- X3DAudioCalculate( X3DAudioInstance, &doom_Listener, &sound->m_Emitter, dwCalculateFlags, &sound->m_DSPSettings );
- // Pan the voice according to X3DAudio calculation
- sound->m_pSourceVoice->SetOutputMatrix( NULL, 1, numOutputChannels, sound->m_DSPSettings.pMatrixCoefficients );
- sound->localSound = false;
- } else {
- // Local(or Global) sound, fixed speaker volumes
- sound->m_pSourceVoice->SetOutputMatrix( NULL, 1, numOutputChannels, localSoundVolumeEntries );
- sound->localSound = true;
- }
- // Submit packet
- HRESULT hr;
- if( FAILED( hr = sound->m_pSourceVoice->SubmitSourceBuffer( &Packet ) ) ) {
- int fail = 1;
- }
- // Play the source voice
- if( FAILED( hr = sound->m_pSourceVoice->Start( 0 ) ) ) {
- int fail = 1;
- }
- // set id, and start time
- sound->id = id;
- sound->start = ::g->gametic;
- sound->valid = 1;
- sound->player = player;
- sound->originator = origin;
- return id;
- }
- /*
- ======================
- I_ProcessSoundEvents
- ======================
- */
- void I_ProcessSoundEvents( void ) {
- for( int i = 0; i < 128; i++ ) {
- if( soundEvents[i].pitch ) {
- I_StartSound2( i, soundEvents[i].player, soundEvents[i].originator, soundEvents[i].listener, soundEvents[i].pitch, soundEvents[i].priority );
- }
- }
- memset( soundEvents, 0, sizeof( soundEvents ) );
- }
- /*
- ======================
- I_StartSound
- ======================
- */
- int I_StartSound ( int id, mobj_t *origin, mobj_t *listener_origin, int vol, int pitch, int priority ) {
- // only allow player 0s sounds in intermission and finale screens
- if( ::g->gamestate != GS_LEVEL && DoomLib::GetPlayer() != 0 ) {
- return 0;
- }
- // if we're only one player or we're trying to play the chainsaw sound, do it normal
- // otherwise only allow one sound of each type per frame
- if( PLAYERCOUNT == 1 || id == sfx_sawup || id == sfx_sawidl || id == sfx_sawful || id == sfx_sawhit ) {
- return I_StartSound2( id, ::g->consoleplayer, origin, listener_origin, pitch, priority );
- }
- else {
- if( soundEvents[ id ].vol < vol ) {
- soundEvents[ id ].player = DoomLib::GetPlayer();
- soundEvents[ id ].pitch = pitch;
- soundEvents[ id ].priority = priority;
- soundEvents[ id ].vol = vol;
- soundEvents[ id ].originator = origin;
- soundEvents[ id ].listener = listener_origin;
- }
- return id;
- }
- }
- /*
- ======================
- I_StopSound
- ======================
- */
- void I_StopSound (int handle, int player)
- {
- // You need the handle returned by StartSound.
- // Would be looping all channels,
- // tracking down the handle,
- // an setting the channel to zero.
- int i;
- activeSound_t* sound = 0;
- for (i = 0; i < NUM_SOUNDBUFFERS; ++i)
- {
- sound = &activeSounds[i];
- if (!sound->valid || sound->id != handle || (player >= 0 && sound->player != player) )
- continue;
- break;
- }
- if (i == NUM_SOUNDBUFFERS)
- return;
- // stop the sound
- if ( sound->m_pSourceVoice != NULL ) {
- sound->m_pSourceVoice->Stop( 0 );
- }
- sound->valid = 0;
- sound->player = -1;
- }
- /*
- ======================
- I_SoundIsPlaying
- ======================
- */
- int I_SoundIsPlaying(int handle) {
- if ( !soundHardwareInitialized ) {
- return 0;
- }
- int i;
- XAUDIO2_VOICE_STATE state;
- activeSound_t* sound;
- for (i = 0; i < NUM_SOUNDBUFFERS; ++i)
- {
- sound = &activeSounds[i];
- if (!sound->valid || sound->id != handle)
- continue;
- sound->m_pSourceVoice->GetState( &state );
- if ( state.BuffersQueued > 0 ) {
- return 1;
- }
- }
- return 0;
- }
- /*
- ======================
- I_UpdateSound
- ======================
- */
- // Update Listener Position and go through all the
- // channels and update speaker volumes for 3D sound.
- void I_UpdateSound( void ) {
- if ( !soundHardwareInitialized ) {
- return;
- }
- int i;
- XAUDIO2_VOICE_STATE state;
- activeSound_t* sound;
- for ( i=0; i < NUM_SOUNDBUFFERS; i++ ) {
- sound = &activeSounds[i];
- if ( !sound->valid || sound->localSound ) {
- continue;
- }
- sound->m_pSourceVoice->GetState( &state );
- if ( state.BuffersQueued > 0 ) {
- mobj_t *playerObj = ::g->players[ sound->player ].mo;
- // Update Listener Orientation and Position
- angle_t pAngle = playerObj->angle;
- fixed_t fx, fz;
- pAngle >>= ANGLETOFINESHIFT;
- fx = finecosine[pAngle];
- fz = finesine[pAngle];
- doom_Listener.OrientFront.x = (float)(fx) / 65535.f;
- doom_Listener.OrientFront.y = 0.f;
- doom_Listener.OrientFront.z = (float)(fz) / 65535.f;
- doom_Listener.Position.x = (float)(playerObj->x >> FRACBITS);
- doom_Listener.Position.y = 0.f;
- doom_Listener.Position.z = (float)(playerObj->y >> FRACBITS);
- // Update Emitter Position
- sound->m_Emitter.Position.x = (float)(sound->originator->x >> FRACBITS);
- sound->m_Emitter.Position.y = 0.f;
- sound->m_Emitter.Position.z = (float)(sound->originator->y >> FRACBITS);
- // Calculate 3D positioned speaker volumes
- DWORD dwCalculateFlags = X3DAUDIO_CALCULATE_MATRIX;
- X3DAudioCalculate( X3DAudioInstance, &doom_Listener, &sound->m_Emitter, dwCalculateFlags, &sound->m_DSPSettings );
- // Pan the voice according to X3DAudio calculation
- sound->m_pSourceVoice->SetOutputMatrix( NULL, 1, numOutputChannels, sound->m_DSPSettings.pMatrixCoefficients );
- }
- }
- }
- /*
- ======================
- I_UpdateSoundParams
- ======================
- */
- void I_UpdateSoundParams( int handle, int vol, int sep, int pitch) {
- }
- /*
- ======================
- I_ShutdownSound
- ======================
- */
- void I_ShutdownSound(void) {
- int done = 0;
- int i;
- if ( S_initialized ) {
- // Stop all sounds, but don't destroy the XAudio2 buffers.
- for ( i = 0; i < NUM_SOUNDBUFFERS; ++i ) {
- activeSound_t * sound = &activeSounds[i];
- if ( sound == NULL ) {
- continue;
- }
- I_StopSound( sound->id, 0 );
- if ( sound->m_pSourceVoice ) {
- sound->m_pSourceVoice->FlushSourceBuffers();
- }
- }
- for (i=1 ; i<NUMSFX ; i++) {
- if ( S_sfx[i].data && !(S_sfx[i].link) ) {
- //Z_Free( S_sfx[i].data );
- free( S_sfx[i].data );
- }
- }
- }
- I_StopSong( 0 );
- S_initialized = 0;
- // Done.
- return;
- }
- /*
- ======================
- I_InitSoundHardware
- Called from the tech4x initialization code. Sets up Doom classic's
- sound channels.
- ======================
- */
- void I_InitSoundHardware( int numOutputChannels_, int channelMask ) {
- ::numOutputChannels = numOutputChannels_;
- // Initialize the X3DAudio
- // Speaker geometry configuration on the final mix, specifies assignment of channels
- // to speaker positions, defined as per WAVEFORMATEXTENSIBLE.dwChannelMask
- // SpeedOfSound - not used by doomclassic
- X3DAudioInitialize( channelMask, 340.29f, X3DAudioInstance );
- for ( int i = 0; i < NUM_SOUNDBUFFERS; ++i ) {
- // Initialize source voices
- I_InitSoundChannel( i, numOutputChannels );
- }
- I_InitMusic();
- soundHardwareInitialized = true;
- }
- /*
- ======================
- I_ShutdownitSoundHardware
- Called from the tech4x shutdown code. Tears down Doom classic's
- sound channels.
- ======================
- */
- void I_ShutdownSoundHardware() {
- soundHardwareInitialized = false;
- I_ShutdownMusic();
- for ( int i = 0; i < NUM_SOUNDBUFFERS; ++i ) {
- activeSound_t * sound = &activeSounds[i];
- if ( sound == NULL ) {
- continue;
- }
- if ( sound->m_pSourceVoice ) {
- sound->m_pSourceVoice->Stop();
- sound->m_pSourceVoice->FlushSourceBuffers();
- sound->m_pSourceVoice->DestroyVoice();
- sound->m_pSourceVoice = NULL;
- }
- if ( sound->m_DSPSettings.pMatrixCoefficients ) {
- delete [] sound->m_DSPSettings.pMatrixCoefficients;
- sound->m_DSPSettings.pMatrixCoefficients = NULL;
- }
- }
- }
- /*
- ======================
- I_InitSoundChannel
- ======================
- */
- void I_InitSoundChannel( int channel, int numOutputChannels_ ) {
- activeSound_t *soundchannel = &activeSounds[ channel ];
- X3DAUDIO_VECTOR ZeroVector = { 0.0f, 0.0f, 0.0f };
- // Set up emitter parameters
- soundchannel->m_Emitter.OrientFront.x = 0.0f;
- soundchannel->m_Emitter.OrientFront.y = 0.0f;
- soundchannel->m_Emitter.OrientFront.z = 1.0f;
- soundchannel->m_Emitter.OrientTop.x = 0.0f;
- soundchannel->m_Emitter.OrientTop.y = 1.0f;
- soundchannel->m_Emitter.OrientTop.z = 0.0f;
- soundchannel->m_Emitter.Position = ZeroVector;
- soundchannel->m_Emitter.Velocity = ZeroVector;
- soundchannel->m_Emitter.pCone = &(soundchannel->m_Cone);
- soundchannel->m_Emitter.pCone->InnerAngle = 0.0f; // Setting the inner cone angles to X3DAUDIO_2PI and
- // outer cone other than 0 causes
- // the emitter to act like a point emitter using the
- // INNER cone settings only.
- soundchannel->m_Emitter.pCone->OuterAngle = 0.0f; // Setting the outer cone angles to zero causes
- // the emitter to act like a point emitter using the
- // OUTER cone settings only.
- soundchannel->m_Emitter.pCone->InnerVolume = 0.0f;
- soundchannel->m_Emitter.pCone->OuterVolume = 1.0f;
- soundchannel->m_Emitter.pCone->InnerLPF = 0.0f;
- soundchannel->m_Emitter.pCone->OuterLPF = 1.0f;
- soundchannel->m_Emitter.pCone->InnerReverb = 0.0f;
- soundchannel->m_Emitter.pCone->OuterReverb = 1.0f;
- soundchannel->m_Emitter.ChannelCount = 1;
- soundchannel->m_Emitter.ChannelRadius = 0.0f;
- soundchannel->m_Emitter.pVolumeCurve = NULL;
- soundchannel->m_Emitter.pLFECurve = NULL;
- soundchannel->m_Emitter.pLPFDirectCurve = NULL;
- soundchannel->m_Emitter.pLPFReverbCurve = NULL;
- soundchannel->m_Emitter.pReverbCurve = NULL;
- soundchannel->m_Emitter.CurveDistanceScaler = 1200.0f;
- soundchannel->m_Emitter.DopplerScaler = 1.0f;
- soundchannel->m_Emitter.pChannelAzimuths = g_EmitterAzimuths;
- soundchannel->m_DSPSettings.SrcChannelCount = 1;
- soundchannel->m_DSPSettings.DstChannelCount = numOutputChannels_;
- soundchannel->m_DSPSettings.pMatrixCoefficients = new FLOAT[ numOutputChannels_ ];
- // Create Source voice
- WAVEFORMATEX voiceFormat = {0};
- voiceFormat.wFormatTag = WAVE_FORMAT_PCM;
- voiceFormat.nChannels = 1;
- voiceFormat.nSamplesPerSec = 11025;
- voiceFormat.nAvgBytesPerSec = 11025;
- voiceFormat.nBlockAlign = 1;
- voiceFormat.wBitsPerSample = 8;
- voiceFormat.cbSize = 0;
- soundSystemLocal.hardware.GetIXAudio2()->CreateSourceVoice( &soundchannel->m_pSourceVoice, (WAVEFORMATEX *)&voiceFormat );
- }
- /*
- ======================
- I_InitSound
- ======================
- */
- void I_InitSound() {
- if (S_initialized == 0) {
- int i;
- X3DAUDIO_VECTOR ZeroVector = { 0.0f, 0.0f, 0.0f };
- // Set up listener parameters
- doom_Listener.OrientFront.x = 0.0f;
- doom_Listener.OrientFront.y = 0.0f;
- doom_Listener.OrientFront.z = 1.0f;
- doom_Listener.OrientTop.x = 0.0f;
- doom_Listener.OrientTop.y = 1.0f;
- doom_Listener.OrientTop.z = 0.0f;
- doom_Listener.Position = ZeroVector;
- doom_Listener.Velocity = ZeroVector;
- for (i=1 ; i<NUMSFX ; i++)
- {
- // Alias? Example is the chaingun sound linked to pistol.
- if (!S_sfx[i].link)
- {
- // Load data from WAD file.
- S_sfx[i].data = getsfx( S_sfx[i].name, &lengths[i] );
- }
- else
- {
- // Previously loaded already?
- S_sfx[i].data = S_sfx[i].link->data;
- lengths[i] = lengths[(S_sfx[i].link - S_sfx)/sizeof(sfxinfo_t)];
- }
- }
- S_initialized = 1;
- }
- }
- /*
- ======================
- I_SubmitSound
- ======================
- */
- void I_SubmitSound(void)
- {
- // Only do this for player 0, it will still handle positioning
- // for other players, but it can't be outside the game
- // frame like the soundEvents are.
- if ( DoomLib::GetPlayer() == 0 ) {
- // Do 3D positioning of sounds
- I_UpdateSound();
- // Check for XMP notifications
- I_UpdateMusic();
- }
- }
- // =========================================================
- // =========================================================
- // Background Music
- // =========================================================
- // =========================================================
- /*
- ======================
- I_SetMusicVolume
- ======================
- */
- void I_SetMusicVolume(int volume)
- {
- x_MusicVolume = (float)volume / 15.f;
- }
- /*
- ======================
- I_InitMusic
- ======================
- */
- void I_InitMusic(void)
- {
- if ( !Music_initialized ) {
- // Initialize Timidity
- Timidity_Init( MIDI_RATE, MIDI_FORMAT, MIDI_CHANNELS, MIDI_RATE, "classicmusic/gravis.cfg" );
- hMusicThread = NULL;
- musicBuffer = NULL;
- totalBufferSize = 0;
- waitingForMusic = false;
- musicReady = false;
- // Create Source voice
- WAVEFORMATEX voiceFormat = {0};
- voiceFormat.wFormatTag = WAVE_FORMAT_PCM;
- voiceFormat.nChannels = 2;
- voiceFormat.nSamplesPerSec = MIDI_RATE;
- voiceFormat.nAvgBytesPerSec = MIDI_RATE * MIDI_FORMAT_BYTES * 2;
- voiceFormat.nBlockAlign = MIDI_FORMAT_BYTES * 2;
- voiceFormat.wBitsPerSample = MIDI_FORMAT_BYTES * 8;
- voiceFormat.cbSize = 0;
- soundSystemLocal.hardware.GetIXAudio2()->CreateSourceVoice( &pMusicSourceVoice, (WAVEFORMATEX *)&voiceFormat, XAUDIO2_VOICE_MUSIC );
- Music_initialized = true;
- }
- }
- /*
- ======================
- I_ShutdownMusic
- ======================
- */
- void I_ShutdownMusic(void)
- {
- I_StopSong( 0 );
- if ( Music_initialized ) {
- if ( pMusicSourceVoice ) {
- pMusicSourceVoice->Stop();
- pMusicSourceVoice->FlushSourceBuffers();
- pMusicSourceVoice->DestroyVoice();
- pMusicSourceVoice = NULL;
- }
- if ( hMusicThread ) {
- DWORD rc;
- do {
- GetExitCodeThread( hMusicThread, &rc );
- if ( rc == STILL_ACTIVE ) {
- Sleep( 1 );
- }
- } while( rc == STILL_ACTIVE );
- CloseHandle( hMusicThread );
- }
- if ( musicBuffer ) {
- free( musicBuffer );
- }
- Timidity_Shutdown();
- }
- pMusicSourceVoice = NULL;
- hMusicThread = NULL;
- musicBuffer = NULL;
- totalBufferSize = 0;
- waitingForMusic = false;
- musicReady = false;
- Music_initialized = false;
- }
- int Mus2Midi(unsigned char* bytes, unsigned char* out, int* len);
- namespace {
- const int MaxMidiConversionSize = 1024 * 1024;
- unsigned char midiConversionBuffer[MaxMidiConversionSize];
- }
- /*
- ======================
- I_LoadSong
- ======================
- */
- DWORD WINAPI I_LoadSong( LPVOID songname ) {
- idStr lumpName = "d_";
- lumpName += static_cast< const char * >( songname );
- unsigned char * musFile = static_cast< unsigned char * >( W_CacheLumpName( lumpName.c_str(), PU_STATIC_SHARED ) );
- int length = 0;
- Mus2Midi( musFile, midiConversionBuffer, &length );
- doomMusic = Timidity_LoadSongMem( midiConversionBuffer, length );
- if ( doomMusic ) {
- musicBuffer = (byte *)malloc( MIDI_CHANNELS * MIDI_FORMAT_BYTES * doomMusic->samples );
- totalBufferSize = doomMusic->samples * MIDI_CHANNELS * MIDI_FORMAT_BYTES;
- Timidity_Start( doomMusic );
- int rc = RC_NO_RETURN_VALUE;
- int num_bytes = 0;
- int offset = 0;
- do {
- rc = Timidity_PlaySome( musicBuffer + offset, MIDI_RATE, &num_bytes );
- offset += num_bytes;
- } while ( rc != RC_TUNE_END );
- Timidity_Stop();
- Timidity_FreeSong( doomMusic );
- }
- musicReady = true;
- return ERROR_SUCCESS;
- }
- /*
- ======================
- I_PlaySong
- ======================
- */
- void I_PlaySong( const char *songname, int looping)
- {
- if ( !Music_initialized ) {
- return;
- }
- if ( pMusicSourceVoice != NULL ) {
- // Stop the voice and flush packets before freeing the musicBuffer
- pMusicSourceVoice->Stop();
- pMusicSourceVoice->FlushSourceBuffers();
- }
- // Make sure voice is stopped before we free the buffer
- bool isStopped = false;
- int d = 0;
- while ( !isStopped ) {
- XAUDIO2_VOICE_STATE test;
- if ( pMusicSourceVoice != NULL ) {
- pMusicSourceVoice->GetState( &test );
- }
- if ( test.pCurrentBufferContext == NULL && test.BuffersQueued == 0 ) {
- isStopped = true;
- }
- //I_Printf( "waiting to stop (%d)\n", d++ );
- }
- // Clear old state
- if ( musicBuffer != NULL ) {
- free( musicBuffer );
- musicBuffer = NULL;
- }
- musicReady = false;
- I_LoadSong( (LPVOID)songname );
- waitingForMusic = true;
- if ( DoomLib::GetPlayer() >= 0 ) {
- ::g->mus_looping = looping;
- }
- }
- /*
- ======================
- I_UpdateMusic
- ======================
- */
- void I_UpdateMusic( void ) {
- if ( !Music_initialized ) {
- return;
- }
- if ( waitingForMusic ) {
- if ( musicReady && pMusicSourceVoice != NULL ) {
- if ( musicBuffer ) {
- // Set up packet
- XAUDIO2_BUFFER Packet = { 0 };
- Packet.Flags = XAUDIO2_END_OF_STREAM;
- Packet.AudioBytes = totalBufferSize;
- Packet.pAudioData = (BYTE*)musicBuffer;
- Packet.PlayBegin = 0;
- Packet.PlayLength = 0;
- Packet.LoopBegin = 0;
- Packet.LoopLength = 0;
- Packet.LoopCount = ::g->mus_looping ? XAUDIO2_LOOP_INFINITE : 0;
- Packet.pContext = NULL;
- // Submit packet
- HRESULT hr;
- if( FAILED( hr = pMusicSourceVoice->SubmitSourceBuffer( &Packet ) ) ) {
- int fail = 1;
- }
- // Play the source voice
- if( FAILED( hr = pMusicSourceVoice->Start( 0 ) ) ) {
- int fail = 1;
- }
- }
- waitingForMusic = false;
- }
- }
- if ( pMusicSourceVoice != NULL ) {
- // Set the volume
- pMusicSourceVoice->SetVolume( x_MusicVolume * GLOBAL_VOLUME_MULTIPLIER );
- }
- }
- /*
- ======================
- I_PauseSong
- ======================
- */
- void I_PauseSong (int handle)
- {
- if ( !Music_initialized ) {
- return;
- }
- if ( pMusicSourceVoice != NULL ) {
- // Stop the music source voice
- pMusicSourceVoice->Stop( 0 );
- }
- }
- /*
- ======================
- I_ResumeSong
- ======================
- */
- void I_ResumeSong (int handle)
- {
- if ( !Music_initialized ) {
- return;
- }
- // Stop the music source voice
- if ( pMusicSourceVoice != NULL ) {
- pMusicSourceVoice->Start( 0 );
- }
- }
- /*
- ======================
- I_StopSong
- ======================
- */
- void I_StopSong(int handle)
- {
- if ( !Music_initialized ) {
- return;
- }
- // Stop the music source voice
- if ( pMusicSourceVoice != NULL ) {
- pMusicSourceVoice->Stop( 0 );
- }
- }
- /*
- ======================
- I_UnRegisterSong
- ======================
- */
- void I_UnRegisterSong(int handle)
- {
- // does nothing
- }
- /*
- ======================
- I_RegisterSong
- ======================
- */
- int I_RegisterSong(void* data, int length)
- {
- // does nothing
- return 0;
- }
|