mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 12:41:35 -10:00
I've tested this through compiling and through hand checking. Normalises line endings in ALL files to \n.
336 lines
9.0 KiB
C++
336 lines
9.0 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#ifndef USE_OPENAL // to end of file...
|
|
|
|
#include "globalincs/pstypes.h"
|
|
#include <windows.h>
|
|
#include "sound/acm.h"
|
|
|
|
|
|
|
|
|
|
// variables global to file for Audio Compression Manager (ACM) conversion
|
|
static HACMDRIVERID ghadid = NULL;
|
|
static HINSTANCE ghinstAcm;
|
|
static HACMDRIVER ghacmdriver;
|
|
static int ACM_inited = 0;
|
|
|
|
//--------------------------------------------------------------------------;
|
|
//
|
|
// int ACM_enum_callback()
|
|
//
|
|
// This function is called by acmDriverEnum() to go through the installed
|
|
// audio codecs. This function will locate the Microsoft ADPCM codec and
|
|
// set the global value ghadid (type HACMDRIVERID), which we need when
|
|
// converting audio from ADPCM to PCM format.
|
|
//
|
|
// Arguments:
|
|
// HACMDRIVERID hadid:
|
|
// DWORD dwInstance:
|
|
// DWORD fdwSupport:
|
|
//
|
|
//--------------------------------------------------------------------------;
|
|
|
|
int CALLBACK ACM_enum_callback(HACMDRIVERID hadid, DWORD dwInstance, DWORD fdwSupport)
|
|
{
|
|
static TCHAR szBogus[] = TEXT("????");
|
|
|
|
MMRESULT mmr;
|
|
HWND hlb;
|
|
ACMDRIVERDETAILS add;
|
|
BOOL fDisabled;
|
|
DWORD dwPriority;
|
|
|
|
hlb = (HWND)(UINT)dwInstance;
|
|
|
|
add.cbStruct = sizeof(add);
|
|
mmr = acmDriverDetails(hadid, &add, 0L);
|
|
if (MMSYSERR_NOERROR != mmr)
|
|
{
|
|
lstrcpy(add.szShortName, szBogus);
|
|
lstrcpy(add.szLongName, szBogus);
|
|
}
|
|
|
|
dwPriority = (DWORD)-1L;
|
|
acmMetrics((HACMOBJ)hadid, ACM_METRIC_DRIVER_PRIORITY, &dwPriority);
|
|
|
|
fDisabled = (0 != (ACMDRIVERDETAILS_SUPPORTF_DISABLED & fdwSupport));
|
|
|
|
|
|
if ( stricmp(NOX("MS-ADPCM"),add.szShortName) == 0 ) {
|
|
if ( fDisabled != 0 ) {
|
|
nprintf(("Sound", "SOUND => The Microsoft ADPCM driver is disabled, unable to convert ADPCM to PCM\n"));
|
|
ghadid = NULL;
|
|
}
|
|
else {
|
|
ghadid = hadid;
|
|
}
|
|
return (FALSE); // stop enumerating devices, we've found what we need
|
|
}
|
|
//
|
|
// return TRUE to continue with enumeration (FALSE will stop the
|
|
// enumerator)
|
|
//
|
|
return (TRUE);
|
|
}
|
|
|
|
int ACM_stream_open(WAVEFORMATEX *pwfxSrc, WAVEFORMATEX *pwfxDest, void **stream, int dest_bps)
|
|
{
|
|
Assert( pwfxSrc != NULL );
|
|
Assert( pwfxDest != NULL );
|
|
Assert( stream != NULL);
|
|
|
|
int rc;
|
|
|
|
if ( ACM_inited == 0 ) {
|
|
rc = ACM_init();
|
|
if ( rc != 0 )
|
|
return -1;
|
|
}
|
|
|
|
pwfxDest->wFormatTag = WAVE_FORMAT_PCM;
|
|
pwfxDest->nChannels = pwfxSrc->nChannels;
|
|
pwfxDest->nSamplesPerSec = pwfxSrc->nSamplesPerSec;
|
|
pwfxDest->wBitsPerSample = (unsigned short)dest_bps;
|
|
pwfxDest->cbSize = 0;
|
|
pwfxDest->nBlockAlign = (unsigned short)(( pwfxDest->nChannels * pwfxDest->wBitsPerSample ) / 8);
|
|
pwfxDest->nAvgBytesPerSec = pwfxDest->nBlockAlign * pwfxDest->nSamplesPerSec;
|
|
|
|
rc = acmStreamOpen((HACMSTREAM*)stream, ghacmdriver, pwfxSrc, pwfxDest, NULL, 0L, 0L, ACM_STREAMOPENF_NONREALTIME);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int ACM_stream_close(void *stream)
|
|
{
|
|
int rc;
|
|
|
|
rc = acmStreamClose((HACMSTREAM)stream, 0);
|
|
if ( rc != 0 )
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
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)
|
|
{
|
|
int rc;
|
|
ACMSTREAMHEADER hCvtHdr;
|
|
|
|
if ( ACM_inited == 0 ) {
|
|
rc = ACM_init();
|
|
if ( rc != 0 )
|
|
return -1;
|
|
}
|
|
|
|
memset(&hCvtHdr, 0, sizeof(hCvtHdr));
|
|
|
|
hCvtHdr.cbStruct = sizeof(hCvtHdr);
|
|
hCvtHdr.pbSrc = (unsigned char *)src;
|
|
hCvtHdr.cbSrcLength = src_len;
|
|
hCvtHdr.pbDst = (unsigned char*)dest;
|
|
hCvtHdr.cbDstLength = max_dest_bytes;
|
|
|
|
rc = acmStreamPrepareHeader((HACMSTREAM)stream, &hCvtHdr, 0);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
rc = acmStreamConvert((HACMSTREAM)stream, &hCvtHdr, 0);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
// Important step, since we need the exact length of the converted data.
|
|
*dest_len = hCvtHdr.cbDstLengthUsed;
|
|
*src_bytes_used = hCvtHdr.cbSrcLengthUsed;
|
|
|
|
rc = acmStreamUnprepareHeader((HACMSTREAM)stream, &hCvtHdr, 0);
|
|
if ( rc != 0 )
|
|
return -1;
|
|
|
|
return rc;
|
|
}
|
|
|
|
int ACM_query_source_size(void *stream, int dest_len)
|
|
{
|
|
int rc;
|
|
unsigned long src_size;
|
|
|
|
rc = acmStreamSize((HACMSTREAM)stream, dest_len, &src_size, ACM_STREAMSIZEF_DESTINATION);
|
|
return (int)src_size;
|
|
}
|
|
|
|
int ACM_query_dest_size(void *stream, int src_len)
|
|
{
|
|
int rc;
|
|
unsigned long dest_size;
|
|
|
|
rc = acmStreamSize((HACMSTREAM)stream, src_len, &dest_size, ACM_STREAMSIZEF_SOURCE);
|
|
return (int)dest_size;
|
|
}
|
|
|
|
// =============================================================================
|
|
// ACM_convert_ADPCM_to_PCM()
|
|
//
|
|
// Convert an ADPCM wave file to a PCM wave file using the Audio Compression Manager
|
|
//
|
|
// parameters: *pwfxSrc => address of WAVEFORMATEX structure describing the source wave
|
|
// *src => pointer to raw source wave data
|
|
// src_len => num bytes of source wave data
|
|
// **dest => pointer to pointer to dest buffer for wave data
|
|
// (mem is allocated in this function if *dest is NULL)
|
|
// max_dest_bytes => Maximum memory allocated to dest
|
|
// *dest_len => returns num bytes of wave data in converted form (OUTPUT PARAMETER)
|
|
// *src_bytes_used => returns num bytes of src actually used in the conversion
|
|
// dest_bps => bits per sample that data should be uncompressed to
|
|
//
|
|
// returns: 0 => success
|
|
// -1 => could not convert wav file
|
|
//
|
|
//
|
|
// NOTES:
|
|
// 1. Storage for the decompressed audio will be allocated in this function if *dest is NULL.
|
|
// The caller is responsible for freeing this memory later.
|
|
//
|
|
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)
|
|
{
|
|
Assert( pwfxSrc != NULL );
|
|
Assert( pwfxSrc->wFormatTag == WAVE_FORMAT_ADPCM );
|
|
Assert( src != NULL );
|
|
Assert( src_len > 0 );
|
|
Assert( dest_len != NULL );
|
|
|
|
WAVEFORMATEX wfxDest;
|
|
HACMSTREAM hStream;
|
|
ACMSTREAMHEADER hCvtHdr;
|
|
int rc;
|
|
|
|
if ( ACM_inited == 0 ) {
|
|
rc = ACM_init();
|
|
if ( rc != 0 )
|
|
return -1;
|
|
}
|
|
|
|
wfxDest.wFormatTag = WAVE_FORMAT_PCM;
|
|
wfxDest.nChannels = pwfxSrc->nChannels;
|
|
wfxDest.nSamplesPerSec = pwfxSrc->nSamplesPerSec;
|
|
wfxDest.wBitsPerSample = dest_bps;
|
|
wfxDest.cbSize = 0;
|
|
wfxDest.nBlockAlign = (unsigned short)(( wfxDest.nChannels * wfxDest.wBitsPerSample ) / 8);
|
|
wfxDest.nAvgBytesPerSec = wfxDest.nBlockAlign * wfxDest.nSamplesPerSec;
|
|
|
|
rc = acmStreamOpen(&hStream, ghacmdriver, pwfxSrc, &wfxDest, NULL, 0L, 0L, ACM_STREAMOPENF_NONREALTIME);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
rc = acmStreamSize(hStream, src_len, (unsigned long *)dest_len, ACM_STREAMSIZEF_SOURCE);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
if ( *dest == NULL ) {
|
|
*dest = (ubyte*)vm_malloc(*dest_len);
|
|
Assert( *dest != NULL );
|
|
}
|
|
|
|
if ( !max_dest_bytes ) {
|
|
max_dest_bytes = *dest_len;
|
|
}
|
|
|
|
memset(&hCvtHdr, 0, sizeof(hCvtHdr));
|
|
|
|
hCvtHdr.cbStruct = sizeof(hCvtHdr);
|
|
hCvtHdr.pbSrc = (unsigned char *)src;
|
|
hCvtHdr.cbSrcLength = src_len;
|
|
hCvtHdr.pbDst = (unsigned char *)*dest;
|
|
hCvtHdr.cbDstLength = max_dest_bytes;
|
|
|
|
rc = acmStreamPrepareHeader(hStream, &hCvtHdr, 0);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
rc = acmStreamConvert(hStream, &hCvtHdr, 0);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
// Important step, since we need the exact length of the converted data.
|
|
*dest_len = hCvtHdr.cbDstLengthUsed;
|
|
*src_bytes_used = hCvtHdr.cbSrcLengthUsed;
|
|
|
|
rc = acmStreamUnprepareHeader(hStream, &hCvtHdr, 0);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
rc = acmStreamClose(hStream, 0);
|
|
if ( rc != 0 ) return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// =============================================================================
|
|
// ACM_init()
|
|
//
|
|
// Initializes the Audio Compression Manager components used to convert ADPCM to PCM
|
|
//
|
|
// returns: 0 => success
|
|
// -1 => ACM could not be initialized
|
|
//
|
|
int ACM_init()
|
|
{
|
|
int rc;
|
|
|
|
if ( ACM_inited == 1 )
|
|
return 0;
|
|
|
|
ghinstAcm = LoadLibrary(NOX("msacm32.dll"));
|
|
if (ghinstAcm == NULL) {
|
|
return -1;
|
|
}
|
|
FreeLibrary(ghinstAcm);
|
|
|
|
long dwVersion;
|
|
dwVersion = acmGetVersion();
|
|
nprintf(("Sound", "ACM Version number: %u.%.02u\n", HIWORD(dwVersion) >> 8, HIWORD(dwVersion) & 0x00FF));
|
|
// ACM must be version 3.5 or higher
|
|
if ( dwVersion < 0x03320000 ) {
|
|
return -1;
|
|
}
|
|
|
|
rc = acmDriverEnum(ACM_enum_callback, 0L, ACM_DRIVERENUMF_DISABLED);
|
|
if ( rc != MMSYSERR_NOERROR ) return -1;
|
|
|
|
if ( ghadid == NULL ) {
|
|
nprintf(("Sound", "SOUND => Unable to locate the Microsoft ADPCM driver\n"));
|
|
return -1;
|
|
}
|
|
|
|
rc = acmDriverOpen(&ghacmdriver, ghadid, 0L);
|
|
if ( rc != MMSYSERR_NOERROR ) return -1;
|
|
|
|
rc = acmDriverPriority(ghadid,0,0);
|
|
if ( rc != MMSYSERR_NOERROR ) return -1;
|
|
|
|
ACM_inited = 1;
|
|
return 0;
|
|
}
|
|
|
|
// Closes down the Audio Compression Manager components
|
|
void ACM_close()
|
|
{
|
|
if ( ACM_inited == 0 )
|
|
return;
|
|
|
|
acmDriverClose( ghacmdriver, 0L);
|
|
ACM_inited = 0;
|
|
}
|
|
|
|
// Query if the ACM system is initialized
|
|
int ACM_is_inited()
|
|
{
|
|
return ACM_inited;
|
|
}
|
|
|
|
#endif // !USE_OPENAL
|