You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
916 lines
23 KiB
916 lines
23 KiB
/////////////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 1998 Active Voice Corporation. All Rights Reserved.
|
|
//
|
|
// Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
|
|
//
|
|
// Other brand and product names used herein are trademarks of their respective owners.
|
|
//
|
|
// The entire program and user interface including the structure, sequence, selection,
|
|
// and arrangement of the dialog, the exclusively "yes" and "no" choices represented
|
|
// by "1" and "2," and each dialog message are protected by copyrights registered in
|
|
// the United States and by international treaties.
|
|
//
|
|
// Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
|
|
// 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
|
|
//
|
|
// Active Voice Corporation
|
|
// Seattle, Washington
|
|
// USA
|
|
//
|
|
/////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
////
|
|
// vox.c - vox file format (OKI ADPCM) functions
|
|
////
|
|
|
|
#include "winlocal.h"
|
|
|
|
#include "vox.h"
|
|
#include "wav.h"
|
|
#include "mem.h"
|
|
#include "mmio.h"
|
|
#include "sys.h"
|
|
#include "trace.h"
|
|
|
|
////
|
|
// private definitions
|
|
////
|
|
|
|
// step size type
|
|
//
|
|
typedef __int16 ss_type;
|
|
|
|
// vox engine control structure
|
|
//
|
|
typedef struct VOX
|
|
{
|
|
DWORD dwVersion;
|
|
HINSTANCE hInst;
|
|
HTASK hTask;
|
|
DWORD dwFlags;
|
|
ss_type ssDecoder; // decoder step size
|
|
ss_type ssEncoder; // encoder step size
|
|
PCM16 iVoxDecode; // previous decoded sample
|
|
} VOX, FAR *LPVOX;
|
|
|
|
// macros to convert vox 12 bit samples to/from other size samples
|
|
//
|
|
#define _Vox12To16(intx) ((PCM16) ((PCM16) (intx) << 4))
|
|
#define _Vox12To8(intx) ((BYTE) (((PCM16) (intx) >> 4) + 128))
|
|
#define _Vox8To12(bytex) (((PCM16) (bytex) - 128) << 4)
|
|
#define _Vox16To12(intx) ((PCM16) (intx) >> 4)
|
|
|
|
// helper functions
|
|
//
|
|
static LPVOX VoxGetPtr(HVOX hVox);
|
|
static HVOX VoxGetHandle(LPVOX lpVox);
|
|
static void ReverseIndexTableInit(void);
|
|
static PCM16 DecodeSample(BYTE bVoxEncode, ss_type FAR *lpss, PCM16 iVoxDecodePrev);
|
|
static BYTE EncodeSample(__int16 iDelta, ss_type FAR *lpss);
|
|
|
|
static LRESULT VoxIOOpen(LPMMIOINFO lpmmioinfo, LPTSTR lpszFileName);
|
|
static LRESULT VoxIOClose(LPMMIOINFO lpmmioinfo, UINT uFlags);
|
|
static LRESULT VoxIORead(LPMMIOINFO lpmmioinfo, HPSTR pch, LONG cch);
|
|
static LRESULT VoxIOWrite(LPMMIOINFO lpmmioinfo, const HPSTR pch, LONG cch, BOOL fFlush);
|
|
static LRESULT VoxIOSeek(LPMMIOINFO lpmmioinfo, LONG lOffset, int iOrigin);
|
|
static LRESULT VoxIORename(LPMMIOINFO lpmmioinfo, LPCTSTR lpszFileName, LPCTSTR lpszNewFileName);
|
|
static LRESULT VoxIOGetInfo(LPMMIOINFO lpmmioinfo, int iInfo);
|
|
static LRESULT VoxIOChSize(LPMMIOINFO lpmmioinfo, long lSize);
|
|
|
|
////
|
|
// public functions
|
|
////
|
|
|
|
// VoxInit - initialize vox engine
|
|
// <dwVersion> (i) must be VOX_VERSION
|
|
// <hInst> (i) instance handle of calling module
|
|
// <dwFlags> (i) reserved; must be 0
|
|
// return handle (NULL if error)
|
|
//
|
|
HVOX DLLEXPORT WINAPI VoxInit(DWORD dwVersion, HINSTANCE hInst, DWORD dwFlags)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox = NULL;
|
|
|
|
if (dwVersion != VOX_VERSION)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if (hInst == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if ((lpVox = (LPVOX) MemAlloc(NULL, sizeof(VOX), 0)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else
|
|
{
|
|
// initialize engine structure
|
|
//
|
|
lpVox->dwVersion = dwVersion;
|
|
lpVox->hInst = hInst;
|
|
lpVox->hTask = GetCurrentTask();
|
|
lpVox->dwFlags = dwFlags;
|
|
|
|
ReverseIndexTableInit();
|
|
|
|
if (VoxReset(VoxGetHandle(lpVox)) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
}
|
|
|
|
if (!fSuccess)
|
|
{
|
|
VoxTerm(VoxGetHandle(lpVox));
|
|
lpVox = NULL;
|
|
}
|
|
|
|
return fSuccess ? VoxGetHandle(lpVox) : NULL;
|
|
}
|
|
|
|
// VoxTerm - shut down vox engine
|
|
// <hVox> (i) handle returned from VoxInit
|
|
// return 0 if success
|
|
//
|
|
int DLLEXPORT WINAPI VoxTerm(HVOX hVox)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox;
|
|
|
|
if ((lpVox = VoxGetPtr(hVox)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if ((lpVox = MemFree(NULL, lpVox)) != NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
return fSuccess ? 0 : -1;
|
|
}
|
|
|
|
// VoxReset - reset vox engine
|
|
// <hVox> (i) handle returned from VoxInit
|
|
// return 0 if success
|
|
//
|
|
int DLLEXPORT WINAPI VoxReset(HVOX hVox)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox;
|
|
|
|
if ((lpVox = VoxGetPtr(hVox)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else
|
|
{
|
|
lpVox->ssDecoder = 16;
|
|
lpVox->ssEncoder = 16;
|
|
lpVox->iVoxDecode = 0;
|
|
}
|
|
|
|
return fSuccess ? 0 : -1;
|
|
}
|
|
|
|
// VoxDecode_16BitMono - decode vox samples
|
|
// <hVox> (i) handle returned from VoxInit
|
|
// <lpabVox> (i) array of encoded samples
|
|
// <lpaiPcm> (o) array of decoded samples
|
|
// <uSamples> (i) number of samples to decode
|
|
// return 0 if success
|
|
//
|
|
// NOTE: each BYTE in <lpabVox> contains 2 12-bit encoded samples
|
|
// in OKI ADPCM Vox format, as described by Dialogic
|
|
// Each PCM16 in <lpaiPcm> contains 1 16-bit decoded sample
|
|
// in standard PCM format.
|
|
//
|
|
int DLLEXPORT WINAPI VoxDecode_16BitMono(HVOX hVox, LPBYTE lpabVox, LPPCM16 lpaiPcm, UINT uSamples)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox;
|
|
|
|
if ((lpVox = VoxGetPtr(hVox)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if (lpaiPcm == NULL || lpabVox == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// since there are two samples per Vox data byte,
|
|
// we will decode two samples each time through the loop
|
|
//
|
|
else while (uSamples > 1)
|
|
{
|
|
BYTE bData;
|
|
|
|
bData = *lpabVox++;
|
|
|
|
lpVox->iVoxDecode = DecodeSample((BYTE)
|
|
(0xFF & ((BYTE) (bData >> 4) & (BYTE) 0x0F)),
|
|
&lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
*lpaiPcm++ = _Vox12To16(lpVox->iVoxDecode);
|
|
|
|
lpVox->iVoxDecode = DecodeSample((BYTE)
|
|
(0xFF & (bData & (BYTE) 0x0F)),
|
|
&lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
*lpaiPcm++ = _Vox12To16(lpVox->iVoxDecode);
|
|
|
|
uSamples -= 2;
|
|
}
|
|
|
|
return fSuccess ? 0 : -1;
|
|
}
|
|
|
|
// VoxEncode_16BitMono - encode vox samples
|
|
// <hVox> (i) handle returned from VoxInit
|
|
// <lpaiPcm> (i) array of decoded samples
|
|
// <lpabVox> (o) array of encoded samples
|
|
// <uSamples> (i) number of samples to encode
|
|
// return 0 if success
|
|
//
|
|
// NOTE: each BYTE in <lpabVox> contains 2 12-bit encoded samples
|
|
// in OKI ADPCM Vox format, as described by Dialogic
|
|
// Each PCM16 in <lpaiPcm> contains 1 16-bit decoded sample
|
|
// in standard PCM format.
|
|
//
|
|
int DLLEXPORT WINAPI VoxEncode_16BitMono(HVOX hVox, LPPCM16 lpaiPcm, LPBYTE lpabVox, UINT uSamples)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox;
|
|
|
|
if ((lpVox = VoxGetPtr(hVox)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if (lpaiPcm == NULL || lpabVox == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// since there are two samples per Vox data byte,
|
|
// we will encode two samples each time through the loop
|
|
//
|
|
else while (uSamples > 1)
|
|
{
|
|
__int16 iDelta;
|
|
PCM16 iVoxDecode;
|
|
BYTE bVoxEncode1;
|
|
BYTE bVoxEncode2;
|
|
|
|
iVoxDecode = _Vox16To12(*lpaiPcm++);
|
|
|
|
iDelta = iVoxDecode - lpVox->iVoxDecode;
|
|
bVoxEncode1 = EncodeSample(iDelta, &lpVox->ssEncoder);
|
|
lpVox->iVoxDecode = DecodeSample(bVoxEncode1, &lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
iVoxDecode = _Vox16To12(*lpaiPcm++);
|
|
|
|
iDelta = iVoxDecode - lpVox->iVoxDecode;
|
|
bVoxEncode2 = EncodeSample(iDelta, &lpVox->ssEncoder);
|
|
lpVox->iVoxDecode = DecodeSample(bVoxEncode2, &lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
*lpabVox++ = (BYTE) (((BYTE) (bVoxEncode1 << 4) & (BYTE) 0xF0) | bVoxEncode2);
|
|
|
|
uSamples -= 2;
|
|
}
|
|
|
|
return fSuccess ? 0 : -1;
|
|
}
|
|
|
|
// VoxDecode_8BitMono - decode vox samples
|
|
// <hVox> (i) handle returned from VoxInit
|
|
// <lpabVox> (i) array of encoded samples
|
|
// <lpabPcm> (o) array of decoded samples
|
|
// <uSamples> (i) number of samples to decode
|
|
// return 0 if success
|
|
//
|
|
// NOTE: each BYTE in <lpabVox> contains 2 12-bit encoded samples
|
|
// in OKI ADPCM Vox format, as described by Dialogic
|
|
// Each PCM8 in <lpabPcm> contains 1 8-bit decoded sample
|
|
// in standard PCM format.
|
|
//
|
|
int DLLEXPORT WINAPI VoxDecode_8BitMono(HVOX hVox, LPBYTE lpabVox, LPPCM8 lpabPcm, UINT uSamples)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox;
|
|
|
|
if ((lpVox = VoxGetPtr(hVox)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if (lpabPcm == NULL || lpabVox == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// since there are two samples per Vox data byte,
|
|
// we will decode two samples each time through the loop
|
|
//
|
|
else while (uSamples > 1)
|
|
{
|
|
BYTE bData;
|
|
|
|
bData = *lpabVox++;
|
|
|
|
lpVox->iVoxDecode = DecodeSample((BYTE)
|
|
(0xFF & ((BYTE) (bData >> 4) & (BYTE) 0x0F)),
|
|
&lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
*lpabPcm++ = _Vox12To8(lpVox->iVoxDecode);
|
|
|
|
lpVox->iVoxDecode = DecodeSample((BYTE)
|
|
(0xFF & (bData & (BYTE) 0x0F)),
|
|
&lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
*lpabPcm++ = _Vox12To8(lpVox->iVoxDecode);
|
|
|
|
uSamples -= 2;
|
|
}
|
|
|
|
return fSuccess ? 0 : -1;
|
|
}
|
|
|
|
// VoxEncode_8BitMono - encode vox samples
|
|
// <hVox> (i) handle returned from VoxInit
|
|
// <lpabPcm> (i) array of decoded samples
|
|
// <lpabVox> (o) array of encoded samples
|
|
// <uSamples> (i) number of samples to encode
|
|
// return 0 if success
|
|
//
|
|
// NOTE: each BYTE in <lpabVox> contains 2 12-bit encoded samples
|
|
// in OKI ADPCM Vox format, as described by Dialogic
|
|
// Each PCM8 in <lpabPcm> contains 1 8-bit decoded sample
|
|
// in standard PCM format.
|
|
//
|
|
int DLLEXPORT WINAPI VoxEncode_8BitMono(HVOX hVox, LPPCM8 lpabPcm, LPBYTE lpabVox, UINT uSamples)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox;
|
|
|
|
if ((lpVox = VoxGetPtr(hVox)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if (lpabPcm == NULL || lpabVox == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// since there are two samples per Vox data byte,
|
|
// we will encode two samples each time through the loop
|
|
//
|
|
else while (uSamples > 1)
|
|
{
|
|
__int16 iDelta;
|
|
PCM16 iVoxDecode;
|
|
BYTE bVoxEncode1;
|
|
BYTE bVoxEncode2;
|
|
|
|
iVoxDecode = _Vox8To12(*lpabPcm++);
|
|
|
|
iDelta = iVoxDecode - lpVox->iVoxDecode;
|
|
bVoxEncode1 = EncodeSample(iDelta, &lpVox->ssEncoder);
|
|
lpVox->iVoxDecode = DecodeSample(bVoxEncode1, &lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
iVoxDecode = _Vox8To12(*lpabPcm++);
|
|
|
|
iDelta = iVoxDecode - lpVox->iVoxDecode;
|
|
bVoxEncode2 = EncodeSample(iDelta, &lpVox->ssEncoder);
|
|
lpVox->iVoxDecode = DecodeSample(bVoxEncode2, &lpVox->ssDecoder, lpVox->iVoxDecode);
|
|
|
|
*lpabVox++ = (BYTE) (((BYTE) (bVoxEncode1 << 4) & (BYTE) 0xF0) | bVoxEncode2);
|
|
|
|
uSamples -= 2;
|
|
}
|
|
|
|
return fSuccess ? 0 : -1;
|
|
}
|
|
|
|
// VoxIOProc - i/o procedure for vox format file data
|
|
// <lpmmioinfo> (i/o) information about open file
|
|
// <uMessage> (i) message indicating the requested I/O operation
|
|
// <lParam1> (i) message specific parameter
|
|
// <lParam2> (i) message specific parameter
|
|
// returns 0 if message not recognized, otherwise message specific value
|
|
//
|
|
// NOTE: the address of this function should be passed to the WavOpen()
|
|
// or mmioInstallIOProc() functions for accessing vox format file data.
|
|
//
|
|
LRESULT DLLEXPORT CALLBACK VoxIOProc(LPTSTR lpmmioinfo,
|
|
UINT uMessage, LPARAM lParam1, LPARAM lParam2)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LRESULT lResult = 0;
|
|
|
|
if (lpmmioinfo == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else switch (uMessage)
|
|
{
|
|
case MMIOM_OPEN:
|
|
lResult = VoxIOOpen((LPMMIOINFO) lpmmioinfo,
|
|
(LPTSTR) lParam1);
|
|
break;
|
|
|
|
case MMIOM_CLOSE:
|
|
lResult = VoxIOClose((LPMMIOINFO) lpmmioinfo,
|
|
(UINT) lParam1);
|
|
break;
|
|
|
|
case MMIOM_READ:
|
|
lResult = VoxIORead((LPMMIOINFO) lpmmioinfo,
|
|
(HPSTR) lParam1, (LONG) lParam2);
|
|
break;
|
|
|
|
case MMIOM_WRITE:
|
|
lResult = VoxIOWrite((LPMMIOINFO) lpmmioinfo,
|
|
(const HPSTR) lParam1, (LONG) lParam2, FALSE);
|
|
break;
|
|
|
|
case MMIOM_WRITEFLUSH:
|
|
lResult = VoxIOWrite((LPMMIOINFO) lpmmioinfo,
|
|
(const HPSTR) lParam1, (LONG) lParam2, TRUE);
|
|
break;
|
|
|
|
case MMIOM_SEEK:
|
|
lResult = VoxIOSeek((LPMMIOINFO) lpmmioinfo,
|
|
(LONG) lParam1, (int) lParam2);
|
|
break;
|
|
|
|
case MMIOM_RENAME:
|
|
lResult = VoxIORename((LPMMIOINFO) lpmmioinfo,
|
|
(LPCTSTR) lParam1, (LPCTSTR) lParam2);
|
|
break;
|
|
|
|
case MMIOM_GETINFO:
|
|
lResult = VoxIOGetInfo((LPMMIOINFO) lpmmioinfo,
|
|
(int) lParam1);
|
|
break;
|
|
|
|
case MMIOM_CHSIZE:
|
|
lResult = VoxIOChSize((LPMMIOINFO) lpmmioinfo,
|
|
(long) lParam1);
|
|
break;
|
|
|
|
default:
|
|
lResult = 0;
|
|
break;
|
|
}
|
|
|
|
return lResult;
|
|
}
|
|
|
|
////
|
|
// private functions
|
|
////
|
|
|
|
// VoxGetPtr - verify that vox handle is valid,
|
|
// <hVox> (i) handle returned from VoxInit
|
|
// return corresponding vox pointer (NULL if error)
|
|
//
|
|
static LPVOX VoxGetPtr(HVOX hVox)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
LPVOX lpVox;
|
|
|
|
if ((lpVox = (LPVOX) hVox) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if (IsBadWritePtr(lpVox, sizeof(VOX)))
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
#ifdef CHECKTASK
|
|
// make sure current task owns the vox engine handle
|
|
//
|
|
else if (lpVox->hTask != GetCurrentTask())
|
|
fSuccess = TraceFALSE(NULL);
|
|
#endif
|
|
|
|
return fSuccess ? lpVox : NULL;
|
|
}
|
|
|
|
// VoxGetHandle - verify that vox pointer is valid,
|
|
// <lpVox> (i) pointer to VOX structure
|
|
// return corresponding vox handle (NULL if error)
|
|
//
|
|
static HVOX VoxGetHandle(LPVOX lpVox)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HVOX hVox;
|
|
|
|
if ((hVox = (HVOX) lpVox) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
return fSuccess ? hVox : NULL;
|
|
}
|
|
|
|
////
|
|
// low-level ADPCM stuff
|
|
////
|
|
|
|
static ss_type const ss_table[] =
|
|
{
|
|
16, 17, 19, 21, 23, 25, 28, 31, 34, 37,
|
|
41, 45, 50, 55, 60, 66, 73, 80, 88, 97,
|
|
107, 118, 130, 143, 157, 173, 190, 209, 230, 253,
|
|
279, 307, 337, 371, 408, 449, 494, 544, 598, 658,
|
|
724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552
|
|
};
|
|
|
|
static __int16 delta_index_table[] =
|
|
{
|
|
-1, -1, -1, -1, +2, +4, +6, +8, -1, -1, -1, -1, +2, +4, +6, +8
|
|
};
|
|
|
|
////
|
|
// The reverse index table is designed so that given a step size, we
|
|
// can get back out the index that generated it.
|
|
////
|
|
static BYTE reverse_index_table[1553];
|
|
|
|
// initialize reverse index table
|
|
//
|
|
static void ReverseIndexTableInit(void)
|
|
{
|
|
__int16 i;
|
|
|
|
for (i = 0; i < 49; ++i)
|
|
reverse_index_table[ss_table[i]] = (BYTE) i;
|
|
}
|
|
|
|
#if 0
|
|
static ss_type new_ss(ss_type ss, BYTE bVoxEncode);
|
|
static ss_type new_ss(ss_type ss, BYTE bVoxEncode)
|
|
{
|
|
__int16 index;
|
|
|
|
// find out what our old index into the step size table was
|
|
//
|
|
index = reverse_index_table[ss];
|
|
|
|
// modify our index based on the present value of the ADPCM nibble
|
|
//
|
|
index += delta_index_table[bVoxEncode];
|
|
|
|
// limit ourselves to the maximum size of the table in case of overflow
|
|
//
|
|
index = max(0, min(48, index));
|
|
|
|
// and return our new step size out of the table
|
|
//
|
|
return ss_table[index];
|
|
}
|
|
#else
|
|
#define new_ss(ss, bVoxEncode) ss_table[max(0, min(48, \
|
|
reverse_index_table[ss] + delta_index_table[bVoxEncode]))]
|
|
#endif
|
|
|
|
// DECODE - ADPCM to linear
|
|
//
|
|
static PCM16 DecodeSample(BYTE bVoxEncode, ss_type FAR *lpss, PCM16 iVoxDecodePrev)
|
|
{
|
|
__int16 iDelta;
|
|
PCM16 iVoxDecode;
|
|
ss_type ss;
|
|
|
|
ss = *lpss;
|
|
|
|
// iDelta = (((nibble * 2) + 1) / 8 ) * ss;
|
|
//
|
|
iDelta = ((((bVoxEncode & 0x07) << 1) + 1) * ss ) >> 3;
|
|
|
|
if ((bVoxEncode & 0x08) == 0x08)
|
|
iDelta = -iDelta;
|
|
|
|
*lpss = new_ss(ss, bVoxEncode);
|
|
iVoxDecode = iVoxDecodePrev + iDelta;
|
|
|
|
// limit ourselves to 12 bits of resolution
|
|
//
|
|
if (iVoxDecode > 2047)
|
|
return 2047;
|
|
else if (iVoxDecode < -2048)
|
|
return -2048;
|
|
else
|
|
return iVoxDecode;
|
|
}
|
|
|
|
// ENCODE - linear to ADPCM
|
|
//
|
|
static BYTE EncodeSample(__int16 iDelta, ss_type FAR *lpss)
|
|
{
|
|
BYTE bVoxEncode;
|
|
ss_type ss;
|
|
__int16 iDeltaTmp;
|
|
|
|
ss = *lpss;
|
|
iDeltaTmp = iDelta;
|
|
|
|
if (iDeltaTmp < 0)
|
|
{
|
|
iDeltaTmp = -iDeltaTmp;
|
|
bVoxEncode = 0x08;
|
|
}
|
|
else
|
|
bVoxEncode = 0;
|
|
|
|
if (iDeltaTmp >= ss)
|
|
{
|
|
bVoxEncode |= 0x04;
|
|
iDeltaTmp -= ss;
|
|
}
|
|
|
|
if (iDeltaTmp >= (ss >> 1))
|
|
{
|
|
bVoxEncode |= 0x02;
|
|
iDeltaTmp -= (ss >> 1);
|
|
}
|
|
|
|
if (iDeltaTmp >= (ss >> 2))
|
|
{
|
|
bVoxEncode |= 0x01;
|
|
}
|
|
|
|
*lpss = new_ss(ss, bVoxEncode);
|
|
|
|
return (BYTE) (bVoxEncode & (BYTE) 0x0F);
|
|
|
|
// format of return nibble is
|
|
// S W F F
|
|
// | | | |
|
|
// | | | +--- 1/4 of delta/step
|
|
// | | +----- 1/2 of delta/step
|
|
// | +------- whole part of delta/step
|
|
// +--------- sign bit
|
|
}
|
|
|
|
|
|
////
|
|
// installable file i/o procedures
|
|
////
|
|
|
|
static LRESULT VoxIOOpen(LPMMIOINFO lpmmioinfo, LPTSTR lpszFileName)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HMMIO hmmio = NULL;
|
|
MMIOINFO mmioinfo;
|
|
HVOX hVox = NULL;
|
|
HINSTANCE hInst;
|
|
|
|
TracePrintf_1(NULL, 5,
|
|
TEXT("VoxIOOpen (%s)\n"),
|
|
(LPTSTR) lpszFileName);
|
|
|
|
MemSet(&mmioinfo, 0, sizeof(mmioinfo));
|
|
|
|
// interpret first value passed as pointer to next i/o procedure in chain
|
|
//
|
|
mmioinfo.pIOProc = (LPMMIOPROC) lpmmioinfo->adwInfo[0];
|
|
|
|
// pass along second and third values to next i/o procedure
|
|
//
|
|
mmioinfo.adwInfo[0] = lpmmioinfo->adwInfo[1];
|
|
mmioinfo.adwInfo[1] = lpmmioinfo->adwInfo[2];
|
|
mmioinfo.adwInfo[2] = 0L;
|
|
|
|
// get instance handle of current task
|
|
//
|
|
if ((hInst = SysGetTaskInstance(NULL)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if ((hVox = VoxInit(VOX_VERSION, hInst, 0)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if ((hmmio = mmioOpen(lpszFileName, &mmioinfo, lpmmioinfo->dwFlags)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else
|
|
{
|
|
// save stuff for use in other i/o routines
|
|
//
|
|
lpmmioinfo->adwInfo[0] = (DWORD) (LPVOID) hmmio;
|
|
lpmmioinfo->adwInfo[1] = (DWORD) (LPVOID) hVox;
|
|
}
|
|
|
|
// clean up after error
|
|
//
|
|
if (!fSuccess && hVox != NULL && VoxTerm(hVox) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
if (!fSuccess && hmmio != NULL && mmioClose(hmmio, 0) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// return the same error code given by mmioOpen
|
|
//
|
|
return fSuccess ? lpmmioinfo->wErrorRet = mmioinfo.wErrorRet : MMIOERR_CANNOTOPEN;
|
|
}
|
|
|
|
static LRESULT VoxIOClose(LPMMIOINFO lpmmioinfo, UINT uFlags)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HMMIO hmmio = (HMMIO) lpmmioinfo->adwInfo[0];
|
|
HVOX hVox = (HVOX) lpmmioinfo->adwInfo[1];
|
|
UINT uRet = MMIOERR_CANNOTCLOSE;
|
|
|
|
TracePrintf_0(NULL, 5,
|
|
TEXT("VoxIOClose\n"));
|
|
|
|
if (VoxTerm(hVox) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else if ((uRet = mmioClose(hmmio, uFlags)) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
else
|
|
{
|
|
lpmmioinfo->adwInfo[0] = (DWORD) NULL;
|
|
lpmmioinfo->adwInfo[1] = (DWORD) NULL;
|
|
}
|
|
|
|
return fSuccess ? 0 : uRet;
|
|
}
|
|
|
|
static LRESULT VoxIORead(LPMMIOINFO lpmmioinfo, HPSTR pch, LONG cch)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HMMIO hmmio = (HMMIO) lpmmioinfo->adwInfo[0];
|
|
HVOX hVox = (HVOX) lpmmioinfo->adwInfo[1];
|
|
LONG cchVox;
|
|
LONG lBytesRead;
|
|
HPSTR pchVox = NULL;
|
|
|
|
TracePrintf_1(NULL, 5,
|
|
TEXT("VoxIORead (%ld)\n"),
|
|
(long) cch);
|
|
|
|
// vox format files contain 4 bit samples,
|
|
// but we must simulate access to 16 bit samples.
|
|
//
|
|
cchVox = cch / 4L;
|
|
|
|
if (cchVox <= 0)
|
|
lBytesRead = 0; // nothing to do
|
|
|
|
// allocate temporary buffer to hold the vox format samples
|
|
//
|
|
if ((pchVox = (HPSTR) MemAlloc(NULL, cchVox, 0)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// read vox format samples
|
|
//
|
|
else if ((lBytesRead = mmioRead(hmmio, pchVox, cchVox)) == -1)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// decode vox format samples into pcm format samples
|
|
// (there are 2 samples encoded in each vox byte)
|
|
//
|
|
else if (VoxDecode_16BitMono(hVox, (LPBYTE) pchVox, (LPPCM16) pch, (UINT) (lBytesRead * 2L)) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// update simulated file position
|
|
//
|
|
if (fSuccess)
|
|
lpmmioinfo->lDiskOffset += lBytesRead * 4L;
|
|
|
|
TracePrintf_2(NULL, 5,
|
|
TEXT("VoxIO: lpmmioinfo->lDiskOffset=%ld, lBytesRead=%ld\n"),
|
|
(long) lpmmioinfo->lDiskOffset,
|
|
(long) lBytesRead);
|
|
|
|
// clean up
|
|
//
|
|
if (pchVox != NULL &&
|
|
(pchVox = MemFree(NULL, pchVox)) != NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// return number of bytes read/decoded into pch
|
|
//
|
|
return fSuccess ? lBytesRead * 4L : -1;
|
|
}
|
|
|
|
static LRESULT VoxIOWrite(LPMMIOINFO lpmmioinfo, const HPSTR pch, LONG cch, BOOL fFlush)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HMMIO hmmio = (HMMIO) lpmmioinfo->adwInfo[0];
|
|
HVOX hVox = (HVOX) lpmmioinfo->adwInfo[1];
|
|
HPSTR pchVox = NULL;
|
|
LONG cchVox;
|
|
LONG lBytesWritten;
|
|
|
|
TracePrintf_1(NULL, 5,
|
|
TEXT("VoxIOWrite (%ld)\n"),
|
|
(long) cch);
|
|
|
|
// vox format files contain 4 bit samples,
|
|
// but we must simulate access to 16 bit samples.
|
|
//
|
|
cchVox = cch / 4L;
|
|
|
|
if (cchVox <= 0)
|
|
lBytesWritten = 0; // nothing to do
|
|
|
|
// allocate temporary buffer to hold the vox format samples
|
|
//
|
|
else if ((pchVox = (HPSTR) MemAlloc(NULL, cchVox, 0)) == NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// encode pcm format samples into vox format samples
|
|
// (there are 2 bytes required for each pcm sample)
|
|
//
|
|
else if (VoxEncode_16BitMono(hVox, (LPPCM16) pch, (LPBYTE) pchVox, (UINT) (cch / 2L)) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// write vox format samples
|
|
//
|
|
else if ((lBytesWritten = mmioWrite(hmmio, pchVox, cchVox)) == -1)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// update simulated file position
|
|
//
|
|
else
|
|
lpmmioinfo->lDiskOffset += lBytesWritten * 4L;
|
|
|
|
// clean up
|
|
//
|
|
if (pchVox != NULL &&
|
|
(pchVox = MemFree(NULL, pchVox)) != NULL)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
TracePrintf_2(NULL, 5,
|
|
TEXT("VoxIO: lpmmioinfo->lDiskOffset=%ld, lBytesWritten=%ld\n"),
|
|
(long) lpmmioinfo->lDiskOffset,
|
|
(long) lBytesWritten);
|
|
|
|
// return number of bytes encoded/written from pch
|
|
//
|
|
return fSuccess ? lBytesWritten * 4L : -1;
|
|
}
|
|
|
|
static LRESULT VoxIOSeek(LPMMIOINFO lpmmioinfo, LONG lOffset, int iOrigin)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HMMIO hmmio = (HMMIO) lpmmioinfo->adwInfo[0];
|
|
LONG lPosNew;
|
|
|
|
TracePrintf_2(NULL, 5,
|
|
TEXT("VoxIOSeek (%ld, %d)\n"),
|
|
(long) lOffset,
|
|
(int) iOrigin);
|
|
|
|
// vox format files contain 4 bit samples,
|
|
// but we must simulate access to 16 bit samples.
|
|
//
|
|
if ((lPosNew = mmioSeek(hmmio, lOffset / 4L, iOrigin)) == -1)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
// update simulated file position
|
|
//
|
|
else
|
|
lpmmioinfo->lDiskOffset = lPosNew * 4L;
|
|
|
|
TracePrintf_1(NULL, 5,
|
|
TEXT("VoxIO: lpmmioinfo->lDiskOffset=%ld\n"),
|
|
(long) lpmmioinfo->lDiskOffset);
|
|
|
|
return fSuccess ? lpmmioinfo->lDiskOffset : -1;
|
|
}
|
|
|
|
static LRESULT VoxIORename(LPMMIOINFO lpmmioinfo, LPCTSTR lpszFileName, LPCTSTR lpszNewFileName)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
UINT uRet = MMIOERR_FILENOTFOUND;
|
|
|
|
TracePrintf_2(NULL, 5,
|
|
TEXT("VoxIORename (%s, %s)\n"),
|
|
(LPTSTR) lpszFileName,
|
|
(LPTSTR) lpszNewFileName);
|
|
|
|
if ((uRet = mmioRename(lpszFileName, lpszNewFileName, lpmmioinfo, 0)) != 0)
|
|
fSuccess = TraceFALSE(NULL);
|
|
|
|
return fSuccess ? 0 : uRet;
|
|
}
|
|
|
|
static LRESULT VoxIOGetInfo(LPMMIOINFO lpmmioinfo, int iInfo)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HMMIO hmmio = (HMMIO) lpmmioinfo->adwInfo[0];
|
|
LRESULT lResult;
|
|
|
|
TracePrintf_1(NULL, 5,
|
|
TEXT("VoxIOGetInfo (%d)\n"),
|
|
(int) iInfo);
|
|
|
|
lResult = mmioSendMessage(hmmio, MMIOM_GETINFO, iInfo, 0);
|
|
#if 1
|
|
if (iInfo == 1)
|
|
{
|
|
// vox format files contain 4 bit samples,
|
|
// but we must simulate access to 16 bit samples.
|
|
//
|
|
lResult *= 4;
|
|
}
|
|
#endif
|
|
return fSuccess ? lResult : 0;
|
|
}
|
|
|
|
static LRESULT VoxIOChSize(LPMMIOINFO lpmmioinfo, long lSize)
|
|
{
|
|
BOOL fSuccess = TRUE;
|
|
HMMIO hmmio = (HMMIO) lpmmioinfo->adwInfo[0];
|
|
LRESULT lResult;
|
|
|
|
TracePrintf_1(NULL, 5,
|
|
TEXT("VoxIOChSize (%ld)\n"),
|
|
(long) lSize);
|
|
|
|
lResult = mmioSendMessage(hmmio, MMIOM_CHSIZE, lSize, 0);
|
|
|
|
return fSuccess ? lResult : -1;
|
|
}
|