doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
snd_wavefile.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 
34 //-----------------------------------------------------------------------------
35 // Name: idWaveFile::idWaveFile()
36 // Desc: Constructs the class. Call Open() to open a wave file for reading.
37 // Then call Read() as needed. Calling the destructor or Close()
38 // will close the file.
39 //-----------------------------------------------------------------------------
41  memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
42  mhmmio = NULL;
43  mdwSize = 0;
44  mseekBase = 0;
45  mbIsReadingFromMemory = false;
46  mpbData = NULL;
47  ogg = NULL;
48  isOgg = false;
49 }
50 
51 //-----------------------------------------------------------------------------
52 // Name: idWaveFile::~idWaveFile()
53 // Desc: Destructs the class
54 //-----------------------------------------------------------------------------
56  Close();
57 
58  if ( mbIsReadingFromMemory && mpbData ) {
59  Mem_Free( mpbData );
60  }
61 
62  memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
63 }
64 
65 //-----------------------------------------------------------------------------
66 // Name: idWaveFile::Open()
67 // Desc: Opens a wave file for reading
68 //-----------------------------------------------------------------------------
69 int idWaveFile::Open( const char* strFileName, waveformatex_t* pwfx ) {
70 
71  mbIsReadingFromMemory = false;
72 
73  mpbData = NULL;
75 
76  if( strFileName == NULL ) {
77  return -1;
78  }
79 
80  idStr name = strFileName;
81 
82  // note: used to only check for .wav when making a build
83  name.SetFileExtension( ".ogg" );
84  if ( fileSystem->ReadFile( name, NULL, NULL ) != -1 ) {
85  return OpenOGG( name, pwfx );
86  }
87 
88  memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
89 
90  mhmmio = fileSystem->OpenFileRead( strFileName );
91  if ( !mhmmio ) {
92  mdwSize = 0;
93  return -1;
94  }
95  if ( mhmmio->Length() <= 0 ) {
96  mhmmio = NULL;
97  return -1;
98  }
99  if ( ReadMMIO() != 0 ) {
100  // ReadMMIO will fail if its an not a wave file
101  Close();
102  return -1;
103  }
104 
106 
107  if ( ResetFile() != 0 ) {
108  Close();
109  return -1;
110  }
111 
112  // After the reset, the size of the wav file is mck.cksize so store it now
113  mdwSize = mck.cksize / sizeof( short );
114  mMemSize = mck.cksize;
115 
116  if ( mck.cksize != 0xffffffff ) {
117  if ( pwfx ) {
118  memcpy( pwfx, (waveformatex_t *)&mpwfx, sizeof(waveformatex_t));
119  }
120  return 0;
121  }
122  return -1;
123 }
124 
125 //-----------------------------------------------------------------------------
126 // Name: idWaveFile::OpenFromMemory()
127 // Desc: copy data to idWaveFile member variable from memory
128 //-----------------------------------------------------------------------------
129 int idWaveFile::OpenFromMemory( short* pbData, int ulDataSize, waveformatextensible_t* pwfx ) {
130  mpwfx = *pwfx;
131  mulDataSize = ulDataSize;
132  mpbData = pbData;
134  mdwSize = ulDataSize / sizeof( short );
135  mMemSize = ulDataSize;
136  mbIsReadingFromMemory = true;
137 
138  return 0;
139 }
140 
141 //-----------------------------------------------------------------------------
142 // Name: idWaveFile::ReadMMIO()
143 // Desc: Support function for reading from a multimedia I/O stream.
144 // mhmmio must be valid before calling. This function uses it to
145 // update mckRiff, and mpwfx.
146 //-----------------------------------------------------------------------------
147 int idWaveFile::ReadMMIO( void ) {
148  mminfo_t ckIn; // chunk info. for general use.
149  pcmwaveformat_t pcmWaveFormat; // Temp PCM structure to load in.
150 
151  memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
152 
153  mhmmio->Read( &mckRiff, 12 );
154  assert( !isOgg );
158  mckRiff.dwDataOffset = 12;
159 
160  // Check to make sure this is a valid wave file
161  if( (mckRiff.ckid != fourcc_riff) || (mckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) ) {
162  return -1;
163  }
164 
165  // Search the input file for for the 'fmt ' chunk.
166  ckIn.dwDataOffset = 12;
167  do {
168  if (8 != mhmmio->Read( &ckIn, 8 ) ) {
169  return -1;
170  }
171  assert( !isOgg );
172  ckIn.ckid = LittleLong( ckIn.ckid );
173  ckIn.cksize = LittleLong( ckIn.cksize );
174  ckIn.dwDataOffset += ckIn.cksize-8;
175  } while (ckIn.ckid != mmioFOURCC('f', 'm', 't', ' '));
176 
177  // Expect the 'fmt' chunk to be at least as large as <PCMWAVEFORMAT>;
178  // if there are extra parameters at the end, we'll ignore them
179  if( ckIn.cksize < sizeof(pcmwaveformat_t) ) {
180  return -1;
181  }
182 
183  // Read the 'fmt ' chunk into <pcmWaveFormat>.
184  if( mhmmio->Read( &pcmWaveFormat, sizeof(pcmWaveFormat) ) != sizeof(pcmWaveFormat) ) {
185  return -1;
186  }
187  assert( !isOgg );
188  pcmWaveFormat.wf.wFormatTag = LittleShort( pcmWaveFormat.wf.wFormatTag );
189  pcmWaveFormat.wf.nChannels = LittleShort( pcmWaveFormat.wf.nChannels );
190  pcmWaveFormat.wf.nSamplesPerSec = LittleLong( pcmWaveFormat.wf.nSamplesPerSec );
191  pcmWaveFormat.wf.nAvgBytesPerSec = LittleLong( pcmWaveFormat.wf.nAvgBytesPerSec );
192  pcmWaveFormat.wf.nBlockAlign = LittleShort( pcmWaveFormat.wf.nBlockAlign );
193  pcmWaveFormat.wBitsPerSample = LittleShort( pcmWaveFormat.wBitsPerSample );
194 
195  // Copy the bytes from the pcm structure to the waveformatex_t structure
196  memcpy( &mpwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
197 
198  // Allocate the waveformatex_t, but if its not pcm format, read the next
199  // word, and thats how many extra bytes to allocate.
200  if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_TAG_PCM ) {
201  mpwfx.Format.cbSize = 0;
202  } else {
203  return -1; // we don't handle these (32 bit wavefiles, etc)
204 #if 0
205  // Read in length of extra bytes.
206  word cbExtraBytes = 0L;
207  if( mhmmio->Read( (char*)&cbExtraBytes, sizeof(word) ) != sizeof(word) )
208  return -1;
209 
210  mpwfx.Format.cbSize = cbExtraBytes;
211 
212  // Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
213  if( mhmmio->Read( (char*)(((byte*)&(mpwfx.Format.cbSize))+sizeof(word)), cbExtraBytes ) != cbExtraBytes ) {
214  memset( &mpwfx, 0, sizeof( waveformatextensible_t ) );
215  return -1;
216  }
217 #endif
218  }
219 
220  return 0;
221 }
222 
223 //-----------------------------------------------------------------------------
224 // Name: idWaveFile::ResetFile()
225 // Desc: Resets the internal mck pointer so reading starts from the
226 // beginning of the file again
227 //-----------------------------------------------------------------------------
229  if( mbIsReadingFromMemory ) {
231  } else {
232  if( mhmmio == NULL ) {
233  return -1;
234  }
235 
236  // Seek to the data
237  if( -1 == mhmmio->Seek( mckRiff.dwDataOffset + sizeof(fourcc), FS_SEEK_SET ) ) {
238  return -1;
239  }
240 
241  // Search the input file for for the 'fmt ' chunk.
242  mck.ckid = 0;
243  do {
244  byte ioin;
245  if ( !mhmmio->Read( &ioin, 1 ) ) {
246  return -1;
247  }
248  mck.ckid = (mck.ckid>>8) | (ioin<<24);
249  } while (mck.ckid != mmioFOURCC('d', 'a', 't', 'a'));
250 
251  mhmmio->Read( &mck.cksize, 4 );
252  assert( !isOgg );
254  mseekBase = mhmmio->Tell();
255  }
256 
257  return 0;
258 }
259 
260 //-----------------------------------------------------------------------------
261 // Name: idWaveFile::Read()
262 // Desc: Reads section of data from a wave file into pBuffer and returns
263 // how much read in pdwSizeRead, reading not more than dwSizeToRead.
264 // This uses mck to determine where to start reading from. So
265 // subsequent calls will be continue where the last left off unless
266 // Reset() is called.
267 //-----------------------------------------------------------------------------
268 int idWaveFile::Read( byte* pBuffer, int dwSizeToRead, int *pdwSizeRead ) {
269 
270  if ( ogg != NULL ) {
271 
272  return ReadOGG( pBuffer, dwSizeToRead, pdwSizeRead );
273 
274  } else if ( mbIsReadingFromMemory ) {
275 
276  if( mpbDataCur == NULL ) {
277  return -1;
278  }
279  if( (byte*)(mpbDataCur + dwSizeToRead) > (byte*)(mpbData + mulDataSize) ) {
280  dwSizeToRead = mulDataSize - (int)(mpbDataCur - mpbData);
281  }
282  SIMDProcessor->Memcpy( pBuffer, mpbDataCur, dwSizeToRead );
283  mpbDataCur += dwSizeToRead;
284 
285  if ( pdwSizeRead != NULL ) {
286  *pdwSizeRead = dwSizeToRead;
287  }
288 
289  return dwSizeToRead;
290 
291  } else {
292 
293  if( mhmmio == NULL ) {
294  return -1;
295  }
296  if( pBuffer == NULL ) {
297  return -1;
298  }
299 
300  dwSizeToRead = mhmmio->Read( pBuffer, dwSizeToRead );
301  // this is hit by ogg code, which does it's own byte swapping internally
302  if ( !isOgg ) {
303  LittleRevBytes( pBuffer, 2, dwSizeToRead / 2 );
304  }
305 
306  if ( pdwSizeRead != NULL ) {
307  *pdwSizeRead = dwSizeToRead;
308  }
309 
310  return dwSizeToRead;
311  }
312 }
313 
314 //-----------------------------------------------------------------------------
315 // Name: idWaveFile::Close()
316 // Desc: Closes the wave file
317 //-----------------------------------------------------------------------------
318 int idWaveFile::Close( void ) {
319  if ( ogg != NULL ) {
320  return CloseOGG();
321  }
322  if( mhmmio != NULL ) {
324  mhmmio = NULL;
325  }
326  return 0;
327 }
328 
329 //-----------------------------------------------------------------------------
330 // Name: idWaveFile::Seek()
331 //-----------------------------------------------------------------------------
333 
334  if ( ogg != NULL ) {
335 
336  common->FatalError( "idWaveFile::Seek: cannot seek on an OGG file\n" );
337 
338  } else if( mbIsReadingFromMemory ) {
339 
341 
342  } else {
343  if( mhmmio == NULL ) {
344  return -1;
345  }
346 
347  if ((int)(offset+mseekBase) == mhmmio->Tell()) {
348  return 0;
349  }
350  mhmmio->Seek( offset + mseekBase, FS_SEEK_SET );
351  return 0;
352  }
353  return -1;
354 }
dword nAvgBytesPerSec
Definition: snd_local.h:114
#define mmioFOURCC(ch0, ch1, ch2, ch3)
Definition: snd_local.h:135
virtual idFile * OpenFileRead(const char *relativePath, bool allowCopyFiles=true, const char *gamedir=NULL)=0
waveformatextensible_t mpwfx
Definition: snd_local.h:198
dword mdwSize
Definition: snd_local.h:204
idStr & SetFileExtension(const char *extension)
Definition: Str.cpp:743
assert(prefInfo.fullscreenBtn)
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
bool isOgg
Definition: snd_local.h:215
case const int
Definition: Callbacks.cpp:52
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
dword mseekBase
Definition: snd_local.h:206
fourcc ckid
Definition: snd_local.h:160
int Seek(int offset)
virtual int Tell(void)
Definition: File.cpp:217
#define fourcc_riff
Definition: snd_local.h:140
int ReadMMIO(void)
mminfo_t mck
Definition: snd_local.h:202
GLintptr offset
Definition: glext.h:3113
int Open(const char *strFileName, waveformatex_t *pwfx=NULL)
short * mpbDataCur
Definition: snd_local.h:211
int OpenFromMemory(short *pbData, int ulDataSize, waveformatextensible_t *pwfx)
idFile * mhmmio
Definition: snd_local.h:201
idCommon * common
Definition: Common.cpp:206
word wFormatTag
Definition: snd_local.h:111
waveformat_t wf
Definition: snd_local.h:128
int OpenOGG(const char *strFileName, waveformatex_t *pwfx=NULL)
#define NULL
Definition: Lib.h:88
void LittleRevBytes(void *bp, int elsize, int elcount)
Definition: Lib.cpp:285
int Close(void)
short * mpbData
Definition: snd_local.h:210
word nBlockAlign
Definition: snd_local.h:115
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
Definition: eax4.h:1413
virtual int Read(void *buffer, int len)
Definition: File.cpp:179
idWaveFile(void)
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
int Read(byte *pBuffer, int dwSizeToRead, int *pdwSizeRead)
~idWaveFile(void)
void * ogg
Definition: snd_local.h:214
int LittleLong(int l)
Definition: Lib.cpp:281
virtual int Seek(long offset, fsOrigin_t origin)
Definition: File.cpp:242
virtual ID_TIME_T Timestamp(void)
Definition: File.cpp:208
mminfo_t mckRiff
Definition: snd_local.h:203
virtual void VPCALL Memcpy(void *dst, const void *src, const int count)=0
dword mMemSize
Definition: snd_local.h:205
fourcc fccType
Definition: snd_local.h:162
short LittleShort(short l)
Definition: Lib.cpp:279
word wBitsPerSample
Definition: snd_local.h:129
dword fourcc
Definition: snd_local.h:156
waveformatex_t Format
Definition: snd_local.h:143
unsigned short word
Definition: Lib.h:76
dword cksize
Definition: snd_local.h:161
unsigned char byte
Definition: Lib.h:75
const GLcharARB * name
Definition: glext.h:3629
Definition: Str.h:116
dword dwDataOffset
Definition: snd_local.h:163
int CloseOGG(void)
ID_TIME_T mfileTime
Definition: snd_local.h:207
int ResetFile(void)
virtual void CloseFile(idFile *f)=0
dword nSamplesPerSec
Definition: snd_local.h:113
bool mbIsReadingFromMemory
Definition: snd_local.h:209
int ReadOGG(byte *pBuffer, int dwSizeToRead, int *pdwSizeRead)
virtual int Length(void)
Definition: File.cpp:199
word nChannels
Definition: snd_local.h:112
dword mulDataSize
Definition: snd_local.h:212
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43