Skip to content

Commit 6fab704

Browse files
committed
Add OGG soundtrack support and refactor audio system
Refactored CWavPlayer to CSoundtrackSystem to support both WAV and OGG playback using OpenAL and libvorbis. Updated CMakeLists.txt to include ogg and vorbis libraries and headers. Replaced old command interface with soundtrack_play and soundtrack_stop commands, supporting looped playback. Updated initialization and shutdown logic to use the new system.
1 parent 0c76747 commit 6fab704

File tree

4 files changed

+116
-71
lines changed

4 files changed

+116
-71
lines changed

CMakeLists.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,19 @@ set(CMAKE_POLICY_VERSION_MINIMUM 3.23)
22
cmake_minimum_required(VERSION 3.23)
33
set(ALSOFT_USE_CPP20_MODULES OFF CACHE BOOL "Disable OpenAL C++20 modules" FORCE)
44
set(CMAKE_CXX_SCAN_FOR_MODULES OFF CACHE BOOL "Disable module scanning" FORCE)
5+
set(ALSOFT_UTILS OFF CACHE BOOL "" FORCE)
6+
set(ALSOFT_TESTS OFF CACHE BOOL "" FORCE)
7+
set(ALSOFT_EXAMPLES OFF CACHE BOOL "" FORCE)
8+
9+
set(ALSOFT_INSTALL OFF CACHE BOOL "" FORCE)
10+
11+
set(ALSOFT_NO_CONFIG_UTIL OFF CACHE BOOL "" FORCE)
12+
13+
set(BUILD_SHARED_LIBS OFF CACHE BOOL "" FORCE)
14+
set(OGG_BUILD_TESTS OFF CACHE BOOL "" FORCE)
15+
set(VORBIS_BUILD_TESTS OFF CACHE BOOL "" FORCE)
16+
set(VORBIS_ENABLE_DOCS OFF CACHE BOOL "" FORCE)
17+
518

619
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<OR:$<CONFIG:Debug>,$<CONFIG:SteamDebug>,$<CONFIG:HaloDebug>>:Debug>DLL")
720

@@ -166,6 +179,8 @@ add_subdirectory(game_shared)
166179
add_subdirectory(pm_shared)
167180
add_subdirectory(public)
168181
add_subdirectory(external/openal-soft)
182+
add_subdirectory(external/ogg)
183+
add_subdirectory(external/vorbis)
169184
add_subdirectory(source_sdk)
170185

171186
get_property(SOURCE_FILES GLOBAL PROPERTY SOURCE_FILES)
@@ -185,6 +200,8 @@ target_include_directories(client PRIVATE
185200
external
186201
external/discord-rpc/include
187202
external/openal-soft/include
203+
external/ogg/include
204+
external/vorbis/include
188205
game_shared
189206
pm_shared
190207
public
@@ -292,4 +309,4 @@ target_compile_definitions(client PRIVATE
292309
-DCLIENT_WEAPONS
293310
-DUPDATE_CHECK)
294311

295-
target_link_libraries(client discord-rpc OpenAL)
312+
target_link_libraries(client discord-rpc OpenAL::OpenAL vorbisfile vorbis ogg)

cl_dll/audio/openal_wav.cpp

Lines changed: 85 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -41,24 +41,32 @@ bool CSoundtrackSystem::Init()
4141
gEngfuncs.Con_Printf("OpenAL error after alGenSources: %d\n", err);
4242
}
4343

44+
bool CSoundtrackSystem::LoadSoundtrack(const std::string& filename)
45+
{
46+
std::string lower = filename;
47+
for (auto& c : lower) c = tolower(c);
48+
49+
if (lower.find(".ogg") != std::string::npos || lower.find(".rts") != std::string::npos) // .rts is also ogg
50+
return LoadOgg(filename);
51+
else
52+
return LoadWav(filename);
53+
}
54+
4455
bool CSoundtrackSystem::LoadWav(const std::string& filename)
4556
{
46-
// Construct full path: <gamedir>/sound/<filename>
47-
const char* gamedir = gEngfuncs.pfnGetGameDirectory();
48-
std::string path = filename;
4957

50-
FILE* file = fopen(path.c_str(), "rb");
58+
FILE* file = fopen(filename.c_str(), "rb");
5159
if (!file)
5260
{
53-
gEngfuncs.Con_Printf("CSoundtrackSystem: Failed to open file: %s\n", path.c_str());
61+
gEngfuncs.Con_Printf("CSoundtrackSystem: Failed to open file: %s\n", filename.c_str());
5462
return false;
5563
}
5664

5765
char riff[4];
5866
fread(riff, 1, 4, file);
5967
if (strncmp(riff, "RIFF", 4) != 0)
6068
{
61-
gEngfuncs.Con_Printf("CSoundtrackSystem: Not a RIFF file: %s\n", path.c_str());
69+
gEngfuncs.Con_Printf("CSoundtrackSystem: Not a RIFF file: %s\n", filename.c_str());
6270
fclose(file);
6371
return false;
6472
}
@@ -68,7 +76,7 @@ bool CSoundtrackSystem::LoadWav(const std::string& filename)
6876
fread(wave, 1, 4, file);
6977
if (strncmp(wave, "WAVE", 4) != 0)
7078
{
71-
gEngfuncs.Con_Printf("CSoundtrackSystem: Not a WAVE file: %s\n", path.c_str());
79+
gEngfuncs.Con_Printf("CSoundtrackSystem: Not a WAVE file: %s\n", filename.c_str());
7280
fclose(file);
7381
return false;
7482
}
@@ -132,7 +140,7 @@ bool CSoundtrackSystem::LoadWav(const std::string& filename)
132140

133141
if (audioData.empty())
134142
{
135-
gEngfuncs.Con_Printf("CSoundtrackSystem: No audio data found in %s\n", path.c_str());
143+
gEngfuncs.Con_Printf("CSoundtrackSystem: No audio data found in %s\n", filename.c_str());
136144
return false;
137145
}
138146

@@ -168,13 +176,56 @@ bool CSoundtrackSystem::LoadWav(const std::string& filename)
168176
return false;
169177
}
170178

171-
gEngfuncs.Con_Printf("CSoundtrackSystem: Loaded WAV file: %s\n", path.c_str());
179+
gEngfuncs.Con_Printf("CSoundtrackSystem: Loaded WAV file: %s\n", filename.c_str());
180+
return true;
181+
}
182+
183+
bool CSoundtrackSystem::LoadOgg(const std::string& filename)
184+
{
185+
OggVorbis_File vf;
186+
if (ov_fopen(filename.c_str(), &vf) < 0)
187+
{
188+
gEngfuncs.Con_Printf("CSoundtrackSystem: Failed to open OGG file: %s\n", filename.c_str());
189+
return false;
190+
}
191+
192+
vorbis_info* info = ov_info(&vf, -1);
193+
int channels = info->channels;
194+
long sampleRate = info->rate;
195+
ALenum format = (channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16;
196+
197+
std::vector<char> pcm;
198+
char buffer[4096];
199+
int bitstream;
200+
201+
long bytes;
202+
while ((bytes = ov_read(&vf, buffer, sizeof(buffer), 0,2,1, &bitstream)) > 0)
203+
pcm.insert(pcm.end(), buffer, buffer + bytes);
204+
205+
ov_clear(&vf);
206+
207+
if (pcm.empty())
208+
{
209+
gEngfuncs.Con_Printf("CSoundtrackSystem: No audio data found in %s\n", filename.c_str());
210+
return false;
211+
}
212+
213+
if (m_buffer)
214+
alDeleteBuffers(1, &m_buffer);
215+
216+
alGenBuffers(1, &m_buffer);
217+
alBufferData(m_buffer, format, pcm.data(), (ALsizei)pcm.size(), sampleRate);
218+
alSourcei(m_source, AL_BUFFER, m_buffer);
219+
220+
gEngfuncs.Con_Printf("CSoundtrackSystem: Loaded OGG file: %s\n", filename.c_str());
172221
return true;
173222
}
174223

175-
void CSoundtrackSystem::Play()
224+
void CSoundtrackSystem::Play(bool loop)
176225
{
177-
alSourcePlay(m_source);
226+
alSourcei(m_source, AL_LOOPING, loop ? AL_TRUE : AL_FALSE);
227+
SetVolumeFromCvar();
228+
alSourcePlay(m_source);
178229
}
179230

180231
void CSoundtrackSystem::Stop()
@@ -196,51 +247,6 @@ void CSoundtrackSystem::SetVolumeFromCvar()
196247
alSourcef(m_source, AL_GAIN, vol);
197248
}
198249

199-
void CSoundtrackSystem::PlayCmd()
200-
{
201-
if (!g_SoundtrackSystem.Init())
202-
{
203-
gEngfuncs.Con_Printf("WHAT THE FUCK?!?\n");
204-
return;
205-
}
206-
207-
if (gEngfuncs.Cmd_Argc() < 2)
208-
{
209-
gEngfuncs.Con_Printf("Usage: al_play <filename.wav> [play|loop]\n");
210-
return;
211-
}
212-
213-
const char* filename = gEngfuncs.Cmd_Argv(1);
214-
const char* mode = (gEngfuncs.Cmd_Argc() >= 3) ? gEngfuncs.Cmd_Argv(2) : "play";
215-
216-
std::string path;
217-
std::string snd = "sound/";
218-
const char* gamedir = gEngfuncs.pfnGetGameDirectory();
219-
path = std::string(gamedir) + "/" + snd + filename;
220-
221-
if (!g_SoundtrackSystem.LoadWav(path))
222-
{
223-
gEngfuncs.Con_Printf("Failed to load WAV file from %s.\n", path.c_str());
224-
return;
225-
}
226-
else
227-
gEngfuncs.Con_Printf("Loading WAV from %s.\n", path.c_str());
228-
229-
if (stricmp(mode, "loop") == 0)
230-
alSourcei(g_SoundtrackSystem.m_source, AL_LOOPING, AL_TRUE);
231-
else
232-
alSourcei(g_SoundtrackSystem.m_source, AL_LOOPING, AL_FALSE);
233-
234-
g_SoundtrackSystem.SetVolumeFromCvar();
235-
g_SoundtrackSystem.Play();
236-
}
237-
238-
void CSoundtrackSystem::StopCmd()
239-
{
240-
g_SoundtrackSystem.Stop();
241-
gEngfuncs.Con_Printf("stopped\n");
242-
}
243-
244250
void CSoundtrackSystem::Shutdown()
245251
{
246252
alDeleteSources(1, &m_source);
@@ -249,12 +255,31 @@ void CSoundtrackSystem::Shutdown()
249255
alcCloseDevice(m_device);
250256
}
251257

252-
CON_COMMAND(al_play, "None")
258+
CON_COMMAND(soundtrack_play, "file.ext [loop]")
253259
{
254-
g_SoundtrackSystem.PlayCmd();
260+
if (!g_SoundtrackSystem.Init())
261+
{
262+
gEngfuncs.Con_Printf("soundtrack_play: Failed to initialize OpenAL\n");
263+
return;
264+
}
265+
266+
if (gEngfuncs.Cmd_Argc() < 2)
267+
{
268+
gEngfuncs.Con_Printf("Usage: soundtrack_play <file.ext> [loop]\n");
269+
return;
270+
}
271+
272+
std::string file = gEngfuncs.Cmd_Argv(1);
273+
std::string path = std::string(gEngfuncs.pfnGetGameDirectory()) + "/sound/" + file;
274+
275+
if (!g_SoundtrackSystem.LoadSoundtrack(path))
276+
return;
277+
278+
bool loop = (gEngfuncs.Cmd_Argc() >= 3 && !stricmp(gEngfuncs.Cmd_Argv(2), "loop"));
279+
g_SoundtrackSystem.Play(loop);
255280
}
256281

257-
CON_COMMAND(al_stop, "none")
282+
CON_COMMAND(soundtrack_stop, "Stop soundtrack")
258283
{
259-
g_SoundtrackSystem.StopCmd();
284+
g_SoundtrackSystem.Stop();
260285
}

cl_dll/audio/openal_wav.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,29 @@
1212
#pragma once
1313

1414
#include <string>
15-
#include <AL/al.h>
1615
#include <AL/alc.h>
16+
#include <AL/al.h>
17+
#include <ogg/ogg.h>
18+
#include <vorbis/vorbisfile.h>
1719

18-
class CWavPlayer
20+
class CSoundtrackSystem
1921
{
2022
public:
2123
bool Init();
22-
bool LoadWav(const std::string& filename);
23-
void Play();
24+
bool LoadSoundtrack(const std::string& filename); // handles wav and ogg soundtracks
25+
void Play(bool loop);
2426
void Stop();
2527
void SetVolumeFromCvar();
26-
void PlayCmd();
27-
void StopCmd();
2828
void Shutdown();
2929

3030
private:
31+
bool LoadWav(const std::string& filename);
32+
bool LoadOgg(const std::string& filename);
33+
3134
ALCdevice* m_device = nullptr;
3235
ALCcontext* m_context = nullptr;
3336
ALuint m_source = 0;
3437
ALuint m_buffer = 0;
3538
};
3639

37-
extern CWavPlayer g_WavPlayer;
40+
extern CSoundtrackSystem g_SoundtrackSystem;

cl_dll/cdll_int.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ int CL_DLLEXPORT Initialize( cldll_enginefunc_t *pEnginefuncs, int iVersion )
173173
update_checker::check_for_updates();
174174
discord_integration::initialize();
175175

176-
if (!g_WavPlayer.Init())
176+
if (!g_SoundtrackSystem.Init())
177177
gEngfuncs.Con_Printf("Failed to init openal\n");
178178

179179
CvarSystem::RegisterCvars();
@@ -359,8 +359,8 @@ void CL_DLLEXPORT HUD_Shutdown(void)
359359
CL_UnloadParticleMan();
360360
console::HudShutdown();
361361
discord_integration::shutdown();
362-
g_WavPlayer.Stop();
363-
g_WavPlayer.Shutdown();
362+
g_SoundtrackSystem.Stop();
363+
g_SoundtrackSystem.Shutdown();
364364
}
365365

366366
//---------------------------------------------------

0 commit comments

Comments
 (0)