windows-nt/Source/XPSP1/NT/multimedia/media/sndrec32/soundrec/edit.c
2020-09-26 16:20:57 +08:00

1713 lines
51 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* (C) Copyright Microsoft Corporation 1991-1994. All Rights Reserved */
/* edit.c
*
* Editing operations and special effects.
*/
/* Revision History.
* 4/ Feb/91 LaurieGr (AKA LKG) Ported to WIN32 / WIN16 common code
* 14/Feb/94 LaurieGr merged Motown and Daytona versions
*/
#include "nocrap.h"
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <string.h>
#define INCLUDE_OLESTUBS
#include "SoundRec.h"
#include "srecids.h"
/* constants */
#define CHVOL_INCDELTAVOLUME 25 // ChangeVolume: % to inc volume by
#define CHVOL_DECDELTAVOLUME 20 // ChangeVolume: % to dec volume by
#define ECHO_VOLUME 25 // AddEcho: % to multiply echo samples
#define ECHO_DELAY 150 // AddEcho: millisec delay for echo
#define WAVEBUFSIZE 400 // IncreasePitch, DecreasePitch
#define FINDWAVE_PICKYNESS 5 // how picky is FindWave?
extern char aszInitFile[]; // soundrec.c
static SZCODE aszSamplesFormat[] = TEXT("%d%c%02d");
static SZCODE aszSamplesNoZeroFormat[] = TEXT("%c%02d");
/* InsertFile(void)
*
* Prompt for the name of a WAVE file to insert at the current position.
*/
void FAR PASCAL
InsertFile(BOOL fPaste)
{
TCHAR achFileName[_MAX_PATH]; // name of file to insert
WAVEFORMATEX* pwfInsert=NULL; // WAVE file format of given file
DWORD cb; // size of WAVEFORMATEX
HPBYTE pInsertSamples = NULL; // samples from file to insert
long lInsertSamples; // number of samples in given file
long lSamplesToInsert;// no. samp. at samp. rate of cur. file
TCHAR ach[80]; // buffer for string loading
HCURSOR hcurPrev = NULL; // cursor before hourglass
HPBYTE pchSrc; // pointer into source wave buffer
short * piSrc; // 16-bit pointer
HPBYTE pchDst; // pointer into destination wave buffer
short * piDst; // 16-bit pointer
long lSamplesDst; // bytes to copy into destination buffer
long lDDA; // used to implement DDA algorithm
HMMIO hmmio; // Handle to open file to read from
BOOL fDirty = TRUE; // Is the buffer Dirty?
BOOL fStereoIn;
BOOL fStereoOut;
BOOL fEightIn;
BOOL fEightOut;
BOOL fEditWave = FALSE;
int iTemp;
int iTemp2;
OPENFILENAME ofn;
#ifdef DOWECARE
/* HACK from "server.c" to read objects without CF_WAVE */
extern WORD cfNative;
#endif
if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(gpWaveFormat))
return;
if (fPaste) {
MMIOINFO mmioinfo;
HANDLE h;
BeginWaveEdit();
if (!OpenClipboard(ghwndApp))
return;
LoadString(ghInst, IDS_CLIPBOARD, achFileName, SIZEOF(achFileName));
h = GetClipboardData(CF_WAVE);
#ifdef DOWECARE
if (!h) h = GetClipboardData(cfNative);
#endif
if (h)
{
mmioinfo.fccIOProc = FOURCC_MEM;
mmioinfo.pIOProc = NULL;
mmioinfo.pchBuffer = GlobalLock(h);
mmioinfo.cchBuffer = (long)GlobalSize(h); // initial size
mmioinfo.adwInfo[0] = 0; // grow by this much
hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ);
}
else
{
hmmio = NULL;
}
}
else
{
BOOL f;
achFileName[0] = 0;
/* prompt user for file to open */
LoadString(ghInst, IDS_INSERTFILE, ach, SIZEOF(ach));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = ghwndApp;
ofn.hInstance = NULL;
ofn.lpstrFilter = aszFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 1;
ofn.lpstrFile = achFileName;
ofn.nMaxFile = SIZEOF(achFileName);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = ach;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = NULL;
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
f = GetOpenFileName(&ofn); // get the filename
// did we succeed or not?
if (!f)
goto RETURN_ERROR;
/* read the WAVE file */
hmmio = mmioOpen(achFileName, NULL, MMIO_READ | MMIO_ALLOCBUF);
}
if (hmmio != NULL)
{
MMRESULT mmr;
//
// show hourglass cursor
//
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// read the WAVE file
//
mmr = ReadWaveFile( hmmio
, &pwfInsert
, &cb
, &pInsertSamples
, &lInsertSamples
, achFileName
, FALSE );
mmioClose(hmmio, 0);
if (mmr != MMSYSERR_NOERROR)
goto RETURN_ERROR;
if (lInsertSamples == 0)
goto RETURN_SUCCESS;
if (pInsertSamples == NULL)
goto RETURN_ERROR;
if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(pwfInsert))
{
ErrorResBox( ghwndApp
, ghInst
, MB_ICONEXCLAMATION | MB_OK
, IDS_APPTITLE
, fPaste ? IDS_CANTPASTE : IDS_NOTASUPPORTEDFILE
, (LPTSTR) achFileName
);
goto RETURN_ERROR;
}
} else {
ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
IDS_APPTITLE, IDS_ERROROPEN, (LPTSTR) achFileName);
goto RETURN_ERROR;
}
//jyg:moved
// BeginWaveEdit();
fEditWave = TRUE;
//
// if the current file is empty, treat the insert like a open
//
if (glWaveSamplesValid == 0)
{
DestroyWave();
gpWaveSamples = pInsertSamples;
glWaveSamples = lInsertSamples;
glWaveSamplesValid = lInsertSamples;
gpWaveFormat = pwfInsert;
gcbWaveFormat = cb;
pInsertSamples = NULL;
pwfInsert = NULL;
goto RETURN_SUCCESS;
}
fStereoIn = pwfInsert->nChannels != 1;
fStereoOut = gpWaveFormat->nChannels != 1;
fEightIn = ((LPWAVEFORMATEX)pwfInsert)->wBitsPerSample == 8;
fEightOut = ((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8;
/* figure out how many bytes need to be inserted */
lSamplesToInsert = MulDiv(lInsertSamples, gpWaveFormat->nSamplesPerSec,
pwfInsert->nSamplesPerSec);
#ifdef DEBUG
DPF(TEXT("insert %ld samples, converting from %ld Hz to %ld Hz\n"),
lInsertSamples, pwfInsert->nSamplesPerSec,
gpWaveFormat->nSamplesPerSec);
DPF(TEXT("so %ld samples need to be inserted at position %ld\n"),
lSamplesToInsert, glWavePosition);
#endif
/* reallocate the WAVE buffer to be big enough */
if (!AllocWaveBuffer(glWaveSamplesValid + lSamplesToInsert, TRUE, TRUE))
goto RETURN_ERROR;
glWaveSamplesValid += lSamplesToInsert;
/* create a "gap" in the WAVE buffer to go from this:
* |---glWavePosition---|-rest-of-buffer-|
* to this:
* |---glWavePosition---|----lSamplesToInsert----|-rest-of-buffer-|
* where <glWaveSamplesValid> is the size of the buffer
* *after* reallocation
*/
memmove( gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition + lSamplesToInsert)
, gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition)
, wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - (glWavePosition + lSamplesToInsert))
);
/* copy the read-in WAVE file into the "gap" */
pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat,glWavePosition);
piDst = (short *) pchDst;
lSamplesDst = lSamplesToInsert;
pchSrc = pInsertSamples;
piSrc = (short *) pchSrc;
lDDA = -((LONG)gpWaveFormat->nSamplesPerSec);
while (lSamplesDst > 0)
{
/* get a sample, convert to right format */
if (fEightIn) {
iTemp = *((BYTE *) pchSrc);
if (fStereoIn) {
iTemp2 = (unsigned char) *(pchSrc+1);
if (!fStereoOut) {
iTemp = (iTemp + iTemp2) / 2;
}
}
else
iTemp2 = iTemp;
if (!fEightOut) {
iTemp = (iTemp - 128) << 8;
iTemp2 = (iTemp2 - 128) << 8;
}
} else {
iTemp = *piSrc;
if (fStereoIn) {
iTemp2 = *(piSrc+1);
if (!fStereoOut) {
iTemp = (int) ( ( ((long)iTemp) + ((long) iTemp2)
) / 2);
}
}
else
iTemp2 = iTemp;
if (fEightOut) {
iTemp = (iTemp >> 8) + 128;
iTemp2 = (iTemp2 >> 8) + 128;
}
}
/* Output a sample */
if (fEightOut)
{ // Cast on lvalue eliminated -- LKG
*(BYTE *) pchDst = (BYTE) iTemp;
pchDst = (BYTE *)pchDst + 1;
}
else
*piDst++ = (short)iTemp;
if (fStereoOut) {
if (fEightOut)
{ // Cast on lvalue eliminated -- LKG
*(BYTE *) pchDst = (BYTE) iTemp2;
pchDst = (BYTE *)pchDst + 1;
}
else
*piDst++ = (short)iTemp2;
}
lSamplesDst--;
/* increment <pchSrc> at the correct rate so that the
* sampling rate of the input file is converted to match
* the sampling rate of the current file
*/
lDDA += pwfInsert->nSamplesPerSec;
while (lDDA >= 0) {
lDDA -= gpWaveFormat->nSamplesPerSec;
if (fEightIn)
pchSrc++;
else
piSrc++;
if (fStereoIn) {
if (fEightIn)
pchSrc++;
else
piSrc++;
}
}
}
#ifdef DEBUG
if (!fEightIn)
pchSrc = (HPBYTE) piSrc;
DPF(TEXT("copied %ld bytes from insertion buffer\n"), (long) (pchSrc - pInsertSamples));
#endif
goto RETURN_SUCCESS;
RETURN_ERROR: // do error exit without error message
fDirty = FALSE;
RETURN_SUCCESS: // normal exit
if (fPaste)
CloseClipboard();
if (pInsertSamples != NULL)
GlobalFreePtr(pInsertSamples);
if (pwfInsert != NULL)
GlobalFreePtr(pwfInsert);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
if (fEditWave == TRUE)
EndWaveEdit(fDirty);
/* update the display */
UpdateDisplay(TRUE);
}
/* MixWithFile(void)
*
* Prompt for the name of a WAVE file to mix with the audio starting at
* the current location.
*/
void FAR PASCAL
MixWithFile(BOOL fPaste)
{
TCHAR achFileName[_MAX_PATH]; // name of file to mix with
WAVEFORMATEX* pwfMix=NULL; // WAVE file format of given file
UINT cb;
HPBYTE pMixSamples = NULL; // samples from file to mix with
long lMixSamples; // number of samples in given file
long lSamplesToMix; // no. Samples at samp. rate. of cur. file
long lSamplesToAdd; // no. Samples to add in
TCHAR ach[80]; // buffer for string loading
HCURSOR hcurPrev = NULL; // cursor before hourglass
HPBYTE pchSrc; // pointer into source wave buffer
HPBYTE pchDst; // pointer into destination wave buffer
short * piSrc; // pointer into source wave buffer
short * piDst; // pointer into destination wave buffer
long lSamplesDst; // Samples to copy into destination buffer
long lDDA; // used to implement DDA algorithm
int iSample; // value of a waveform sample
long lSample; // value of a waveform sample
HMMIO hmmio;
BOOL fDirty = TRUE;
BOOL fStereoIn;
BOOL fStereoOut;
BOOL fEightIn;
BOOL fEightOut;
BOOL fEditWave = FALSE;
int iTemp;
int iTemp2;
OPENFILENAME ofn;
#ifdef DOWECARE
/* HACK from "server.c" to read objects without CF_WAVE */
extern WORD cfNative;
#endif
if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(gpWaveFormat))
return;
if (fPaste) {
MMIOINFO mmioinfo;
HANDLE h;
BeginWaveEdit();
if (!OpenClipboard(ghwndApp))
return;
LoadString(ghInst, IDS_CLIPBOARD, achFileName, SIZEOF(achFileName));
h = GetClipboardData(CF_WAVE);
#ifdef DOWECARE
if (!h) h = GetClipboardData(cfNative);
#endif
if (h) {
mmioinfo.fccIOProc = FOURCC_MEM;
mmioinfo.pIOProc = NULL;
mmioinfo.pchBuffer = GlobalLock(h);
mmioinfo.cchBuffer = (long)GlobalSize(h); // initial size
mmioinfo.adwInfo[0] = 0; // grow by this much
hmmio = mmioOpen(NULL, &mmioinfo, MMIO_READ);
}
else {
hmmio = NULL;
}
}
else {
BOOL f;
achFileName[0] = 0;
/* prompt user for file to open */
LoadString(ghInst, IDS_MIXWITHFILE, ach, SIZEOF(ach));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = ghwndApp;
ofn.hInstance = NULL;
ofn.lpstrFilter = aszFilter;
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0;
ofn.nFilterIndex = 1;
ofn.lpstrFile = achFileName;
ofn.nMaxFile = SIZEOF(achFileName);
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.lpstrTitle = ach;
ofn.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = NULL;
ofn.lCustData = 0;
ofn.lpfnHook = NULL;
ofn.lpTemplateName = NULL;
f = GetOpenFileName(&ofn); // get the filename for mixing
// see if we continue
if (!f)
goto RETURN_ERROR;
/* read the WAVE file */
hmmio = mmioOpen(achFileName, NULL, MMIO_READ | MMIO_ALLOCBUF);
}
if (hmmio != NULL)
{
MMRESULT mmr;
//
// show hourglass cursor
//
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
//
// read the WAVE file
//
mmr = ReadWaveFile( hmmio
, &pwfMix // wave format
, &cb // wave format size
, &pMixSamples // samples
, &lMixSamples // number of samples
, achFileName // file name for error
, FALSE ); // cache riff?
mmioClose(hmmio, 0);
if (mmr != MMSYSERR_NOERROR)
goto RETURN_ERROR;
if (lMixSamples == 0)
goto RETURN_SUCCESS;
if (pMixSamples == NULL)
goto RETURN_ERROR;
if (glWaveSamplesValid > 0 && !IsWaveFormatPCM(pwfMix)) {
ErrorResBox( ghwndApp
, ghInst
, MB_ICONEXCLAMATION | MB_OK
, IDS_APPTITLE
, fPaste ? IDS_CANTPASTE : IDS_NOTASUPPORTEDFILE
, (LPTSTR) achFileName
);
goto RETURN_ERROR;
}
}
else
{
ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
IDS_APPTITLE, IDS_ERROROPEN, (LPTSTR) achFileName);
goto RETURN_ERROR;
}
//jyg: moved
// BeginWaveEdit();
fEditWave = TRUE;
//
// if the current file is empty, treat the insert like a open
//
if (glWaveSamplesValid == 0)
{
DestroyWave();
gpWaveSamples = pMixSamples;
glWaveSamples = lMixSamples;
glWaveSamplesValid = lMixSamples;
gpWaveFormat = pwfMix;
gcbWaveFormat = cb;
pMixSamples = NULL;
pwfMix = NULL;
goto RETURN_SUCCESS;
}
fStereoIn = pwfMix->nChannels != 1;
fStereoOut = gpWaveFormat->nChannels != 1;
fEightIn = ((LPWAVEFORMATEX)pwfMix)->wBitsPerSample == 8;
fEightOut = ((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8;
/* figure out how many Samples need to be mixed in */
lSamplesToMix = MulDiv(lMixSamples, gpWaveFormat->nSamplesPerSec,
pwfMix->nSamplesPerSec);
lSamplesToAdd = lSamplesToMix - (glWaveSamplesValid - glWavePosition);
if (lSamplesToAdd < 0)
lSamplesToAdd = 0;
#ifdef DEBUG
DPF(TEXT("mix in %ld samples, converting from %ld Hz to %ld Hz\n"),
lMixSamples, pwfMix->nSamplesPerSec,
gpWaveFormat->nSamplesPerSec);
DPF(TEXT("so %ld Samples need to be mixed in at position %ld (add %ld)\n"),
lSamplesToMix, glWavePosition, lSamplesToAdd);
#endif
if (lSamplesToAdd > 0) {
/* mixing the specified file at the current location will
* require the current file's wave buffer to be expanded
* by <lSamplesToAdd>
*/
/* reallocate the WAVE buffer to be big enough */
if (!AllocWaveBuffer(glWaveSamplesValid + lSamplesToAdd,TRUE, TRUE))
goto RETURN_ERROR;
/* fill in the new part of the buffer with silence
*/
lSamplesDst = lSamplesToAdd;
/* If stereo, just twice as many samples
*/
if (fStereoOut)
lSamplesDst *= 2;
pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat,glWaveSamplesValid);
if (fEightOut) {
while (lSamplesDst-- > 0) {
// cast on lvalue eliminated
*((BYTE *) pchDst) = 128;
pchDst = (BYTE *)pchDst + 1;
}
}
else {
piDst = (short *) pchDst;
while (lSamplesDst-- > 0) {
*((short *) piDst) = 0;
piDst = (short *)piDst + 1;
}
}
glWaveSamplesValid += lSamplesToAdd;
}
/* mix the read-in WAVE file with the current file starting at the
* current position
*/
pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition);
piDst = (short *) pchDst;
lSamplesDst = lSamplesToMix;
pchSrc = pMixSamples;
piSrc = (short *) pchSrc;
lDDA = -((LONG)gpWaveFormat->nSamplesPerSec);
while (lSamplesDst > 0)
{
/* get a sample, convert to right format */
if (fEightIn) {
iTemp = (int) (unsigned char) *pchSrc;
if (fStereoIn) {
iTemp2 = (int) (unsigned char) *(pchSrc+1);
if (!fStereoOut) {
iTemp = (iTemp + iTemp2) / 2;
}
} else
iTemp2 = iTemp;
if (!fEightOut) {
iTemp = (iTemp - 128) << 8;
iTemp2 = (iTemp2 - 128) << 8;
}
} else {
iTemp = *piSrc;
if (fStereoIn) {
iTemp2 = *(piSrc+1);
if (!fStereoOut) {
iTemp = (int) ((((long) iTemp)
+ ((long) iTemp2)) / 2);
}
} else
iTemp2 = iTemp;
if (fEightOut) {
iTemp = (iTemp >> 8) + 128;
iTemp2 = (iTemp2 >> 8) + 128;
}
}
/* Output a sample */
if (fEightOut)
{
iSample = (int) *((BYTE *) pchDst)
+ iTemp - 128;
*((BYTE *) pchDst++) = (BYTE)
(iSample < 0 ? 0 :
(iSample > 255 ? 255 : iSample));
}
else
{
lSample = (long) *((short *) piDst)
+ (long) iTemp;
*((short *) piDst++) = (int)
(lSample < -32768L
? -32768 : (lSample > 32767L
? 32767 : (short) lSample));
}
if (fStereoOut) {
if (fEightOut)
{
iSample = (int) *((BYTE *) pchDst)
+ iTemp2 - 128;
*((BYTE *) pchDst++) = (BYTE)
(iSample < 0
? 0 : (iSample > 255
? 255 : iSample));
}
else
{
lSample = (long) *((short *) piDst)
+ (long) iTemp2;
*((short *) piDst++) = (short)
(lSample < -32768L
? -32768 : (lSample > 32767L
? 32767 : (short) lSample));
}
}
lSamplesDst--;
/* increment <pchSrc> at the correct rate so that the
* sampling rate of the input file is converted to match
* the sampling rate of the current file
*/
lDDA += pwfMix->nSamplesPerSec;
while (lDDA >= 0)
{
lDDA -= gpWaveFormat->nSamplesPerSec;
if (fEightIn)
pchSrc++;
else
piSrc++;
if (fStereoIn) {
if (fEightIn)
pchSrc++;
else
piSrc++;
}
}
}
#ifdef DEBUG
if (!fEightIn)
pchSrc = (HPBYTE) piSrc;
DPF(TEXT("copied %ld bytes from mix buffer\n"),
(long) (pchSrc - pMixSamples));
#endif
goto RETURN_SUCCESS;
RETURN_ERROR: // do error exit without error message
fDirty = FALSE;
RETURN_SUCCESS: // normal exit
if (fPaste)
CloseClipboard();
if (pMixSamples != NULL)
GlobalFreePtr(pMixSamples);
if (pwfMix != NULL)
GlobalFreePtr(pwfMix);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
if (fEditWave == TRUE)
EndWaveEdit(fDirty);
/* update the display */
UpdateDisplay(TRUE);
}
/* DeleteBefore()
*
* Delete samples before <glWavePosition>.
*/
void FAR PASCAL
DeleteBefore(void)
{
TCHAR ach[40];
long lTime;
int id;
if (glWavePosition == 0) // nothing to do?
return; // don't set dirty flag
BeginWaveEdit();
/* jyg - made this conditional because of rounding errors at
* the end of buffer case
*/
if (glWavePosition != glWaveSamplesValid)
glWavePosition = wfSamplesToSamples(gpWaveFormat, glWavePosition);
/* get the current wave position */
lTime = wfSamplesToTime(gpWaveFormat, glWavePosition);
if (gfLZero || ((int)(lTime/1000) != 0)) // ??? what are these casts ???
wsprintf(ach, aszSamplesFormat, (int)(lTime/1000), chDecimal, (int)((lTime/10)%100));
else
wsprintf(ach, aszSamplesNoZeroFormat, chDecimal, (int)((lTime/10)%100));
/* prompt user for permission */
id = ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OKCANCEL,
IDS_APPTITLE, IDS_DELBEFOREWARN, (LPTSTR) ach);
if (id != IDOK)
return;
/* copy the samples after <glWavePosition> to the beginning of
* the buffer
*/
memmove(gpWaveSamples,
gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWavePosition),
wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - glWavePosition));
/* reallocate the buffer to be <glWavePosition> samples smaller */
AllocWaveBuffer(glWaveSamplesValid - glWavePosition, TRUE, TRUE);
glWavePosition = 0L;
EndWaveEdit(TRUE);
/* update the display */
UpdateDisplay(TRUE);
} /* DeleteBefore */
/* DeleteAfter()
*
* Delete samples after <glWavePosition>.
*/
void FAR PASCAL
DeleteAfter(void)
{
TCHAR ach[40];
long lTime;
int id;
if (glWavePosition == glWaveSamplesValid) // nothing to do?
return; // don't set dirty flag
glWavePosition = wfSamplesToSamples(gpWaveFormat, glWavePosition);
BeginWaveEdit();
/* get the current wave position */
lTime = wfSamplesToTime(gpWaveFormat, glWavePosition);
if (gfLZero || ((int)(lTime/1000) != 0)) // ??? casts ???
wsprintf(ach, aszSamplesFormat, (int)(lTime/1000), chDecimal, (int)((lTime/10)%100));
else
wsprintf(ach, aszSamplesNoZeroFormat, chDecimal, (int)((lTime/10)%100));
/* prompt user for permission */
id = ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OKCANCEL,
IDS_APPTITLE, IDS_DELAFTERWARN, (LPTSTR) ach);
if (id != IDOK)
return;
/* reallocate the buffer to be <glWavePosition> samples in size */
AllocWaveBuffer(glWavePosition, TRUE, TRUE);
EndWaveEdit(TRUE);
/* update the display */
UpdateDisplay(TRUE);
} /* DeleteAfter */
/* ChangeVolume(fIncrease)
*
* Increase the volume (if <fIncrease> is TRUE) or decrease the volume
* (if <fIncrease> is FALSE) of samples in the wave buffer by CHVOL_DELTAVOLUME
* percent.
*/
void FAR PASCAL
ChangeVolume(BOOL fIncrease)
{
HPBYTE pch = gpWaveSamples; // ptr. into waveform buffer
long lSamples; // samples to modify
HCURSOR hcurPrev = NULL; // cursor before hourglass
int iFactor; // amount to multiply amplitude by
short * pi = (short *) gpWaveSamples;
if (glWaveSamplesValid == 0L) // nothing to do?
return; // don't set dirty flag
if (!IsWaveFormatPCM(gpWaveFormat))
return;
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
BeginWaveEdit();
/* for stereo, just twice as many samples */
lSamples = glWaveSamplesValid * gpWaveFormat->nChannels;
iFactor = 100 + (fIncrease ? CHVOL_INCDELTAVOLUME : -CHVOL_DECDELTAVOLUME);
if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8) {
/* 8-bit: samples 0-255 */
int iTemp;
while (lSamples-- > 0)
{
iTemp = ( ((short) *((BYTE *) pch) - 128)
* iFactor
)
/ 100 + 128;
*((BYTE *) pch++) = (BYTE)
(iTemp < 0 ? 0 : (iTemp > 255 ? 255 : iTemp));
}
} else {
/* 16-bit: samples -32768 - 32767 */
long lTemp;
while (lSamples-- > 0)
{
lTemp = (((long) *pi) * iFactor) / 100;
*(pi++) = (short) (lTemp < -32768L ? -32768 :
(lTemp > 32767L ?
32767 : (short) lTemp));
}
}
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
}
/* MakeFaster()
*
* Make the sound play twice as fast.
*/
void FAR PASCAL
MakeFaster(void)
{
HPBYTE pchSrc; // pointer into source part of buffer
HPBYTE pchDst; // pointer into destination part
short * piSrc;
short * piDst;
long lSamplesDst; // samples to copy into destination buffer
HCURSOR hcurPrev = NULL; // cursor before hourglass
if (glWaveSamplesValid == 0L) // nothing to do?
return; // don't set dirty flag
if (!IsWaveFormatPCM(gpWaveFormat))
return;
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
BeginWaveEdit();
/* move the current position so it will correspond to the same point
* in the audio before and after the change-pitch operation
*/
glWavePosition /= 2L;
/* delete every other sample */
lSamplesDst = glWaveSamplesValid / 2L;
if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8) {
pchSrc = pchDst = gpWaveSamples;
if (gpWaveFormat->nChannels == 1) {
while (lSamplesDst-- > 0)
{
*pchDst++ = *pchSrc++;
pchSrc++;
}
} else {
while (lSamplesDst-- > 0)
{
*pchDst++ = *pchSrc++;
*pchDst++ = *pchSrc++;
pchSrc++;
pchSrc++;
}
}
} else {
piSrc = piDst = (short *) gpWaveSamples;
if (gpWaveFormat->nChannels == 1) {
while (lSamplesDst-- > 0)
{
*piDst++ = *piSrc++;
piSrc++;
}
} else {
while (lSamplesDst-- > 0)
{
*piDst++ = *piSrc++;
*piDst++ = *piSrc++;
piSrc++;
piSrc++;
}
}
}
/* reallocate the WAVE buffer to be half as big enough */
//!!WinEval(AllocWaveBuffer(glWaveSamplesValid / 2L));
AllocWaveBuffer(glWaveSamplesValid / 2L, TRUE, TRUE);
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
}
/* MakeSlower()
*
* Make the sound play twice as slow.
*/
void FAR PASCAL
MakeSlower(void)
{
HPBYTE pchSrc; // pointer into source part of buffer
HPBYTE pchDst; // pointer into destination part
short * piSrc;
short * piDst;
long lSamplesSrc; // samples to copy from source buffer
HCURSOR hcurPrev = NULL; // cursor before hourglass
long lPrevPosition; // previous "current position"
int iSample; // current source sample
int iPrevSample; // previous sample (for interpolation)
int iSample2;
int iPrevSample2;
long lSample;
long lPrevSample;
long lSample2;
long lPrevSample2;
if (glWaveSamplesValid == 0L) // nothing to do?
return; // don't set dirty flag
if (!IsWaveFormatPCM(gpWaveFormat))
return;
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
BeginWaveEdit();
/* reallocate the WAVE buffer to be twice as big */
lPrevPosition = glWavePosition;
if (!AllocWaveBuffer(glWaveSamplesValid * 2L, TRUE, TRUE))
goto RETURN;
/* each source sample generates two destination samples;
* use interpolation to generate new samples; must go backwards
* through the buffer to avoid destroying data
*/
pchSrc = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid);
pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid * 2L);
lSamplesSrc = glWaveSamplesValid;
if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8)
{
if (gpWaveFormat->nChannels == 1)
{
iPrevSample = *((BYTE *) (pchSrc - 1));
while (lSamplesSrc-- > 0)
{
pchSrc = ((BYTE *) pchSrc) - 1;
iSample = *((BYTE *) pchSrc);
*--pchDst = (BYTE)((iSample + iPrevSample)/2);
*--pchDst = (BYTE) iSample;
iPrevSample = iSample;
}
}
else
{
iPrevSample = *((BYTE *) (pchSrc - 2));
iPrevSample2 = *((BYTE *) (pchSrc - 1));
while (lSamplesSrc-- > 0)
{
pchSrc = ((BYTE *) pchSrc)-1;
iSample2 = *((BYTE *) pchSrc);
pchSrc = ((BYTE *) pchSrc)-1;
iSample = *((BYTE *) pchSrc);
*--pchDst = (BYTE)((iSample2 + iPrevSample2)
/ 2);
*--pchDst = (BYTE)((iSample + iPrevSample)
/ 2);
*--pchDst = (BYTE) iSample2;
*--pchDst = (BYTE) iSample;
iPrevSample = iSample;
iPrevSample2 = iSample2;
}
}
}
else
{
piDst = (short *) pchDst;
piSrc = (short *) pchSrc;
if (gpWaveFormat->nChannels == 1)
{
lPrevSample = *(piSrc - 1);
while (lSamplesSrc-- > 0)
{
lSample = *--piSrc;
*--piDst = (short)((lSample + lPrevSample)/2);
*--piDst = (short) lSample;
lPrevSample = lSample;
}
}
else
{
lPrevSample = *(piSrc - 2);
lPrevSample2 = *(piSrc - 1);
while (lSamplesSrc-- > 0)
{
lSample2 = *--piSrc;
lSample = *--piSrc;
*--piDst = (short)((lSample2 + lPrevSample2)/2);
*--piDst = (short)((lSample + lPrevSample) / 2);
*--piDst = (short) lSample2;
*--piDst = (short) lSample;
lPrevSample = lSample;
lPrevSample2 = lSample2;
}
}
}
/* the entire buffer now contains valid samples */
glWaveSamplesValid *= 2L;
/* move the current position so it will correspond to the same point
* in the audio before and after the change-pitch operation
*/
glWavePosition = lPrevPosition * 2L;
//!!WinAssert(glWavePosition <= glWaveSamplesValid);
RETURN:
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
}
#if 0
/* pchNew = FindWave(pch, pchEnd, ppchWaveBuf)
*
* Assuming <pch> points within the wave buffer and <pchEnd> points past the
* end of the buffer, find the beginning of the next "wave", i.e. the point
* where the waveform starts rising (after it has fallen).
*
* <ppchWaveBuf> points to a pointer that points to a buffer that is filled
* in with a copy of the wave. The pointer <*ppchWaveBuf> is modified and
* upon return will point past the end of the wave.
*/
HPBYTE NEAR PASCAL
FindWave(HPBYTE pch, HPBYTE pchEnd, NPBYTE *ppchWaveBuf)
{
BYTE bLowest = 255;
BYTE bHighest = 0;
BYTE bLowPoint;
BYTE bHighPoint;
BYTE bDelta;
HPBYTE pchWalk;
BYTE b;
#ifdef VERBOSEDEBUG
NPBYTE pchWaveBufInit = *ppchWaveBuf;
#endif
if (pch == pchEnd)
return pch;
for (pchWalk = pch; pchWalk != pchEnd; pchWalk++)
{
b = *pchWalk;
b = *((BYTE *) pchWalk);
if (bLowest > b)
bLowest = b;
if (bHighest < b)
bHighest = b;
}
bDelta = (bHighest - bLowest) / FINDWAVE_PICKYNESS;
bLowPoint = bLowest + bDelta;
bHighPoint = bHighest - bDelta;
//!!WinAssert(bLowPoint >= bLowest);
//!!WinAssert(bHighPoint <= bHighest);
#ifdef VERBOSEDEBUG
DPF(TEXT("0x%08lX: %3d to %3d"), (DWORD) pch,
(int) bLowPoint, (int) bHighPoint);
#endif
if (bLowPoint == bHighPoint)
{
/* avoid infinite loop */
*(*ppchWaveBuf)++ = *((BYTE *) pch++);
#ifdef VERBOSEDEBUG
DPF(TEXT(" (equal)\n"));
#endif
return pch;
}
/* find a "peak" */
while ((pch != pchEnd) && (*((BYTE *) pch) < bHighPoint))
*(*ppchWaveBuf)++ = *((BYTE *) pch++);
/* find a "valley" */
while ((pch != pchEnd) && (*((BYTE *) pch) > bLowPoint))
*(*ppchWaveBuf)++ = *((BYTE *) pch++);
#ifdef VERBOSEDEBUG
DPF(TEXT(" (copied %d)\n"), *ppchWaveBuf - pchWaveBufInit);
#endif
return pch;
}
#endif
#if 0
/* IncreasePitch()
*
* Increase the pitch of samples in the wave buffer by one octave.
*/
void FAR PASCAL
IncreasePitch(void)
{
HCURSOR hcurPrev = NULL; // cursor before hourglass
HPBYTE pchEndFile; // end of file's buffer
HPBYTE pchStartWave; // start of one wave
HPBYTE pchMaxWave; // last place where wave may end
HPBYTE pchEndWave; // end an actual wave
char achWaveBuf[WAVEBUFSIZE];
NPBYTE pchWaveBuf;
NPBYTE pchSrc;
HPBYTE pchDst;
if (glWaveSamplesValid == 0L) // nothing to do?
return; // don't set dirty flag
if (!IsWaveFormatPCM(gpWaveFormat))
return;
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
BeginWaveEdit();
/* find each wave in the wave buffer and double it */
pchEndFile = gpWaveSamples + glWaveSamplesValid;
pchStartWave = gpWaveSamples;
while (TRUE)
{
pchMaxWave = pchStartWave + WAVEBUFSIZE;
if (pchMaxWave > pchEndFile)
pchMaxWave = pchEndFile;
pchWaveBuf = achWaveBuf;
pchEndWave = FindWave(pchStartWave, pchMaxWave, &pchWaveBuf);
pchSrc = achWaveBuf;
pchDst = pchStartWave;
if (pchSrc == pchWaveBuf)
break; // no samples copied
while (pchDst != pchEndWave)
{
*pchDst++ = *pchSrc++;
pchSrc++;
if (pchSrc >= pchWaveBuf)
{
if (pchSrc == pchWaveBuf)
pchSrc = achWaveBuf;
else
pchSrc = achWaveBuf + 1;
}
}
pchStartWave = pchEndWave;
}
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
}
#endif
#if 0
/* DecreasePitch()
*
* Decrease the pitch of samples in the wave buffer by one octave.
*/
void FAR PASCAL
DecreasePitch(void)
{
HCURSOR hcurPrev = NULL; // cursor before hourglass
HPBYTE pchEndFile; // end of file's buffer
HPBYTE pchStartWave; // start of one wave
HPBYTE pchMaxWave; // last place where wave may end
HPBYTE pchEndWave; // end an actual wave
char achWaveBuf[WAVEBUFSIZE];
NPBYTE pchWaveBuf; // end of first wave in <achWaveBuf>
NPBYTE pchSrc; // place to read samples from
NPBYTE pchSrcEnd; // end of place to read samples from
int iSample; // current source sample
int iPrevSample; // previous sample (for interpolation)
HPBYTE pchDst; // where result gets put in buffer
long lNewFileSize; // file size after pitch change
if (glWaveSamplesValid == 0L) // nothing to do?
return; // don't set dirty flag
if (!IsWaveFormatPCM(gpWaveFormat))
return;
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
BeginWaveEdit();
/* find each pair of waves in the wave buffer, discard the longer
* of the two waves, and expand the shorter of the two waves to
* twice its size
*/
pchEndFile = gpWaveSamples + glWaveSamplesValid;
pchStartWave = gpWaveSamples; // read waves from here
pchDst = gpWaveSamples; // write waves to here
while (TRUE)
{
pchMaxWave = pchStartWave + WAVEBUFSIZE;
if (pchMaxWave > pchEndFile)
pchMaxWave = pchEndFile;
/* read one wave -- make <pchWaveBuf> point to the end
* of the wave that's copied into <achWaveBuf>
*/
pchWaveBuf = achWaveBuf;
pchEndWave = FindWave(pchStartWave, pchMaxWave, &pchWaveBuf);
if (pchWaveBuf == achWaveBuf)
break;
/* read another wave -- make <pchWaveBuf> now point to the end
* of that wave that's copied into <achWaveBuf>
*/
pchEndWave = FindWave(pchEndWave, pchMaxWave, &pchWaveBuf);
pchSrc = achWaveBuf;
pchSrcEnd = achWaveBuf + ((pchWaveBuf - achWaveBuf) / 2);
iPrevSample = *((BYTE *) pchSrc);
while (pchSrc != pchSrcEnd)
{
iSample = *((BYTE *) pchSrc)++;
*pchDst++ = (BYTE) ((iSample + iPrevSample) / 2);
*pchDst++ = iSample;
iPrevSample = iSample;
}
pchStartWave = pchEndWave;
}
/* file may have shrunk */
lNewFileSize = pchDst - gpWaveSamples;
//!!WinAssert(lNewFileSize <= glWaveSamplesValid);
#ifdef DEBUG
DPF(TEXT("old file size is %ld, new size is %ld\n"),
glWaveSamplesValid, lNewFileSize);
#endif
AllocWaveBuffer(lNewFileSize, TRUE, TRUE);
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
}
#endif
/* AddEcho()
*
* Add echo to samples in the wave buffer.
*/
void FAR PASCAL
AddEcho(void)
{
HCURSOR hcurPrev = NULL; // cursor before hourglass
long lDeltaSamples; // no. samples for echo delay
long lSamples; // no. samples to modify
int iAmpSrc; // current source sample amplitude
int iAmpDst; // current destination sample amplitude
if (!IsWaveFormatPCM(gpWaveFormat))
return;
BeginWaveEdit();
/* figure out how many samples need to be modified */
lDeltaSamples = MulDiv((long) ECHO_DELAY,
gpWaveFormat->nSamplesPerSec, 1000L);
/* Set lSamples to be number of samples * number of channels */
lSamples = (glWaveSamplesValid - lDeltaSamples)
* gpWaveFormat->nChannels;
if (lSamples <= 0L) // nothing to do?
return; // don't set dirty flag
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
/* copy ECHO_VOLUME percent of each source sample (starting at
* ECHO_DELAY milliseconds from the end of the the buffer)
* to the each destination sample (starting at the end of the
* buffer)
*/
if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8)
{
HPBYTE pchSrc; // pointer into source part of buffer
HPBYTE pchDst; // pointer into destination part
int iSample; // destination sample
pchSrc = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - lDeltaSamples);
pchDst = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid);
while (lSamples-- > 0)
{
pchSrc = ((BYTE *) pchSrc) - 1;
iAmpSrc = (int) *((BYTE *) pchSrc) - 128;
pchDst = ((BYTE *) pchDst) - 1;
iAmpDst = (int) *((BYTE *) pchDst) - 128;
iSample = iAmpDst + (iAmpSrc * ECHO_VOLUME) / 100
+ 128;
*((BYTE *) pchDst) = (BYTE)
(iSample < 0 ? 0 : (iSample > 255
? 255 : iSample));
}
}
else
{
short * piSrc; // pointer into source part of buffer
short * piDst; // pointer into destination part
long lSample;// destination sample
piSrc = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - lDeltaSamples));
piDst = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid));
while (lSamples-- > 0)
{
iAmpSrc = *--piSrc;
iAmpDst = *--piDst;
lSample = ((long) iAmpSrc * ECHO_VOLUME) / 100 + (long) iAmpDst;
*piDst = (short) (lSample < -32768L
? -32768 : (lSample > 32767L
? 32767 : (short) lSample));
}
}
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
}
/* Reverse()
*
* Reverse samples in the wave buffer.
*/
void FAR PASCAL
Reverse(void)
{
HCURSOR hcurPrev = NULL; // cursor before hourglass
HPBYTE pchA, pchB; // pointers into buffer
short * piA;
short * piB;
long lSamples; // no. Samples to modify
char chTmp; // for swapping
int iTmp;
if (glWaveSamplesValid == 0L) // nothing to do?
return; // don't set dirty flag
if (!IsWaveFormatPCM(gpWaveFormat))
return;
BeginWaveEdit();
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
lSamples = glWaveSamplesValid / 2;
if (((LPWAVEFORMATEX)gpWaveFormat)->wBitsPerSample == 8)
{
pchA = gpWaveSamples;
if (gpWaveFormat->nChannels == 1)
{
pchB = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid);
while (lSamples-- > 0)
{
chTmp = *pchA;
*pchA++ = *--pchB;
*pchB = chTmp;
}
}
else
{
pchB = gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - 1);
while (lSamples-- > 0)
{
chTmp = *pchA;
*pchA = *pchB;
*pchB = chTmp;
chTmp = pchA[1];
pchA[1] = pchB[1];
pchB[1] = chTmp;
pchA += 2;
pchB -= 2;
}
}
}
else
{
piA = (short *) gpWaveSamples;
if (gpWaveFormat->nChannels == 1)
{
piB = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid));
while (lSamples-- > 0)
{
iTmp = *piA;
*piA++ = *--piB;
*piB = (short)iTmp;
}
}
else
{
piB = (short *) (gpWaveSamples + wfSamplesToBytes(gpWaveFormat, glWaveSamplesValid - 1));
while (lSamples-- > 0)
{
iTmp = *piA;
*piA = *piB;
*piB = (short)iTmp;
iTmp = piA[1];
piA[1] = piB[1];
piB[1] = (short)iTmp;
piA += 2;
piB -= 2;
}
}
}
/* move the current position so it corresponds to the same point
* in the audio as it did before the reverse operation
*/
glWavePosition = glWaveSamplesValid - glWavePosition;
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
}
#if defined(REVERB)
/* AddReverb()
*
* Add reverberation to samples in the wave buffer.
* Very similar to add echo, but instead of adding a single
* shot we
* 1. have multiple echoes
* 2. Have feedback so that each echo also generates an echo
* Danger: Because some of the echo times are short, there
* is likely to be high correlation between the wave
* at the source and destination points. In this case
* we don't get an echo at all, we get a resonance.
* The effect of a large hall DOES give resonances,
* but we should scatter them about to avoid making
* any sharp resonance.
* The first echo is also chosen to be long enough that
* its primary resonance will be below any normal speaking
* voice. 20mSec is 50Hz and an octave below bass range.
* Low levels of sound suffer badly from quantisation noise
* which can get quite bad. For this reason it's probably
* better to have the multipliers as powers of 2.
*
* Cheat: The reverb does NOT extend the total time (no realloc (yet).
*
* This takes a lot of compute - and is not really very much different
* in sound to AddEcho. Conclusion -- NOT IN PRODUCT.
*
*/
void FAR PASCAL
AddReverb(void)
{
HCURSOR hcurPrev = NULL; // cursor before hourglass
long lSamples; // no. samples to modify
int iAmpSrc; // current source sample amplitude
int iAmpDst; // current destination sample amplitude
int i;
typedef struct
{ long Offset; // delay in samples
long Delay; // delay in mSec
int Vol; // volume multiplier in units of 1/256
} ECHO;
#define CREVERB 3
ECHO Reverb[CREVERB] = { 0, 18, 64
, 0, 64, 64
};
if (!IsWaveFormatPCM(gpWaveFormat))
return;
BeginWaveEdit();
/* Convert millisec figures into samples */
for (i=0; i<CREVERB; ++i)
{ Reverb[i].Offset = MulDiv( Reverb[i].Delay
, gpWaveFormat->nSamplesPerSec
, 1000L
);
// I think this could have the effect of putting the reverb
// from one stereo channel onto the other one sometimes.
// It's a feature! (Fix is to make Offset always even)
}
if (lSamples <= 0L) // nothing to do?
return; // don't set dirty flag
/* show hourglass cursor */
hcurPrev = SetCursor(LoadCursor(NULL, IDC_WAIT));
lSamples = glWaveSamplesValid * gpWaveFormat->nChannels;
/* Work through the buffer left to right adding in the reverbs */
if (((LPPCMWAVEFORMAT)gpWaveFormat)->wBitsPerSample == 8)
{
BYTE * pbSrc; // pointer into source part of buffer
BYTE * pbDst; // pointer into destination part
int iSample; // destination sample
for (i=0; i<CREVERB; ++i)
{ long cSamp; // loop counter
int Vol = Reverb[i].Vol;
pbSrc = gpWaveSamples;
pbDst = gpWaveSamples+Reverb[i].Offset; // but elsewhere if realloc
cSamp = lSamples-Reverb[i].Offset;
while (cSamp-- > 0)
{
iAmpSrc = (*pbSrc) - 128;
iSample = *pbDst + MulDiv(iAmpSrc, Vol, 256);
*pbDst = (iSample < 0 ? 0 : (iSample > 255 ? 255 : iSample));
++pbSrc;
++pbDst;
}
}
}
else
{
int short * piSrc; // pointer into source part of buffer
int short * piDst; // pointer into destination part
long lSample;// destination sample
piSrc = gpWaveSamples;
piDst = gpWaveSamples;
while (lSamples-- > 0)
{
iAmpSrc = *piSrc;
for (i=0; i<CREVERB; ++i)
{ int short * piD = piDst + Reverb[i].Offset; // !!not win16
lSample = *piD + MulDiv(iAmpSrc, Reverb[i].Vol, 256);
*piDst = (short) ( lSample < -32768L
? -32768
: (lSample > 32767L ? 32767 : (short) lSample)
);
}
++piSrc;
++piDst;
}
}
EndWaveEdit(TRUE);
if (hcurPrev != NULL)
SetCursor(hcurPrev);
/* update the display */
UpdateDisplay(TRUE);
} /* AddReverb */
#endif //REVERB