2 * $Logfile: /Freespace2/code/Sound/acm.cpp $
7 * C file for interface to Audio Compression Manager functions
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 2 10/07/98 10:53a Dave
17 * 1 10/07/98 10:51a Dave
19 * 8 6/13/98 1:45p Sandeep
21 * 7 2/18/98 5:49p Lawrance
22 * Even if the ADPCM codec is unavailable, allow game to continue.
24 * 6 11/28/97 2:09p Lawrance
25 * Overhaul how ADPCM conversion works... use much less memory... safer
28 * 5 11/22/97 11:32p Lawrance
29 * decompress ADPCM data into 8 bit (not 16bit) for regular sounds (ie not
32 * 4 9/09/97 3:39p Sandeep
33 * warning level 4 bugs
35 * 3 8/05/97 1:39p Lawrance
36 * support compressed stereo playback
38 * 2 5/29/97 12:03p Lawrance
39 * creation of file to hold AudioCompressionManager specific code
51 // variables global to file for Audio Compression Manager (ACM) conversion
52 static HACMDRIVERID ghadid = NULL;
53 static HINSTANCE ghinstAcm;
54 static HACMDRIVER ghacmdriver;
55 static int ACM_inited = 0;
57 //--------------------------------------------------------------------------;
59 // int ACM_enum_callback()
61 // This function is called by acmDriverEnum() to go through the installed
62 // audio codecs. This function will locate the Microsoft ADPCM codec and
63 // set the global value ghadid (type HACMDRIVERID), which we need when
64 // converting audio from ADPCM to PCM format.
67 // HACMDRIVERID hadid:
71 //--------------------------------------------------------------------------;
73 int CALLBACK ACM_enum_callback(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)
75 static TCHAR szBogus[] = TEXT("????");
83 hlb = (HWND)(UINT)dwInstance;
85 add.cbStruct = sizeof(add);
86 mmr = acmDriverDetails(hadid, &add, 0L);
87 if (MMSYSERR_NOERROR != mmr)
89 lstrcpy(add.szShortName, szBogus);
90 lstrcpy(add.szLongName, szBogus);
93 dwPriority = (DWORD)-1L;
94 acmMetrics((HACMOBJ)hadid, ACM_METRIC_DRIVER_PRIORITY, &dwPriority);
96 fDisabled = (0 != (ACMDRIVERDETAILS_SUPPORTF_DISABLED & fdwSupport));
99 if ( stricmp(NOX("MS-ADPCM"),add.szShortName) == 0 ) {
100 if ( fDisabled != 0 ) {
101 nprintf(("Sound", "SOUND => The Microsoft ADPCM driver is disabled, unable to convert ADPCM to PCM\n"));
107 return (FALSE); // stop enumerating devices, we've found what we need
110 // return TRUE to continue with enumeration (FALSE will stop the
116 int ACM_stream_open(WAVEFORMATEX *pwfxSrc, WAVEFORMATEX *pwfxDest, void **stream, int dest_bps)
118 Assert( pwfxSrc != NULL );
119 Assert( pwfxDest != NULL );
120 Assert( stream != NULL);
124 if ( ACM_inited == 0 ) {
130 pwfxDest->wFormatTag = WAVE_FORMAT_PCM;
131 pwfxDest->nChannels = pwfxSrc->nChannels;
132 pwfxDest->nSamplesPerSec = pwfxSrc->nSamplesPerSec;
133 pwfxDest->wBitsPerSample = (unsigned short)dest_bps;
134 pwfxDest->cbSize = 0;
135 pwfxDest->nBlockAlign = (unsigned short)(( pwfxDest->nChannels * pwfxDest->wBitsPerSample ) / 8);
136 pwfxDest->nAvgBytesPerSec = pwfxDest->nBlockAlign * pwfxDest->nSamplesPerSec;
138 rc = acmStreamOpen((HACMSTREAM*)stream, ghacmdriver, pwfxSrc, pwfxDest, NULL, 0L, 0L, ACM_STREAMOPENF_NONREALTIME);
139 if ( rc != 0 ) return -1;
144 int ACM_stream_close(void *stream)
148 rc = acmStreamClose((HACMSTREAM)stream, 0);
156 int ACM_convert(void *stream, ubyte *src, int src_len, ubyte *dest, int max_dest_bytes, unsigned int *dest_len, unsigned int *src_bytes_used)
159 ACMSTREAMHEADER hCvtHdr;
161 if ( ACM_inited == 0 ) {
167 memset(&hCvtHdr, 0, sizeof(hCvtHdr));
169 hCvtHdr.cbStruct = sizeof(hCvtHdr);
170 hCvtHdr.pbSrc = (unsigned char *)src;
171 hCvtHdr.cbSrcLength = src_len;
172 hCvtHdr.pbDst = (unsigned char*)dest;
173 hCvtHdr.cbDstLength = max_dest_bytes;
175 rc = acmStreamPrepareHeader((HACMSTREAM)stream, &hCvtHdr, 0);
176 if ( rc != 0 ) return -1;
178 rc = acmStreamConvert((HACMSTREAM)stream, &hCvtHdr, 0);
179 if ( rc != 0 ) return -1;
181 // Important step, since we need the exact length of the converted data.
182 *dest_len = hCvtHdr.cbDstLengthUsed;
183 *src_bytes_used = hCvtHdr.cbSrcLengthUsed;
185 rc = acmStreamUnprepareHeader((HACMSTREAM)stream, &hCvtHdr, 0);
192 int ACM_query_source_size(void *stream, int dest_len)
195 unsigned long src_size;
197 rc = acmStreamSize((HACMSTREAM)stream, dest_len, &src_size, ACM_STREAMSIZEF_DESTINATION);
198 return (int)src_size;
201 int ACM_query_dest_size(void *stream, int src_len)
204 unsigned long dest_size;
206 rc = acmStreamSize((HACMSTREAM)stream, src_len, &dest_size, ACM_STREAMSIZEF_SOURCE);
207 return (int)dest_size;
210 // =============================================================================
211 // ACM_convert_ADPCM_to_PCM()
213 // Convert an ADPCM wave file to a PCM wave file using the Audio Compression Manager
215 // parameters: *pwfxSrc => address of WAVEFORMATEX structure describing the source wave
216 // *src => pointer to raw source wave data
217 // src_len => num bytes of source wave data
218 // **dest => pointer to pointer to dest buffer for wave data
219 // (mem is allocated in this function if *dest is NULL)
220 // max_dest_bytes => Maximum memory allocated to dest
221 // *dest_len => returns num bytes of wave data in converted form (OUTPUT PARAMETER)
222 // *src_bytes_used => returns num bytes of src actually used in the conversion
223 // dest_bps => bits per sample that data should be uncompressed to
225 // returns: 0 => success
226 // -1 => could not convert wav file
230 // 1. Storage for the decompressed audio will be allocated in this function if *dest in NULL.
231 // The caller is responsible for freeing this memory later.
233 int ACM_convert_ADPCM_to_PCM(WAVEFORMATEX *pwfxSrc, ubyte *src, int src_len, ubyte **dest, int max_dest_bytes, int *dest_len, unsigned int *src_bytes_used, unsigned short dest_bps)
235 Assert( pwfxSrc != NULL );
236 Assert( pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM );
237 Assert( src != NULL );
238 Assert( src_len > 0 );
239 Assert( dest_len != NULL );
241 WAVEFORMATEX wfxDest;
243 ACMSTREAMHEADER hCvtHdr;
246 if ( ACM_inited == 0 ) {
252 wfxDest.wFormatTag = WAVE_FORMAT_PCM;
253 wfxDest.nChannels = pwfxSrc->nChannels;
254 wfxDest.nSamplesPerSec = pwfxSrc->nSamplesPerSec;
255 wfxDest.wBitsPerSample = dest_bps;
257 wfxDest.nBlockAlign = (unsigned short)(( wfxDest.nChannels * wfxDest.wBitsPerSample ) / 8);
258 wfxDest.nAvgBytesPerSec = wfxDest.nBlockAlign * wfxDest.nSamplesPerSec;
260 rc = acmStreamOpen(&hStream, ghacmdriver, pwfxSrc, &wfxDest, NULL, 0L, 0L, ACM_STREAMOPENF_NONREALTIME);
261 if ( rc != 0 ) return -1;
263 rc = acmStreamSize(hStream, src_len, (unsigned long *)dest_len, ACM_STREAMSIZEF_SOURCE);
264 if ( rc != 0 ) return -1;
266 if ( *dest == NULL ) {
267 *dest = (ubyte*)malloc(*dest_len);
268 Assert( *dest != NULL );
271 if ( !max_dest_bytes ) {
272 max_dest_bytes = *dest_len;
275 memset(&hCvtHdr, 0, sizeof(hCvtHdr));
277 hCvtHdr.cbStruct = sizeof(hCvtHdr);
278 hCvtHdr.pbSrc = (unsigned char *)src;
279 hCvtHdr.cbSrcLength = src_len;
280 hCvtHdr.pbDst = (unsigned char *)*dest;
281 hCvtHdr.cbDstLength = max_dest_bytes;
283 rc = acmStreamPrepareHeader(hStream, &hCvtHdr, 0);
284 if ( rc != 0 ) return -1;
286 rc = acmStreamConvert(hStream, &hCvtHdr, 0);
287 if ( rc != 0 ) return -1;
289 // Important step, since we need the exact length of the converted data.
290 *dest_len = hCvtHdr.cbDstLengthUsed;
291 *src_bytes_used = hCvtHdr.cbSrcLengthUsed;
293 rc = acmStreamUnprepareHeader(hStream, &hCvtHdr, 0);
294 if ( rc != 0 ) return -1;
296 rc = acmStreamClose(hStream, 0);
297 if ( rc != 0 ) return -1;
302 // =============================================================================
305 // Initializes the Audio Compression Manager components used to convert ADPCM to PCM
307 // returns: 0 => success
308 // -1 => ACM could not be initialized
314 if ( ACM_inited == 1 )
317 ghinstAcm = LoadLibrary(NOX("msacm32.dll"));
318 if (ghinstAcm == NULL) {
321 FreeLibrary(ghinstAcm);
324 dwVersion = acmGetVersion();
325 nprintf(("Sound", "ACM Version number: %u.%.02u\n", HIWORD(dwVersion) >> 8, HIWORD(dwVersion) & 0x00FF));
326 // ACM must be version 3.5 or higher
327 if ( dwVersion < 0x03320000 ) {
331 rc = acmDriverEnum(ACM_enum_callback, 0L, ACM_DRIVERENUMF_DISABLED);
332 if ( rc != MMSYSERR_NOERROR ) return -1;
334 if ( ghadid == NULL ) {
335 nprintf(("Sound", "SOUND => Unable to locate the Microsoft ADPCM driver\n"));
339 rc = acmDriverOpen(&ghacmdriver, ghadid, 0L);
340 if ( rc != MMSYSERR_NOERROR ) return -1;
342 rc = acmDriverPriority(ghadid,0,0);
343 if ( rc != MMSYSERR_NOERROR ) return -1;
349 // Closes down the Audio Compression Manager components
352 if ( ACM_inited == 0 )
355 acmDriverClose( ghacmdriver, 0L);
359 // Query if the ACM system is initialized