doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
snd_decoder.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "snd_local.h"
33 #include "OggVorbis/vorbis/codec.h"
35 
36 
37 /*
38 ===================================================================================
39 
40  Thread safe decoder memory allocator.
41 
42  Each OggVorbis decoder consumes about 150kB of memory.
43 
44 ===================================================================================
45 */
46 
48 
49 const int MIN_OGGVORBIS_MEMORY = 768 * 1024;
50 
51 extern "C" {
52  void *_decoder_malloc( size_t size );
53  void *_decoder_calloc( size_t num, size_t size );
54  void *_decoder_realloc( void *memblock, size_t size );
55  void _decoder_free( void *memblock );
56 }
57 
58 void *_decoder_malloc( size_t size ) {
59  void *ptr = decoderMemoryAllocator.Alloc( size );
60  assert( size == 0 || ptr != NULL );
61  return ptr;
62 }
63 
64 void *_decoder_calloc( size_t num, size_t size ) {
65  void *ptr = decoderMemoryAllocator.Alloc( num * size );
66  assert( ( num * size ) == 0 || ptr != NULL );
67  memset( ptr, 0, num * size );
68  return ptr;
69 }
70 
71 void *_decoder_realloc( void *memblock, size_t size ) {
72  void *ptr = decoderMemoryAllocator.Resize( (byte *)memblock, size );
73  assert( size == 0 || ptr != NULL );
74  return ptr;
75 }
76 
77 void _decoder_free( void *memblock ) {
78  decoderMemoryAllocator.Free( (byte *)memblock );
79 }
80 
81 
82 /*
83 ===================================================================================
84 
85  OggVorbis file loading/decoding.
86 
87 ===================================================================================
88 */
89 
90 /*
91 ====================
92 FS_ReadOGG
93 ====================
94 */
95 size_t FS_ReadOGG( void *dest, size_t size1, size_t size2, void *fh ) {
96  idFile *f = reinterpret_cast<idFile *>(fh);
97  return f->Read( dest, size1 * size2 );
98 }
99 
100 /*
101 ====================
102 FS_SeekOGG
103 ====================
104 */
105 int FS_SeekOGG( void *fh, ogg_int64_t to, int type ) {
106  fsOrigin_t retype = FS_SEEK_SET;
107 
108  if ( type == SEEK_CUR ) {
109  retype = FS_SEEK_CUR;
110  } else if ( type == SEEK_END ) {
111  retype = FS_SEEK_END;
112  } else if ( type == SEEK_SET ) {
113  retype = FS_SEEK_SET;
114  } else {
115  common->FatalError( "fs_seekOGG: seek without type\n" );
116  }
117  idFile *f = reinterpret_cast<idFile *>(fh);
118  return f->Seek( to, retype );
119 }
120 
121 /*
122 ====================
123 FS_CloseOGG
124 ====================
125 */
126 int FS_CloseOGG( void *fh ) {
127  return 0;
128 }
129 
130 /*
131 ====================
132 FS_TellOGG
133 ====================
134 */
135 long FS_TellOGG( void *fh ) {
136  idFile *f = reinterpret_cast<idFile *>(fh);
137  return f->Tell();
138 }
139 
140 /*
141 ====================
142 ov_openFile
143 ====================
144 */
146  ov_callbacks callbacks;
147 
148  memset( vf, 0, sizeof( OggVorbis_File ) );
149 
150  callbacks.read_func = FS_ReadOGG;
151  callbacks.seek_func = FS_SeekOGG;
152  callbacks.close_func = FS_CloseOGG;
153  callbacks.tell_func = FS_TellOGG;
154  return ov_open_callbacks((void *)f, vf, NULL, -1, callbacks);
155 }
156 
157 /*
158 ====================
159 idWaveFile::OpenOGG
160 ====================
161 */
162 int idWaveFile::OpenOGG( const char* strFileName, waveformatex_t *pwfx ) {
163  OggVorbis_File *ov;
164 
165  memset( pwfx, 0, sizeof( waveformatex_t ) );
166 
167  mhmmio = fileSystem->OpenFileRead( strFileName );
168  if ( !mhmmio ) {
169  return -1;
170  }
171 
173 
174  ov = new OggVorbis_File;
175 
176  if( ov_openFile( mhmmio, ov ) < 0 ) {
177  delete ov;
180  mhmmio = NULL;
181  return -1;
182  }
183 
185 
186  vorbis_info *vi = ov_info( ov, -1 );
187 
190  mpwfx.Format.wBitsPerSample = sizeof(short) * 8;
191  mdwSize = ov_pcm_total( ov, -1 ) * vi->channels; // pcm samples * num channels
192  mbIsReadingFromMemory = false;
193 
194  if ( idSoundSystemLocal::s_realTimeDecoding.GetBool() ) {
195 
196  ov_clear( ov );
198  mhmmio = NULL;
199  delete ov;
200 
202  mhmmio = fileSystem->OpenFileRead( strFileName );
203  mMemSize = mhmmio->Length();
204 
205  } else {
206 
207  ogg = ov;
208 
210  mMemSize = mdwSize * sizeof( short );
211  }
212 
213  memcpy( pwfx, &mpwfx, sizeof( waveformatex_t ) );
214 
216 
217  isOgg = true;
218 
219  return 0;
220 }
221 
222 /*
223 ====================
224 idWaveFile::ReadOGG
225 ====================
226 */
227 int idWaveFile::ReadOGG( byte* pBuffer, int dwSizeToRead, int *pdwSizeRead ) {
228  int total = dwSizeToRead;
229  char *bufferPtr = (char *)pBuffer;
231 
232  do {
233  int ret = ov_read( ov, bufferPtr, total >= 4096 ? 4096 : total, Swap_IsBigEndian(), 2, 1, &ov->stream );
234  if ( ret == 0 ) {
235  break;
236  }
237  if ( ret < 0 ) {
238  return -1;
239  }
240  bufferPtr += ret;
241  total -= ret;
242  } while( total > 0 );
243 
244  dwSizeToRead = (byte *)bufferPtr - pBuffer;
245 
246  if ( pdwSizeRead != NULL ) {
247  *pdwSizeRead = dwSizeToRead;
248  }
249 
250  return dwSizeToRead;
251 }
252 
253 /*
254 ====================
255 idWaveFile::CloseOGG
256 ====================
257 */
258 int idWaveFile::CloseOGG( void ) {
260  if ( ov != NULL ) {
262  ov_clear( ov );
263  delete ov;
266  mhmmio = NULL;
267  ogg = NULL;
268  return 0;
269  }
270  return -1;
271 }
272 
273 
274 /*
275 ===================================================================================
276 
277  idSampleDecoderLocal
278 
279 ===================================================================================
280 */
281 
283 public:
284  virtual void Decode( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest );
285  virtual void ClearDecoder( void );
286  virtual idSoundSample * GetSample( void ) const;
287  virtual int GetLastDecodeTime( void ) const;
288 
289  void Clear( void );
290  int DecodePCM( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest );
291  int DecodeOGG( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest );
292 
293 private:
294  bool failed; // set if decoding failed
295  int lastFormat; // last format being decoded
296  idSoundSample * lastSample; // last sample being decoded
297  int lastSampleOffset; // last offset into the decoded sample
298  int lastDecodeTime; // last time decoding sound
299  idFile_Memory file; // encoded file in memory
300 
301  OggVorbis_File ogg; // OggVorbis file
302 };
303 
305 
306 /*
307 ====================
308 idSampleDecoder::Init
309 ====================
310 */
311 void idSampleDecoder::Init( void ) {
312  decoderMemoryAllocator.Init();
313  decoderMemoryAllocator.SetLockMemory( true );
314  decoderMemoryAllocator.SetFixedBlocks( idSoundSystemLocal::s_realTimeDecoding.GetBool() ? 10 : 1 );
315 }
316 
317 /*
318 ====================
319 idSampleDecoder::Shutdown
320 ====================
321 */
323  decoderMemoryAllocator.Shutdown();
324  sampleDecoderAllocator.Shutdown();
325 }
326 
327 /*
328 ====================
329 idSampleDecoder::Alloc
330 ====================
331 */
333  idSampleDecoderLocal *decoder = sampleDecoderAllocator.Alloc();
334  decoder->Clear();
335  return decoder;
336 }
337 
338 /*
339 ====================
340 idSampleDecoder::Free
341 ====================
342 */
344  idSampleDecoderLocal *localDecoder = static_cast<idSampleDecoderLocal *>( decoder );
345  localDecoder->ClearDecoder();
346  sampleDecoderAllocator.Free( localDecoder );
347 }
348 
349 /*
350 ====================
351 idSampleDecoder::GetNumUsedBlocks
352 ====================
353 */
355  return decoderMemoryAllocator.GetNumUsedBlocks();
356 }
357 
358 /*
359 ====================
360 idSampleDecoder::GetUsedBlockMemory
361 ====================
362 */
364  return decoderMemoryAllocator.GetUsedBlockMemory();
365 }
366 
367 /*
368 ====================
369 idSampleDecoderLocal::Clear
370 ====================
371 */
373  failed = false;
375  lastSample = NULL;
376  lastSampleOffset = 0;
377  lastDecodeTime = 0;
378 }
379 
380 /*
381 ====================
382 idSampleDecoderLocal::ClearDecoder
383 ====================
384 */
387 
388  switch( lastFormat ) {
389  case WAVE_FORMAT_TAG_PCM: {
390  break;
391  }
392  case WAVE_FORMAT_TAG_OGG: {
393  ov_clear( &ogg );
394  memset( &ogg, 0, sizeof( ogg ) );
395  break;
396  }
397  }
398 
399  Clear();
400 
402 }
403 
404 /*
405 ====================
406 idSampleDecoderLocal::GetSample
407 ====================
408 */
410  return lastSample;
411 }
412 
413 /*
414 ====================
415 idSampleDecoderLocal::GetLastDecodeTime
416 ====================
417 */
419  return lastDecodeTime;
420 }
421 
422 /*
423 ====================
424 idSampleDecoderLocal::Decode
425 ====================
426 */
427 void idSampleDecoderLocal::Decode( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest ) {
428  int readSamples44k;
429 
430  if ( sample->objectInfo.wFormatTag != lastFormat || sample != lastSample ) {
431  ClearDecoder();
432  }
433 
435 
436  if ( failed ) {
437  memset( dest, 0, sampleCount44k * sizeof( dest[0] ) );
438  return;
439  }
440 
441  // samples can be decoded both from the sound thread and the main thread for shakes
443 
444  switch( sample->objectInfo.wFormatTag ) {
445  case WAVE_FORMAT_TAG_PCM: {
446  readSamples44k = DecodePCM( sample, sampleOffset44k, sampleCount44k, dest );
447  break;
448  }
449  case WAVE_FORMAT_TAG_OGG: {
450  readSamples44k = DecodeOGG( sample, sampleOffset44k, sampleCount44k, dest );
451  break;
452  }
453  default: {
454  readSamples44k = 0;
455  break;
456  }
457  }
458 
460 
461  if ( readSamples44k < sampleCount44k ) {
462  memset( dest + readSamples44k, 0, ( sampleCount44k - readSamples44k ) * sizeof( dest[0] ) );
463  }
464 }
465 
466 /*
467 ====================
468 idSampleDecoderLocal::DecodePCM
469 ====================
470 */
471 int idSampleDecoderLocal::DecodePCM( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest ) {
472  const byte *first;
473  int pos, size, readSamples;
474 
476  lastSample = sample;
477 
478  int shift = 22050 / sample->objectInfo.nSamplesPerSec;
479  int sampleOffset = sampleOffset44k >> shift;
480  int sampleCount = sampleCount44k >> shift;
481 
482  if ( sample->nonCacheData == NULL ) {
483  assert( false ); // this should never happen ( note: I've seen that happen with the main thread down in idGameLocal::MapClear clearing entities - TTimo )
484  failed = true;
485  return 0;
486  }
487 
488  if ( !sample->FetchFromCache( sampleOffset * sizeof( short ), &first, &pos, &size, false ) ) {
489  failed = true;
490  return 0;
491  }
492 
493  if ( size - pos < sampleCount * sizeof( short ) ) {
494  readSamples = ( size - pos ) / sizeof( short );
495  } else {
496  readSamples = sampleCount;
497  }
498 
499  // duplicate samples for 44kHz output
500  SIMDProcessor->UpSamplePCMTo44kHz( dest, (const short *)(first+pos), readSamples, sample->objectInfo.nSamplesPerSec, sample->objectInfo.nChannels );
501 
502  return ( readSamples << shift );
503 }
504 
505 /*
506 ====================
507 idSampleDecoderLocal::DecodeOGG
508 ====================
509 */
510 int idSampleDecoderLocal::DecodeOGG( idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest ) {
511  int readSamples, totalSamples;
512 
513  int shift = 22050 / sample->objectInfo.nSamplesPerSec;
514  int sampleOffset = sampleOffset44k >> shift;
515  int sampleCount = sampleCount44k >> shift;
516 
517  // open OGG file if not yet opened
518  if ( lastSample == NULL ) {
519  // make sure there is enough space for another decoder
520  if ( decoderMemoryAllocator.GetFreeBlockMemory() < MIN_OGGVORBIS_MEMORY ) {
521  return 0;
522  }
523  if ( sample->nonCacheData == NULL ) {
524  assert( false ); // this should never happen
525  failed = true;
526  return 0;
527  }
528  file.SetData( (const char *)sample->nonCacheData, sample->objectMemSize );
529  if ( ov_openFile( &file, &ogg ) < 0 ) {
530  failed = true;
531  return 0;
532  }
534  lastSample = sample;
535  }
536 
537  // seek to the right offset if necessary
538  if ( sampleOffset != lastSampleOffset ) {
539  if ( ov_pcm_seek( &ogg, sampleOffset / sample->objectInfo.nChannels ) != 0 ) {
540  failed = true;
541  return 0;
542  }
543  }
544 
545  lastSampleOffset = sampleOffset;
546 
547  // decode OGG samples
548  totalSamples = sampleCount;
549  readSamples = 0;
550  do {
551  float **samples;
552  int ret = ov_read_float( &ogg, &samples, totalSamples / sample->objectInfo.nChannels, &ogg.stream );
553  if ( ret == 0 ) {
554  failed = true;
555  break;
556  }
557  if ( ret < 0 ) {
558  failed = true;
559  return 0;
560  }
561  ret *= sample->objectInfo.nChannels;
562 
563  SIMDProcessor->UpSampleOGGTo44kHz( dest + ( readSamples << shift ), samples, ret, sample->objectInfo.nSamplesPerSec, sample->objectInfo.nChannels );
564 
565  readSamples += ret;
566  totalSamples -= ret;
567  } while( totalSamples > 0 );
568 
569  lastSampleOffset += readSamples;
570 
571  return ( readSamples << shift );
572 }
void * _decoder_malloc(size_t size)
Definition: snd_decoder.cpp:58
virtual int GetLastDecodeTime(void) const
idSoundSample * lastSample
int(* close_func)(void *datasource)
Definition: vorbisfile.h:42
virtual idFile * OpenFileRead(const char *relativePath, bool allowCopyFiles=true, const char *gamedir=NULL)=0
waveformatextensible_t mpwfx
Definition: snd_local.h:198
size_t FS_ReadOGG(void *dest, size_t size1, size_t size2, void *fh)
Definition: snd_decoder.cpp:95
bool Swap_IsBigEndian(void)
Definition: Lib.cpp:563
dword mdwSize
Definition: snd_local.h:204
static idSampleDecoder * Alloc(void)
assert(prefInfo.fullscreenBtn)
int GetNumUsedBlocks(void) const
Definition: Heap.h:408
word nChannels
Definition: snd_local.h:98
void SetData(const char *data, int length)
Definition: File.cpp:868
virtual void VPCALL UpSamplePCMTo44kHz(float *dest, const short *pcm, const int numSamples, const int kHz, const int numChannels)=0
bool FetchFromCache(int offset, const byte **output, int *position, int *size, const bool allowIO)
Definition: snd_cache.cpp:689
bool isOgg
Definition: snd_local.h:215
int ov_open_callbacks(void *datasource, OggVorbis_File *vf, char *initial, long ibytes, ov_callbacks callbacks)
Definition: vorbisfile.c:729
OggVorbis_File ogg
static int GetNumUsedBlocks(void)
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
void SetFixedBlocks(int numBlocks)
Definition: Heap.h:485
int GetFreeBlockMemory(void) const
Definition: Heap.h:411
int objectMemSize
Definition: snd_local.h:848
idBlockAlloc< idSampleDecoderLocal, 64 > sampleDecoderAllocator
int ov_clear(OggVorbis_File *vf)
Definition: vorbisfile.c:692
GLuint GLuint GLsizei GLenum type
Definition: glext.h:2845
virtual int Tell(void)
Definition: File.cpp:217
size_t(* read_func)(void *ptr, size_t size, size_t nmemb, void *datasource)
Definition: vorbisfile.h:40
int DecodeOGG(idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest)
void * _decoder_realloc(void *memblock, size_t size)
Definition: snd_decoder.cpp:71
type * Alloc(const int num)
Definition: Heap.h:570
GLuint GLuint num
Definition: glext.h:5390
void Free(type *ptr)
Definition: Heap.h:631
ogg_int64_t ov_pcm_total(OggVorbis_File *vf, int i)
Definition: vorbisfile.c:909
int DecodePCM(idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest)
Definition: File.h:50
static int GetUsedBlockMemory(void)
int channels
Definition: codec.h:30
#define SEEK_END
Definition: Unzip.cpp:131
void Shutdown(void)
Definition: Heap.h:461
const int MIN_OGGVORBIS_MEMORY
Definition: snd_decoder.cpp:49
void _decoder_free(void *memblock)
Definition: snd_decoder.cpp:77
static void Shutdown(void)
type * Resize(type *ptr, const int num)
Definition: Heap.h:599
virtual void VPCALL UpSampleOGGTo44kHz(float *dest, const float *const *ogg, const int numSamples, const int kHz, const int numChannels)=0
idFile * mhmmio
Definition: snd_local.h:201
type * Alloc(void)
Definition: Heap.h:197
vorbis_info * ov_info(OggVorbis_File *vf, int link)
Definition: vorbisfile.c:1454
idCommon * common
Definition: Common.cpp:206
int OpenOGG(const char *strFileName, waveformatex_t *pwfx=NULL)
#define NULL
Definition: Lib.h:88
dword nSamplesPerSec
Definition: snd_local.h:99
void Shutdown(void)
Definition: Heap.h:224
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
virtual int Read(void *buffer, int len)
Definition: File.cpp:179
static void Free(idSampleDecoder *decoder)
int FS_SeekOGG(void *fh, ogg_int64_t to, int type)
virtual idSoundSample * GetSample(void) const
virtual void Decode(idSoundSample *sample, int sampleOffset44k, int sampleCount44k, float *dest)
#define SEEK_CUR
Definition: Unzip.cpp:130
void * ogg
Definition: snd_local.h:214
word wBitsPerSample
Definition: snd_local.h:102
int FS_CloseOGG(void *fh)
long ov_read(OggVorbis_File *vf, char *buffer, int length, int bigendianp, int word, int sgned, int *bitstream)
Definition: vorbisfile.c:1527
static void Init(void)
virtual int Seek(long offset, fsOrigin_t origin)
Definition: File.cpp:242
void Init(void)
Definition: Heap.h:456
virtual ID_TIME_T Timestamp(void)
Definition: File.cpp:208
long(* tell_func)(void *datasource)
Definition: vorbisfile.h:43
int ov_openFile(idFile *f, OggVorbis_File *vf)
dword mMemSize
Definition: snd_local.h:205
void * _decoder_calloc(size_t num, size_t size)
Definition: snd_decoder.cpp:64
int(* seek_func)(void *datasource, ogg_int64_t offset, int whence)
Definition: vorbisfile.h:41
idSoundSystemLocal soundSystemLocal
Definition: snd_system.cpp:91
#define SEEK_SET
Definition: Unzip.cpp:129
struct OggVorbis_File OggVorbis_File
waveformatex_t Format
Definition: snd_local.h:143
tuple f
Definition: idal.py:89
long rate
Definition: codec.h:31
int GetUsedBlockMemory(void) const
Definition: Heap.h:409
unsigned char byte
Definition: Lib.h:75
GLsizeiptr size
Definition: glext.h:3112
long ov_read_float(OggVorbis_File *vf, float ***pcm_channels, int samples, int *bitstream)
Definition: vorbisfile.c:1672
int CloseOGG(void)
void SetLockMemory(bool lock)
Definition: Heap.h:518
ID_TIME_T mfileTime
Definition: snd_local.h:207
void Free(type *element)
Definition: Heap.h:216
virtual void ClearDecoder(void)
GLint * first
Definition: glext.h:3036
idDynamicBlockAlloc< byte, 1<< 20, 128 > decoderMemoryAllocator
Definition: snd_decoder.cpp:47
virtual void CloseFile(idFile *f)=0
waveformatex_t objectInfo
Definition: snd_local.h:846
int64_t ogg_int64_t
Definition: os_types.h:140
idFile_Memory file
bool mbIsReadingFromMemory
Definition: snd_local.h:209
void Sys_LeaveCriticalSection(int index)
void Sys_EnterCriticalSection(int index)
byte * nonCacheData
Definition: snd_local.h:849
static idCVar s_realTimeDecoding
Definition: snd_local.h:805
int ReadOGG(byte *pBuffer, int dwSizeToRead, int *pdwSizeRead)
int ov_pcm_seek(OggVorbis_File *vf, ogg_int64_t pos)
Definition: vorbisfile.c:1265
virtual int Length(void)
Definition: File.cpp:199
long FS_TellOGG(void *fh)
fsOrigin_t
Definition: File.h:41
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
word wFormatTag
Definition: snd_local.h:97