From 91301c893f7c2d36a275e406c81c042d103ad0c9 Mon Sep 17 00:00:00 2001 From: Daniel Gibson Date: Sun, 2 Dec 2012 05:00:40 +0100 Subject: [PATCH] Stub away XAudio2 for non-MSVC builds Getting it to work with MinGW seems impossible.. and on Linux/OSX it won't work anyway, so nevermind --- neo/CMakeLists.txt | 22 +- neo/sound/snd_local.h | 19 +- neo/sound/sound.h | 2 +- neo/sound/stub/SoundSample.cpp | 555 +++++++++++++++++++++++++++++++++ neo/sound/stub/SoundStub.h | 217 +++++++++++++ 5 files changed, 811 insertions(+), 4 deletions(-) create mode 100644 neo/sound/stub/SoundSample.cpp create mode 100644 neo/sound/stub/SoundStub.h diff --git a/neo/CMakeLists.txt b/neo/CMakeLists.txt index 0e3c5910..55409660 100644 --- a/neo/CMakeLists.txt +++ b/neo/CMakeLists.txt @@ -19,7 +19,7 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID STREQUAL "Clang") add_definitions(-mmmx -msse -msse2) if(WIN32) # require msvcr70.dll or newer for _aligned_malloc etc - # I think it is from Visual C++ .NET 2002, so it should be available on any modern system. + # I think it is from Visual C++ .NET 2002, so it should be available on any remotely modern system. add_definitions(-D__MSVCRT_VERSION__=0x0700) find_package(DirectX REQUIRED) @@ -360,6 +360,12 @@ set(XAUDIO2_SOURCES sound/XAudio2/XA2_SoundHardware.cpp sound/XAudio2/XA2_SoundSample.cpp sound/XAudio2/XA2_SoundVoice.cpp) + +set(STUBAUDIO_INCLUDES + sound/stub/SoundStub.h) + +set(STUBAUDIO_SOURCES + sound/stub/SoundSample.cpp) set(OGGVORBIS_INCLUDES libs/oggvorbis/ogg/ogg.h @@ -738,6 +744,9 @@ source_group("sound" FILES ${SOUND_SOURCES}) source_group("sound\\XAudio2" FILES ${XAUDIO2_INCLUDES}) source_group("sound\\XAudio2" FILES ${XAUDIO2_SOURCES}) +source_group("sound\\stub" FILES ${STUBAUDIO_INCLUDES}) +source_group("sound\\stub" FILES ${STUBAUDIO_SOURCES}) + source_group("libs\\oggvorbis" FILES ${OGGVORBIS_INCLUDES}) source_group("libs\\oggvorbis" FILES ${OGGVORBIS_SOURCES}) @@ -977,6 +986,17 @@ if(MSVC) wsock32.lib ) else() + list(APPEND RBDOOM3_SOURCES + ${SYS_INCLUDES} ${SYS_SOURCES} + ${STUBAUDIO_INCLUDES} ${STUBAUDIO_SOURCES}) + + # TODO: if WIN32 + list(APPEND RBDOOM3_SOURCES + ${WIN32_INCLUDES} ${WIN32_SOURCES} ${WIN32_RESOURCES}) + + + list(REMOVE_DUPLICATES RBDOOM3_SOURCES) + add_executable(RBDoom3 WIN32 ${RBDOOM3_SOURCES}) add_dependencies(RBDoom3 idlib) diff --git a/neo/sound/snd_local.h b/neo/sound/snd_local.h index ad3d01f1..33ff2a02 100644 --- a/neo/sound/snd_local.h +++ b/neo/sound/snd_local.h @@ -92,6 +92,7 @@ typedef enum #include "SoundVoice.h" +#ifdef _MSC_VER // DG: stub out xaudio for MinGW etc #define OPERATION_SET 1 @@ -115,7 +116,10 @@ typedef enum #include "XAudio2/XA2_SoundVoice.h" #include "XAudio2/XA2_SoundHardware.h" - +#else // not _MSC_VER => MinGW, GCC, ... +// just a stub for now +#include "stub/SoundStub.h" +#endif // _MSC_VER ; DG end //------------------------ // Listener data @@ -441,7 +445,7 @@ public: virtual void InitStreamBuffers(); virtual void FreeStreamBuffers(); - virtual void* GetIXAudio2() const; + virtual void* GetIXAudio2() const; // FIXME: stupid name; get rid of this? not sure if it's really needed.. // for the sound level meter window virtual cinData_t ImageForTime( const int milliseconds, const bool waveform ); @@ -485,8 +489,19 @@ public: sample( NULL ), bufferNumber( 0 ) { } + +#ifdef _MSC_VER // XAudio backend + // DG: because the inheritance is kinda strange (idSoundVoice is derived + // from idSoundVoice_XAudio2), casting the latter to the former isn't possible + // so we need this ugly #ifdef .. idSoundVoice_XAudio2* voice; idSoundSample_XAudio2* sample; +#else // not _MSC_VER + // from stub or something.. + idSoundVoice* voice; + idSoundSample* sample; +#endif // _MSC_VER ; DG end + int bufferNumber; }; diff --git a/neo/sound/sound.h b/neo/sound/sound.h index d9199641..b495a952 100644 --- a/neo/sound/sound.h +++ b/neo/sound/sound.h @@ -319,7 +319,7 @@ public: virtual void FreeStreamBuffers() = 0; // video playback needs to get this - virtual void* GetIXAudio2() const = 0; + virtual void* GetIXAudio2() const = 0; // FIXME: stupid name if we have other backends // for the sound level meter window virtual cinData_t ImageForTime( const int milliseconds, const bool waveform ) = 0; diff --git a/neo/sound/stub/SoundSample.cpp b/neo/sound/stub/SoundSample.cpp new file mode 100644 index 00000000..d4d53965 --- /dev/null +++ b/neo/sound/stub/SoundSample.cpp @@ -0,0 +1,555 @@ +/* +=========================================================================== + +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 . + +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. + +=========================================================================== +*/ + +// DG: SoundSample seems to be XAudio-independent, so this is just a copy of idSoundSample_XAudio2 + +//#include "../../idlib/precompiled.h" +//#include "../snd_local.h" +#include "SoundStub.h" + +extern idCVar s_useCompression; +extern idCVar s_noSound; + +#define GPU_CONVERT_CPU_TO_CPU_CACHED_READONLY_ADDRESS( x ) x + +const uint32 SOUND_MAGIC_IDMSA = 0x6D7A7274; + +extern idCVar sys_lang; + +#define MIN_SAMPLE_RATE 1000 // Minimum audio sample rate supported (this value is from XAudio2) + +/* +======================== +AllocBuffer +======================== +*/ +static void* AllocBuffer( int size, const char* name ) +{ + return Mem_Alloc( size, TAG_AUDIO ); +} + +/* +======================== +FreeBuffer +======================== +*/ +static void FreeBuffer( void* p ) +{ + return Mem_Free( p ); +} + +/* +======================== +idSoundSample_XAudio2::idSoundSample_XAudio2 +======================== +*/ +idSoundSample::idSoundSample() +{ + timestamp = FILE_NOT_FOUND_TIMESTAMP; + loaded = false; + neverPurge = false; + levelLoadReferenced = false; + + memset( &format, 0, sizeof( format ) ); + + totalBufferSize = 0; + + playBegin = 0; + playLength = 0; + + lastPlayedTime = 0; +} + +/* +======================== +idSoundSample::~idSoundSample +======================== +*/ +idSoundSample::~idSoundSample() +{ + FreeData(); +} + +/* +======================== +idSoundSample::WriteGeneratedSample +======================== +*/ +void idSoundSample::WriteGeneratedSample( idFile* fileOut ) +{ + fileOut->WriteBig( SOUND_MAGIC_IDMSA ); + fileOut->WriteBig( timestamp ); + fileOut->WriteBig( loaded ); + fileOut->WriteBig( playBegin ); + fileOut->WriteBig( playLength ); + idWaveFile::WriteWaveFormatDirect( format, fileOut ); + fileOut->WriteBig( ( int )amplitude.Num() ); + fileOut->Write( amplitude.Ptr(), amplitude.Num() ); + fileOut->WriteBig( totalBufferSize ); + fileOut->WriteBig( ( int )buffers.Num() ); + for( int i = 0; i < buffers.Num(); i++ ) + { + fileOut->WriteBig( buffers[ i ].numSamples ); + fileOut->WriteBig( buffers[ i ].bufferSize ); + fileOut->Write( buffers[ i ].buffer, buffers[ i ].bufferSize ); + }; +} +/* +======================== +idSoundSample::WriteAllSamples +======================== +*/ +void idSoundSample::WriteAllSamples( const idStr& sampleName ) +{ + idSoundSample* samplePC = new idSoundSample(); + { + idStrStatic< MAX_OSPATH > inName = sampleName; + inName.Append( ".msadpcm" ); + idStrStatic< MAX_OSPATH > inName2 = sampleName; + inName2.Append( ".wav" ); + + idStrStatic< MAX_OSPATH > outName = "generated/"; + outName.Append( sampleName ); + outName.Append( ".idwav" ); + + if( samplePC->LoadWav( inName ) || samplePC->LoadWav( inName2 ) ) + { + idFile* fileOut = fileSystem->OpenFileWrite( outName, "fs_basepath" ); + samplePC->WriteGeneratedSample( fileOut ); + delete fileOut; + } + } + delete samplePC; +} + +/* +======================== +idSoundSample::LoadGeneratedSound +======================== +*/ +bool idSoundSample::LoadGeneratedSample( const idStr& filename ) +{ + idFileLocal fileIn( fileSystem->OpenFileReadMemory( filename ) ); + if( fileIn != NULL ) + { + uint32 magic; + fileIn->ReadBig( magic ); + fileIn->ReadBig( timestamp ); + fileIn->ReadBig( loaded ); + fileIn->ReadBig( playBegin ); + fileIn->ReadBig( playLength ); + idWaveFile::ReadWaveFormatDirect( format, fileIn ); + int num; + fileIn->ReadBig( num ); + amplitude.Clear(); + amplitude.SetNum( num ); + fileIn->Read( amplitude.Ptr(), amplitude.Num() ); + fileIn->ReadBig( totalBufferSize ); + fileIn->ReadBig( num ); + buffers.SetNum( num ); + for( int i = 0; i < num; i++ ) + { + fileIn->ReadBig( buffers[ i ].numSamples ); + fileIn->ReadBig( buffers[ i ].bufferSize ); + buffers[ i ].buffer = AllocBuffer( buffers[ i ].bufferSize, GetName() ); + fileIn->Read( buffers[ i ].buffer, buffers[ i ].bufferSize ); + buffers[ i ].buffer = GPU_CONVERT_CPU_TO_CPU_CACHED_READONLY_ADDRESS( buffers[ i ].buffer ); + } + return true; + } + return false; +} +/* +======================== +idSoundSample::Load +======================== +*/ +void idSoundSample::LoadResource() +{ + FreeData(); + + if( idStr::Icmpn( GetName(), "_default", 8 ) == 0 ) + { + MakeDefault(); + return; + } + + if( s_noSound.GetBool() ) + { + MakeDefault(); + return; + } + + loaded = false; + + for( int i = 0; i < 2; i++ ) + { + idStrStatic< MAX_OSPATH > sampleName = GetName(); + if( ( i == 0 ) && !sampleName.Replace( "/vo/", va( "/vo/%s/", sys_lang.GetString() ) ) ) + { + i++; + } + idStrStatic< MAX_OSPATH > generatedName = "generated/"; + generatedName.Append( sampleName ); + + { + if( s_useCompression.GetBool() ) + { + sampleName.Append( ".msadpcm" ); + } + else + { + sampleName.Append( ".wav" ); + } + generatedName.Append( ".idwav" ); + } + loaded = LoadGeneratedSample( generatedName ) || LoadWav( sampleName ); + + if( !loaded && s_useCompression.GetBool() ) + { + sampleName.SetFileExtension( "wav" ); + loaded = LoadWav( sampleName ); + } + + if( loaded ) + { + if( cvarSystem->GetCVarBool( "fs_buildresources" ) ) + { + fileSystem->AddSamplePreload( GetName() ); + WriteAllSamples( GetName() ); + + if( sampleName.Find( "/vo/" ) >= 0 ) + { + for( int i = 0; i < Sys_NumLangs(); i++ ) + { + const char* lang = Sys_Lang( i ); + if( idStr::Icmp( lang, ID_LANG_ENGLISH ) == 0 ) + { + continue; + } + idStrStatic< MAX_OSPATH > locName = GetName(); + locName.Replace( "/vo/", va( "/vo/%s/", Sys_Lang( i ) ) ); + WriteAllSamples( locName ); + } + } + } + return; + } + } + + if( !loaded ) + { + // make it default if everything else fails + MakeDefault(); + } + return; +} + +/* +======================== +idSoundSample::LoadWav +======================== +*/ +bool idSoundSample::LoadWav( const idStr& filename ) +{ + + // load the wave + idWaveFile wave; + if( !wave.Open( filename ) ) + { + return false; + } + + idStrStatic< MAX_OSPATH > sampleName = filename; + sampleName.SetFileExtension( "amp" ); + LoadAmplitude( sampleName ); + + const char* formatError = wave.ReadWaveFormat( format ); + if( formatError != NULL ) + { + idLib::Warning( "LoadWav( %s ) : %s", filename.c_str(), formatError ); + MakeDefault(); + return false; + } + timestamp = wave.Timestamp(); + + totalBufferSize = wave.SeekToChunk( 'data' ); + + if( format.basic.formatTag == idWaveFile::FORMAT_PCM || format.basic.formatTag == idWaveFile::FORMAT_EXTENSIBLE ) + { + + if( format.basic.bitsPerSample != 16 ) + { + idLib::Warning( "LoadWav( %s ) : %s", filename.c_str(), "Not a 16 bit PCM wav file" ); + MakeDefault(); + return false; + } + + playBegin = 0; + playLength = ( totalBufferSize ) / format.basic.blockSize; + + buffers.SetNum( 1 ); + buffers[0].bufferSize = totalBufferSize; + buffers[0].numSamples = playLength; + buffers[0].buffer = AllocBuffer( totalBufferSize, GetName() ); + + + wave.Read( buffers[0].buffer, totalBufferSize ); + + if( format.basic.bitsPerSample == 16 ) + { + idSwap::LittleArray( ( short* )buffers[0].buffer, totalBufferSize / sizeof( short ) ); + } + + buffers[0].buffer = GPU_CONVERT_CPU_TO_CPU_CACHED_READONLY_ADDRESS( buffers[0].buffer ); + + } + else if( format.basic.formatTag == idWaveFile::FORMAT_ADPCM ) + { + + playBegin = 0; + playLength = ( ( totalBufferSize / format.basic.blockSize ) * format.extra.adpcm.samplesPerBlock ); + + buffers.SetNum( 1 ); + buffers[0].bufferSize = totalBufferSize; + buffers[0].numSamples = playLength; + buffers[0].buffer = AllocBuffer( totalBufferSize, GetName() ); + + wave.Read( buffers[0].buffer, totalBufferSize ); + + buffers[0].buffer = GPU_CONVERT_CPU_TO_CPU_CACHED_READONLY_ADDRESS( buffers[0].buffer ); + + } + else if( format.basic.formatTag == idWaveFile::FORMAT_XMA2 ) + { + + if( format.extra.xma2.blockCount == 0 ) + { + idLib::Warning( "LoadWav( %s ) : %s", filename.c_str(), "No data blocks in file" ); + MakeDefault(); + return false; + } + + int bytesPerBlock = format.extra.xma2.bytesPerBlock; + assert( format.extra.xma2.blockCount == ALIGN( totalBufferSize, bytesPerBlock ) / bytesPerBlock ); + assert( format.extra.xma2.blockCount * bytesPerBlock >= totalBufferSize ); + assert( format.extra.xma2.blockCount * bytesPerBlock < totalBufferSize + bytesPerBlock ); + + buffers.SetNum( format.extra.xma2.blockCount ); + for( int i = 0; i < buffers.Num(); i++ ) + { + if( i == buffers.Num() - 1 ) + { + buffers[i].bufferSize = totalBufferSize - ( i * bytesPerBlock ); + } + else + { + buffers[i].bufferSize = bytesPerBlock; + } + + buffers[i].buffer = AllocBuffer( buffers[i].bufferSize, GetName() ); + wave.Read( buffers[i].buffer, buffers[i].bufferSize ); + buffers[i].buffer = GPU_CONVERT_CPU_TO_CPU_CACHED_READONLY_ADDRESS( buffers[i].buffer ); + } + + int seekTableSize = wave.SeekToChunk( 'seek' ); + if( seekTableSize != 4 * buffers.Num() ) + { + idLib::Warning( "LoadWav( %s ) : %s", filename.c_str(), "Wrong number of entries in seek table" ); + MakeDefault(); + return false; + } + + for( int i = 0; i < buffers.Num(); i++ ) + { + wave.Read( &buffers[i].numSamples, sizeof( buffers[i].numSamples ) ); + idSwap::Big( buffers[i].numSamples ); + } + + playBegin = format.extra.xma2.loopBegin; + playLength = format.extra.xma2.loopLength; + + if( buffers[buffers.Num() - 1].numSamples < playBegin + playLength ) + { + // This shouldn't happen, but it's not fatal if it does + playLength = buffers[buffers.Num() - 1].numSamples - playBegin; + } + else + { + // Discard samples beyond playLength + for( int i = 0; i < buffers.Num(); i++ ) + { + if( buffers[i].numSamples > playBegin + playLength ) + { + buffers[i].numSamples = playBegin + playLength; + // Ideally, the following loop should always have 0 iterations because playBegin + playLength ends in the last block already + // But there is no guarantee for that, so to be safe, discard all buffers beyond this one + for( int j = i + 1; j < buffers.Num(); j++ ) + { + FreeBuffer( buffers[j].buffer ); + } + buffers.SetNum( i + 1 ); + break; + } + } + } + + } + else + { + idLib::Warning( "LoadWav( %s ) : Unsupported wave format %d", filename.c_str(), format.basic.formatTag ); + MakeDefault(); + return false; + } + + wave.Close(); + + if( format.basic.formatTag == idWaveFile::FORMAT_EXTENSIBLE ) + { + // HACK: XAudio2 doesn't really support FORMAT_EXTENSIBLE so we convert it to a basic format after extracting the channel mask + format.basic.formatTag = format.extra.extensible.subFormat.data1; + } + + // sanity check... + assert( buffers[buffers.Num() - 1].numSamples == playBegin + playLength ); + + return true; +} + + +/* +======================== +idSoundSample::MakeDefault +======================== +*/ +void idSoundSample::MakeDefault() +{ + FreeData(); + + static const int DEFAULT_NUM_SAMPLES = 256; + + timestamp = FILE_NOT_FOUND_TIMESTAMP; + loaded = true; + + memset( &format, 0, sizeof( format ) ); + format.basic.formatTag = idWaveFile::FORMAT_PCM; + format.basic.numChannels = 1; + format.basic.bitsPerSample = 16; + format.basic.samplesPerSec = MIN_SAMPLE_RATE; + format.basic.blockSize = format.basic.numChannels * format.basic.bitsPerSample / 8; + format.basic.avgBytesPerSec = format.basic.samplesPerSec * format.basic.blockSize; + + assert( format.basic.blockSize == 2 ); + + totalBufferSize = DEFAULT_NUM_SAMPLES * 2; + + short* defaultBuffer = ( short* )AllocBuffer( totalBufferSize, GetName() ); + for( int i = 0; i < DEFAULT_NUM_SAMPLES; i += 2 ) + { + defaultBuffer[i + 0] = SHRT_MIN; + defaultBuffer[i + 1] = SHRT_MAX; + } + + buffers.SetNum( 1 ); + buffers[0].buffer = defaultBuffer; + buffers[0].bufferSize = totalBufferSize; + buffers[0].numSamples = DEFAULT_NUM_SAMPLES; + buffers[0].buffer = GPU_CONVERT_CPU_TO_CPU_CACHED_READONLY_ADDRESS( buffers[0].buffer ); + + playBegin = 0; + playLength = DEFAULT_NUM_SAMPLES; +} + +/* +======================== +idSoundSample::FreeData + +Called before deleting the object and at the start of LoadResource() +======================== +*/ +void idSoundSample::FreeData() +{ + if( buffers.Num() > 0 ) + { + soundSystemLocal.StopVoicesWithSample( ( idSoundSample* )this ); + for( int i = 0; i < buffers.Num(); i++ ) + { + FreeBuffer( buffers[i].buffer ); + } + buffers.Clear(); + } + amplitude.Clear(); + + timestamp = FILE_NOT_FOUND_TIMESTAMP; + memset( &format, 0, sizeof( format ) ); + loaded = false; + totalBufferSize = 0; + playBegin = 0; + playLength = 0; +} + +/* +======================== +idSoundSample::LoadAmplitude +======================== +*/ +bool idSoundSample::LoadAmplitude( const idStr& name ) +{ + amplitude.Clear(); + idFileLocal f( fileSystem->OpenFileRead( name ) ); + if( f == NULL ) + { + return false; + } + amplitude.SetNum( f->Length() ); + f->Read( amplitude.Ptr(), amplitude.Num() ); + return true; +} + +/* +======================== +idSoundSample::GetAmplitude +======================== +*/ +float idSoundSample::GetAmplitude( int timeMS ) const +{ + if( timeMS < 0 || timeMS > LengthInMsec() ) + { + return 0.0f; + } + if( IsDefault() ) + { + return 1.0f; + } + int index = timeMS * 60 / 1000; + if( index < 0 || index >= amplitude.Num() ) + { + return 0.0f; + } + return ( float )amplitude[index] / 255.0f; +} diff --git a/neo/sound/stub/SoundStub.h b/neo/sound/stub/SoundStub.h new file mode 100644 index 00000000..4278082b --- /dev/null +++ b/neo/sound/stub/SoundStub.h @@ -0,0 +1,217 @@ +/* +=========================================================================== + +Doom 3 BFG Edition GPL Source Code +Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. +Copyright (C) 2012 Daniel Gibson + +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 . + +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. + +=========================================================================== +*/ + +/* + * DG: a stub to get d3 bfg to compile without XAudio2, because that doesn't work with MinGW + * or on non-Windows platforms. + * + * Please note that many methods are *not* virtual, so just inheriting from the stubs for the + * actual implementations may *not* work! + * (Making them virtual should be evaluated for performance-loss though, it would make the code + * cleaner and may be feasible) + */ + +#include "../SoundVoice.h" +#include "idlib/precompiled.h" // TIME_T + +#ifndef SOUNDSTUB_H_ +#define SOUNDSTUB_H_ + +class idSoundVoice : public idSoundVoice_Base +{ +}; + +class idSoundHardware +{ +public: + idSoundHardware(){} + + void Init(){} + void Shutdown(){} + + void Update(){} + + // FIXME: this is a bad name when having multiple sound backends... and maybe it's not even needed + void* GetIXAudio2() const // NOTE: originally this returned IXAudio2*, but that was casted to void later anyway + { return NULL; } + + idSoundVoice* AllocateVoice( const idSoundSample* leadinSample, const idSoundSample* loopingSample ) + { return NULL; } + + void FreeVoice( idSoundVoice* voice ){} + + int GetNumZombieVoices() const + { return 0; } + + int GetNumFreeVoices() const + { return 0; } + +}; + +// ok, this one isn't really a stub, because it seems to be XAudio-independent, +// I just copied the class from idSoundSample_XAudio2 and renamed it +class idSoundSample +{ +public: + idSoundSample(); + + // Loads and initializes the resource based on the name. + virtual void LoadResource(); + + void SetName( const char* n ) + { + name = n; + } + const char* GetName() const + { + return name; + } + ID_TIME_T GetTimestamp() const + { + return timestamp; + } + + // turns it into a beep + void MakeDefault(); + + // frees all data + void FreeData(); + + int LengthInMsec() const + { + return SamplesToMsec( NumSamples(), SampleRate() ); + } + int SampleRate() const + { + return format.basic.samplesPerSec; + } + int NumSamples() const + { + return playLength; + } + int NumChannels() const + { + return format.basic.numChannels; + } + int BufferSize() const + { + return totalBufferSize; + } + + bool IsCompressed() const + { + return ( format.basic.formatTag != idWaveFile::FORMAT_PCM ); + } + + bool IsDefault() const + { + return timestamp == FILE_NOT_FOUND_TIMESTAMP; + } + bool IsLoaded() const + { + return loaded; + } + + void SetNeverPurge() + { + neverPurge = true; + } + bool GetNeverPurge() const + { + return neverPurge; + } + + void SetLevelLoadReferenced() + { + levelLoadReferenced = true; + } + void ResetLevelLoadReferenced() + { + levelLoadReferenced = false; + } + bool GetLevelLoadReferenced() const + { + return levelLoadReferenced; + } + + int GetLastPlayedTime() const + { + return lastPlayedTime; + } + void SetLastPlayedTime( int t ) + { + lastPlayedTime = t; + } + + float GetAmplitude( int timeMS ) const; + +protected: + +/* + friend class idSoundHardware_XAudio2; + friend class idSoundVoice_XAudio2; +*/ + ~idSoundSample(); + + bool LoadWav( const idStr& name ); + bool LoadAmplitude( const idStr& name ); + void WriteAllSamples( const idStr& sampleName ); + bool LoadGeneratedSample( const idStr& name ); + void WriteGeneratedSample( idFile* fileOut ); + + struct sampleBuffer_t + { + void* buffer; + int bufferSize; + int numSamples; + }; + + idStr name; + + ID_TIME_T timestamp; + bool loaded; + + bool neverPurge; + bool levelLoadReferenced; + bool usesMapHeap; + + uint32 lastPlayedTime; + + int totalBufferSize; // total size of all the buffers + idList buffers; + + int playBegin; + int playLength; + + idWaveFile::waveFmt_t format; + + idList amplitude; +}; + +#endif /* SOUNDSTUB_H_ */