]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/sound/snd_decoder.cpp
hello world
[icculus/iodoom3.git] / neo / sound / snd_decoder.cpp
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"
34 #include "OggVorbis/vorbis/vorbisfile.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
47 idDynamicBlockAlloc<byte, 1<<20, 128>           decoderMemoryAllocator;
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 */
145 int ov_openFile( idFile *f, OggVorbis_File *vf ) {
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
172         Sys_EnterCriticalSection( CRITICAL_SECTION_ONE );
173
174         ov = new OggVorbis_File;
175
176         if( ov_openFile( mhmmio, ov ) < 0 ) {
177                 delete ov;
178                 Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE );
179                 fileSystem->CloseFile( mhmmio );
180                 mhmmio = NULL;
181                 return -1;
182         }
183
184         mfileTime = mhmmio->Timestamp();
185
186         vorbis_info *vi = ov_info( ov, -1 );
187
188         mpwfx.Format.nSamplesPerSec = vi->rate;
189         mpwfx.Format.nChannels = vi->channels;
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 );
197                 fileSystem->CloseFile( mhmmio );
198                 mhmmio = NULL;
199                 delete ov;
200
201                 mpwfx.Format.wFormatTag = WAVE_FORMAT_TAG_OGG;
202                 mhmmio = fileSystem->OpenFileRead( strFileName );
203                 mMemSize = mhmmio->Length();
204
205         } else {
206
207                 ogg = ov;
208
209                 mpwfx.Format.wFormatTag = WAVE_FORMAT_TAG_PCM;
210                 mMemSize = mdwSize * sizeof( short );
211         }
212
213         memcpy( pwfx, &mpwfx, sizeof( waveformatex_t ) );
214
215         Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE );
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;
230         OggVorbis_File *ov = (OggVorbis_File *) ogg;
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 ) {
259         OggVorbis_File *ov = (OggVorbis_File *) ogg;
260         if ( ov != NULL ) {
261                 Sys_EnterCriticalSection( CRITICAL_SECTION_ONE );
262                 ov_clear( ov );
263                 delete ov;
264                 Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE );
265                 fileSystem->CloseFile( mhmmio );
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
282 class idSampleDecoderLocal : public idSampleDecoder {
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
304 idBlockAlloc<idSampleDecoderLocal, 64>          sampleDecoderAllocator;
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 */
322 void idSampleDecoder::Shutdown( void ) {
323         decoderMemoryAllocator.Shutdown();
324         sampleDecoderAllocator.Shutdown();
325 }
326
327 /*
328 ====================
329 idSampleDecoder::Alloc
330 ====================
331 */
332 idSampleDecoder *idSampleDecoder::Alloc( void ) {
333         idSampleDecoderLocal *decoder = sampleDecoderAllocator.Alloc();
334         decoder->Clear();
335         return decoder;
336 }
337
338 /*
339 ====================
340 idSampleDecoder::Free
341 ====================
342 */
343 void idSampleDecoder::Free( idSampleDecoder *decoder ) {
344         idSampleDecoderLocal *localDecoder = static_cast<idSampleDecoderLocal *>( decoder );
345         localDecoder->ClearDecoder();
346         sampleDecoderAllocator.Free( localDecoder );
347 }
348
349 /*
350 ====================
351 idSampleDecoder::GetNumUsedBlocks
352 ====================
353 */
354 int idSampleDecoder::GetNumUsedBlocks( void ) {
355         return decoderMemoryAllocator.GetNumUsedBlocks();
356 }
357
358 /*
359 ====================
360 idSampleDecoder::GetUsedBlockMemory
361 ====================
362 */
363 int idSampleDecoder::GetUsedBlockMemory( void ) {
364         return decoderMemoryAllocator.GetUsedBlockMemory();
365 }
366
367 /*
368 ====================
369 idSampleDecoderLocal::Clear
370 ====================
371 */
372 void idSampleDecoderLocal::Clear( void ) {
373         failed = false;
374         lastFormat = WAVE_FORMAT_TAG_PCM;
375         lastSample = NULL;
376         lastSampleOffset = 0;
377         lastDecodeTime = 0;
378 }
379
380 /*
381 ====================
382 idSampleDecoderLocal::ClearDecoder
383 ====================
384 */
385 void idSampleDecoderLocal::ClearDecoder( void ) {
386         Sys_EnterCriticalSection( CRITICAL_SECTION_ONE );
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
401         Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE );
402 }
403
404 /*
405 ====================
406 idSampleDecoderLocal::GetSample
407 ====================
408 */
409 idSoundSample *idSampleDecoderLocal::GetSample( void ) const {
410         return lastSample;
411 }
412
413 /*
414 ====================
415 idSampleDecoderLocal::GetLastDecodeTime
416 ====================
417 */
418 int idSampleDecoderLocal::GetLastDecodeTime( void ) const {
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
434         lastDecodeTime = soundSystemLocal.CurrentSoundTime;
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
442         Sys_EnterCriticalSection( CRITICAL_SECTION_ONE );
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
459         Sys_LeaveCriticalSection( CRITICAL_SECTION_ONE );
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
475         lastFormat = WAVE_FORMAT_TAG_PCM;
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                 }
533                 lastFormat = WAVE_FORMAT_TAG_OGG;
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 }