1 ////////////////////////////////////////////////////////////////////////
2 // $Source: x:/prj/tech/libsrc/sound/RCS/sndfmt.cpp $
4 // $Date: 1998/03/20 12:55:54 $
7 // (c) 1996 Looking Glass Technologies Inc.
8 // Pat McElhatton (from JohnB)
10 // Module name: sound formats
11 // File name: sndfmt.cpp
13 // Description: Implementation of sound file/resource format handling
15 ////////////////////////////////////////////////////////////////////////
42 int nBytes
, bytesPerSamp
;
44 uint32 maxSamples
, nBlocks
, partialBlockLen
;
46 // get the next riff chunk
47 if(mmioDescend(hmmio
,&riff
, NULL
, 0))
50 // make sure its a wave file
51 if((riff
.ckid
!= FOURCC_RIFF
) || (riff
.fccType
!= mmioFOURCC('W','A','V','E')))
54 /*----------------------------
55 * process format chunk
56 *---------------------------*/
57 // get the format chunk
58 chunk
.ckid
= mmioFOURCC('f', 'm', 't', ' ');
59 if (mmioDescend(hmmio
, &chunk
, &riff
, MMIO_FINDCHUNK
))
62 // make sure the chunk is the right size, otherwise we dont know what
63 // kind of wave file it is
64 if(chunk
.cksize
< (long)sizeof(PCMWAVEFORMAT
))
67 // now grab the format
68 nBytes
= mmioRead(hmmio
, (HPSTR
) &waveFmt
, (long) sizeof(waveFmt
));
69 if ( waveFmt
.wFormatTag
== WAVE_FORMAT_DVI_ADPCM
) {
70 if ( nBytes
!= sizeof(waveFmt
) )
72 if ( waveFmt
.cbSize
< sizeof(sampsPerBlock
) )
74 nBytes
= mmioRead(hmmio
, (HPSTR
) &sampsPerBlock
, (long) sizeof(sampsPerBlock
));
75 pAttribs
->samplesPerBlock
= sampsPerBlock
;
78 // get back out of the format chunk
79 if(mmioAscend(hmmio
, &chunk
, 0))
82 /*----------------------------------------
83 * process fact chunk, or calc #samples
84 *---------------------------------------*/
85 // for ADPCM, get the fact chunk, which holds the number of samples
86 if ( waveFmt
.wFormatTag
== WAVE_FORMAT_DVI_ADPCM
) {
87 // get the format chunk
88 chunk
.ckid
= mmioFOURCC('f', 'a', 'c', 't');
89 // go back to beginning of riff file to handle out of order chunks
90 mmioSeek(hmmio
, riff
.dwDataOffset
+ 4, SEEK_SET
);
91 if (mmioDescend(hmmio
, &chunk
, &riff
, MMIO_FINDCHUNK
))
93 if(chunk
.cksize
< sizeof(uint32
) )
95 nBytes
= mmioRead(hmmio
, (HPSTR
) pNSamples
, sizeof(long) );
96 if(mmioAscend(hmmio
, &chunk
, 0))
98 pAttribs
->dataType
= kSndDataIMAADPCM
;
101 /*----------------------------
103 *---------------------------*/
104 // Find the data subchunk. The current file position should be at
105 // the beginning of the data chunk; however, you should not make
106 // this assumption. Use mmioDescend to locate the data chunk.
107 // go back to beginning of riff file to handle out of order chunks
108 mmioSeek(hmmio
, riff
.dwDataOffset
+ 4, SEEK_SET
);
109 chunk
.ckid
= mmioFOURCC('d', 'a', 't', 'a');
110 if (mmioDescend(hmmio
, &chunk
, &riff
, MMIO_FINDCHUNK
))
113 if (chunk
.cksize
== 0L)
116 // now we look to see where we are
117 if(mmioGetInfo(hmmio
, pMmio
, 0))
120 *ppPCMData
= (uint8
*)pMmio
->pchNext
;
121 *pPCMLen
= chunk
.cksize
;
122 pAttribs
->sampleRate
= waveFmt
.nSamplesPerSec
;
123 pAttribs
->bitsPerSample
= waveFmt
.wBitsPerSample
;
124 pAttribs
->nChannels
= waveFmt
.nChannels
;
125 pAttribs
->bytesPerBlock
= waveFmt
.nBlockAlign
;
127 switch( waveFmt
.wFormatTag
) {
129 case WAVE_FORMAT_PCM
:
130 bytesPerSamp
= ((pAttribs
->nChannels
* pAttribs
->bitsPerSample
) / 8);
131 pAttribs
->dataType
= kSndDataPCM
;
132 // for PCM data types, calculate the #sample from #bytes
133 *pNSamples
= chunk
.cksize
/ bytesPerSamp
;
134 pAttribs
->samplesPerBlock
= pAttribs
->bytesPerBlock
/ bytesPerSamp
;
137 case WAVE_FORMAT_DVI_ADPCM
:
138 // the nSamples field in the fact chunk is often (usually!) wrong
139 // so if nSamples is larger than the max # of samples in the data
140 // chunk, limit nSamples to that
141 nBlocks
= *pPCMLen
/ pAttribs
->bytesPerBlock
;
142 partialBlockLen
= *pPCMLen
% pAttribs
->bytesPerBlock
;
143 maxSamples
= nBlocks
* pAttribs
->samplesPerBlock
;
144 if ( partialBlockLen
>= 4 ) {
145 // there is a partial block, account for any samples in it
146 // the block has a 4 byte header with 1 sample in it, and
147 // 2 samples in each byte after the header
148 maxSamples
+= ( 1 + (2 * (partialBlockLen
- 4)) );
150 if ( *pNSamples
> maxSamples
) {
151 *pNSamples
= maxSamples
;
156 // we don't handle other formats
160 pAttribs
->numSamples
= *pNSamples
;
166 // extract useful info from RIFF WAVE file image header
167 // return TRUE if an error occurs
176 sSndAttribs
*pAttribs
)
182 // set up to read from a memory file. This is becuase
183 // we have the whole file in memory at this point...
184 memset(&mmio
, 0, sizeof(MMIOINFO
));
187 mmio
.fccIOProc
= FOURCC_MEM
;
188 mmio
.pchBuffer
= (char *) pRezData
;
189 mmio
.cchBuffer
= rezLen
;
191 hmmio
= mmioOpen(NULL
, &mmio
, MMIO_READWRITE
);
195 // and point to all that good sound data
196 bad
= openWaveHeader( hmmio
, &mmio
, ppData
, pDataLen
,
197 pNumSamples
, pAttribs
);
204 // extract useful info from VOC file image header
205 // return TRUE if an error occurs
214 sSndAttribs
*pAttribs
)
217 uint8
*pVoc
= (uint8
*) pRezData
;
218 uint8
*pEndRez
= pVoc
+ rezLen
;
219 BOOL voiceBlockFound
= FALSE
;
224 sVocHeader
*hdr
= (sVocHeader
*) pVoc
;
226 sVocDataBlock
*dataBlock
;
227 // voc_continue_block *contBlock;
228 sVocStereoBlock
*stereoBlock
;
229 sVocExtendedBlock
*extendedBlock
;
231 pVoc
+= hdr
->offData
; // fast forward to data
233 while ( !voiceBlockFound
) {
234 if ( pVoc
>= pEndRez
) {
235 // got to the end of VOC without finding a data block
239 blockType
= *pVoc
; // just read the id off the top.
246 dataBlock
= (sVocDataBlock
*)pVoc
;
250 sampleRate
= 1000000L / (256 - dataBlock
->timeConstant
);
252 *ppData
= pVoc
+ sizeof(sVocDataBlock
);
253 *pDataLen
= VOC_BLOCK_LEN(pVoc
) - 2;
254 voiceBlockFound
= TRUE
;
256 case VOC_BLOCK_STEREO
:
257 stereoBlock
= (sVocStereoBlock
*)pVoc
;
258 if(stereoBlock
->voiceMode
)
263 128000000L / (65536L - stereoBlock
->timeConstant
);
270 256000000L / (65536L - stereoBlock
->timeConstant
);
272 pVoc
+= VOC_BLOCK_LEN(pVoc
) + 4; // go to the end of the block
274 *ppData
= pVoc
+ sizeof(sVocDataBlock
);
275 *pDataLen
= VOC_BLOCK_LEN(pVoc
) - 2;
276 voiceBlockFound
= TRUE
;
279 case VOC_BLOCK_EXTENDED
:
280 extendedBlock
= (sVocExtendedBlock
*)pVoc
;
281 *ppData
= pVoc
+ sizeof(sVocExtendedBlock
);
282 *pDataLen
= VOC_BLOCK_LEN(pVoc
) - 12;
283 sampleRate
= extendedBlock
->sampleRate
;
284 channels
= extendedBlock
->channels
;
286 if(extendedBlock
->format
== 0)
288 else if(extendedBlock
->format
== 4)
290 voiceBlockFound
= TRUE
;
293 pVoc
+= VOC_BLOCK_LEN(pVoc
) + 4;
296 } // end while !voiceBlockFound
298 if ( voiceBlockFound
== TRUE
) {
299 // fill in sound attributes & samples-in-resource
300 pAttribs
->nChannels
= channels
;
301 pAttribs
->bitsPerSample
= bits
;
302 pAttribs
->sampleRate
= sampleRate
;
303 pAttribs
->bytesPerBlock
= channels
* (bits
/ 8);
304 pAttribs
->dataType
= kSndDataPCM
;
305 pAttribs
->samplesPerBlock
= 1;
306 *pNumSamples
= *pDataLen
/ pAttribs
->bytesPerBlock
;
308 return !voiceBlockFound
;
312 // get header info from sound resource (mem-resident sound file image)
313 // return TRUE if failure occurs
322 sSndAttribs
*pAttribs
)
324 char *buf
= (char *) pRezData
;
327 // determine the file image type (WAVE or VOC)
328 // extract sound attribs from rez header
329 // find start of audio data
330 if ( (strncmp( buf
, "RIFF", 4) == 0 )
331 && (strncmp( buf
+ 8, "WAVE", 4) == 0) ) {
332 // sound resource is a wave file image
333 bad
= SndCrackWaveHeader( pRezData
, rezLen
, ppData
, pDataLen
,
334 pNumSamples
, pAttribs
);
335 if ( bad
) mprintf( "SndCrackWaveHeader returned error\n");
336 TLOG3("SndCrackWaveHeader %ld bytes, %ld samples %d badFlag",
337 rezLen
, *pNumSamples
, bad
);
338 } else if ( strncmp( buf
, "Creative Voice File", 19 ) == 0 ) {
339 // sound resource is a voc file image
341 bad
= SndCrackVocHeader( pRezData
, rezLen
, ppData
, pDataLen
,
342 pNumSamples
, pAttribs
);
343 if ( bad
) mprintf( "SndCrackVocHeader returned error\n");
344 TLOG3("SndCrackVocHeader %ld bytes, %ld samples %d badFlag",
345 rezLen
, *pNumSamples
, bad
);
347 // Error - Rez is not a recognized sound file image type
348 mprintf("Unrecognizable sound file type\n");