@@ -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+
4455bool 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
180231void 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-
244250void 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}
0 commit comments