Windows2003-3790/multimedia/directx/dmusic/dmsynth/instr.cpp
2020-09-30 16:53:55 +02:00

1725 lines
56 KiB
C++

//
// Copyright (c) 1996-2001 Microsoft Corporation
// Instrument.cpp
//
#ifdef DMSYNTH_MINIPORT
#include "common.h"
#else
#include "simple.h"
#include <mmsystem.h>
#include <dmerror.h>
#include "synth.h"
#include "math.h"
#include "debug.h"
// @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample. See ddkreadme.txt for more info.
#include "..\shared\validate.h"
#if 0 // The following section will only take affect in the DDK sample.
// @@END_DDKSPLIT
#include "validate.h"
// @@BEGIN_DDKSPLIT -- This section will be removed in the DDK sample.
#endif
// @@END_DDKSPLIT
#endif
void MemDump(char * prompt);
//#include <windowsx.h>
CSourceLFO::CSourceLFO()
{
m_pfFrequency = 3804; // f = (256*4096*16*5hz)/(samplerate)
m_stDelay = 0;
m_prMWPitchScale = 0;
m_vrMWVolumeScale = 0;
m_vrVolumeScale = 0;
m_prPitchScale = 0;
m_prCPPitchScale = 0;
m_vrCPVolumeScale = 0;
m_prCutoffScale = 0;
m_prMWCutoffScale = 0;
m_prCPCutoffScale = 0;
}
void CSourceLFO::Init(DWORD dwSampleRate)
{
m_pfFrequency = (256 * 4096 * 16 * 5) / dwSampleRate;
m_stDelay = 0;
m_prMWPitchScale = 0;
m_vrMWVolumeScale = 0;
m_vrVolumeScale = 0;
m_prPitchScale = 0;
m_prCPPitchScale = 0;
m_vrCPVolumeScale = 0;
m_prCutoffScale = 0;
m_prMWCutoffScale = 0;
m_prCPCutoffScale = 0;
}
void CSourceLFO::SetSampleRate(long lChange)
{
if (lChange > 0)
{
m_stDelay <<= lChange;
m_pfFrequency <<= lChange;
}
else
{
m_stDelay >>= -lChange;
m_pfFrequency >>= -lChange;
}
}
void CSourceLFO::Verify()
{
FORCEBOUNDS(m_pfFrequency,64,7600);
FORCEBOUNDS(m_stDelay,0,441000);
FORCEBOUNDS(m_vrVolumeScale,-1200,1200);
FORCEBOUNDS(m_vrMWVolumeScale,-1200,1200);
FORCEBOUNDS(m_prPitchScale,-1200,1200);
FORCEBOUNDS(m_prMWPitchScale,-1200,1200);
FORCEBOUNDS(m_prCPPitchScale,-1200,1200);
FORCEBOUNDS(m_vrCPVolumeScale,-1200,1200);
FORCEBOUNDS(m_prCutoffScale, -12800, 12800);
FORCEBOUNDS(m_prMWCutoffScale, -12800, 12800);
FORCEBOUNDS(m_prCPCutoffScale, -12800, 12800);
}
CSourceEG::CSourceEG()
{
Init();
}
void CSourceEG::Init()
{
m_stAttack = 0;
m_stDecay = 0;
m_pcSustain = 1000;
m_stRelease = 0;
m_trVelAttackScale = 0;
m_trKeyDecayScale = 0;
m_sScale = 0;
m_stDelay = 0;
m_stHold = 0;
m_prCutoffScale = 0;
}
void CSourceEG::SetSampleRate(long lChange)
{
if (lChange > 0)
{
m_stAttack <<= lChange;
m_stDecay <<= lChange;
m_stRelease <<= lChange;
}
else
{
m_stAttack >>= -lChange;
m_stDecay >>= -lChange;
m_stRelease >>= -lChange;
}
}
void CSourceEG::Verify()
{
FORCEBOUNDS(m_stAttack,0,1764000);
FORCEBOUNDS(m_stDecay,0,1764000);
FORCEBOUNDS(m_pcSustain,0,1000);
FORCEBOUNDS(m_stRelease,0,1764000);
FORCEBOUNDS(m_sScale,-1200,1200);
FORCEBOUNDS(m_trKeyDecayScale,-12000,12000);
FORCEBOUNDS(m_trVelAttackScale,-12000,12000);
FORCEBOUNDS(m_trKeyHoldScale,-12000,12000);
FORCEBOUNDS(m_prCutoffScale,-12800,12800);
}
CSourceFilter::CSourceFilter()
{
Init(22050);
}
void CSourceFilter::Init(DWORD dwSampleRate)
{
// First, calculate the playback samplerate in pitch rels.
// The reference frequency is a440, which is midi note 69.
// So, calculate the ratio of the sample rate to 440 and
// convert into prels (1200 per octave), then add the
// offset of 6900.
double fSampleRate = (double)dwSampleRate;
fSampleRate /= 440.0;
fSampleRate = log(fSampleRate) / log(2.0);
fSampleRate *= 1200.0;
fSampleRate += 6900.0;
m_prSampleRate = (PRELS)fSampleRate;
m_prCutoff = (PRELS)0x7FFF;
m_vrQ = (VRELS)0;
m_prVelScale = (PRELS)0;
m_prCutoffSRAdjust = 0;
m_iQIndex = 0;
}
void CSourceFilter::SetSampleRate(LONG lChange)
{
// lChange == 1 -> doubles -> add 1200 cents
// lChange == 2 -> quad -> add 2400 cents
// lChange == -1 -> halves -> sub 1200 cents
// lChange == -2 -> 1/4ths -> sub 2400 cents
//
if (lChange > 0)
{
m_prSampleRate += (1200 << (lChange - 1));
}
else
{
m_prSampleRate -= (1200 << ((-lChange) - 1));
}
m_prCutoffSRAdjust = FILTER_FREQ_RANGE - m_prSampleRate + m_prCutoff;
}
void CSourceFilter::Verify()
{
if ( m_prCutoff == 0x7FFF )
{
m_vrQ = 0;
m_prVelScale = 0;
}
else
{
FORCEBOUNDS(m_prCutoff, 5535, 11921);
FORCEBOUNDS(m_vrQ, 0, 225);
FORCEBOUNDS(m_prVelScale, -12800, 12800);
}
}
CSourceArticulation::CSourceArticulation()
{
// m_sVelToVolScale = -9600;
m_wUsageCount = 0;
m_sDefaultPan = 0;
m_dwSampleRate = 22050;
m_PitchEG.m_sScale = 0; // pitch envelope defaults to off
}
void CSourceArticulation::Init(DWORD dwSampleRate)
{
m_dwSampleRate = dwSampleRate;
m_LFO.Init(dwSampleRate); // Set to default values.
m_PitchEG.Init();
m_VolumeEG.Init();
m_LFO2.Init(dwSampleRate);
m_Filter.Init(dwSampleRate);
}
void CSourceArticulation::SetSampleRate(DWORD dwSampleRate)
{
if (dwSampleRate != m_dwSampleRate)
{
long lChange;
if (dwSampleRate > (m_dwSampleRate * 2))
{
lChange = 2; // going from 11 to 44.
}
else if (dwSampleRate > m_dwSampleRate)
{
lChange = 1; // must be doubling
}
else if ((dwSampleRate * 2) < m_dwSampleRate)
{
lChange = -2; // going from 44 to 11
}
else
{
lChange = -1; // that leaves halving.
}
m_dwSampleRate = dwSampleRate;
m_LFO.SetSampleRate(lChange);
m_PitchEG.SetSampleRate(lChange);
m_VolumeEG.SetSampleRate(lChange);
m_LFO2.SetSampleRate(lChange);
m_Filter.SetSampleRate(lChange);
}
}
void CSourceArticulation::Verify()
{
m_LFO.Verify();
m_PitchEG.Verify();
m_VolumeEG.Verify();
m_LFO2.Verify();
m_Filter.Verify();
}
void CSourceArticulation::AddRef()
{
m_wUsageCount++;
}
void CSourceArticulation::Release()
{
m_wUsageCount--;
if (m_wUsageCount == 0)
{
delete this;
}
}
CSourceSample::CSourceSample()
{
m_pWave = NULL;
m_dwLoopStart = 0;
m_dwLoopEnd = 1;
m_dwLoopType = WLOOP_TYPE_FORWARD;
m_dwSampleLength = 0;
m_prFineTune = 0;
m_dwSampleRate = 22050;
m_bMIDIRootKey = 60;
m_bOneShot = TRUE;
m_bSampleType = 0;
}
CSourceSample::~CSourceSample()
{
if (m_pWave != NULL)
{
m_pWave->Release();
}
}
void CSourceSample::Verify()
{
if (m_pWave != NULL)
{
FORCEBOUNDS(m_dwSampleLength,0,m_pWave->m_dwSampleLength);
FORCEBOUNDS(m_dwLoopEnd,1,m_dwSampleLength);
FORCEBOUNDS(m_dwLoopStart,0,m_dwLoopEnd);
if ((m_dwLoopEnd - m_dwLoopStart) < 6)
{
m_bOneShot = TRUE;
}
}
FORCEBOUNDS(m_dwSampleRate,3000,200000);
FORCEBOUNDS(m_bMIDIRootKey,0,127);
FORCEBOUNDS(m_prFineTune,-1200,1200);
}
BOOL CSourceSample::CopyFromWave()
{
if (m_pWave == NULL)
{
return FALSE;
}
m_dwSampleLength = m_pWave->m_dwSampleLength;
m_dwSampleRate = m_pWave->m_dwSampleRate;
m_bSampleType = m_pWave->m_bSampleType;
if (m_bOneShot)
{
m_dwSampleLength--;
if (m_pWave->m_bSampleType & SFORMAT_16)
{
m_pWave->m_pnWave[m_dwSampleLength] = 0;
}
else
{
char *pBuffer = (char *) m_pWave->m_pnWave;
pBuffer[m_dwSampleLength] = 0;
}
}
else
{
if (m_dwLoopStart >= m_dwSampleLength)
{
m_dwLoopStart = 0;
}
if (m_pWave->m_bSampleType & SFORMAT_16)
{
m_pWave->m_pnWave[m_dwSampleLength-1] =
m_pWave->m_pnWave[m_dwLoopStart];
}
else
{
char *pBuffer = (char *) m_pWave->m_pnWave;
pBuffer[m_dwSampleLength-1] =
pBuffer[m_dwLoopStart];
}
}
Verify();
return (TRUE);
}
CWave::CWave()
{
m_hUserData = NULL;
m_lpFreeHandle = NULL;
m_pnWave = NULL;
m_dwSampleRate = 22050;
m_bSampleType = SFORMAT_16;
m_dwSampleLength = 0;
m_wUsageCount = 0;
m_dwID = 0;
m_wPlayCount = 0;
m_bStream = FALSE;
m_bActive = FALSE;
m_bLastSampleInit = FALSE;
m_bValid = FALSE;
}
CWave::~CWave()
{
if (m_pnWave && m_lpFreeHandle)
{
m_lpFreeHandle((HANDLE) this,m_hUserData);
}
}
void CWave::Verify()
{
FORCEBOUNDS(m_dwSampleRate,3000,200000);
}
void CWave::PlayOn()
{
m_wPlayCount++;
AddRef();
}
void CWave::PlayOff()
{
m_wPlayCount--;
Release();
}
BOOL CWave::IsPlaying()
{
return (m_wPlayCount);
}
void CWave::AddRef()
{
m_wUsageCount++;
}
void CWave::Release()
{
m_wUsageCount--;
if (m_wUsageCount == 0)
{
delete this;
}
}
CWaveArt::CWaveArt()
{
m_wUsageCount = 1;
m_dwID = 0;
m_bSampleType = 0;
m_bStream = FALSE;
memset(&m_WaveArtDl,0,sizeof(DMUS_WAVEARTDL));
memset(&m_WaveformatEx,0,sizeof(WAVEFORMATEX));
}
CWaveArt::~CWaveArt()
{
//>>>>>>>>>> clear list
while(!m_pWaves.IsEmpty())
{
CWaveBuffer* pWaveBuffer = m_pWaves.RemoveHead();
if(pWaveBuffer)
{
pWaveBuffer->m_pWave->Release();
pWaveBuffer->m_pWave = NULL;
delete pWaveBuffer;
}
}
}
void CWaveArt::AddRef()
{
m_wUsageCount++;
}
void CWaveArt::Release()
{
m_wUsageCount--;
if (m_wUsageCount == 0)
{
delete this;
}
}
void CWaveArt::Verify()
{
}
CSourceRegion::CSourceRegion()
{
m_pArticulation = NULL;
m_vrAttenuation = 0;
m_prTuning = 0;
m_bKeyHigh = 127;
m_bKeyLow = 0;
m_bGroup = 0;
m_bAllowOverlap = FALSE;
m_bVelocityHigh = 127;
m_bVelocityLow = 0;
m_dwChannel = 0;
m_sWaveLinkOptions = 0;
}
CSourceRegion::~CSourceRegion()
{
if (m_pArticulation)
{
m_pArticulation->Release();
}
}
void CSourceRegion::SetSampleRate(DWORD dwSampleRate)
{
if (m_pArticulation != NULL)
{
m_pArticulation->SetSampleRate(dwSampleRate);
}
}
void CSourceRegion::Verify()
{
FORCEBOUNDS(m_bKeyHigh,0,127);
FORCEBOUNDS(m_bKeyLow,0,127);
FORCEBOUNDS(m_prTuning,-12000,12000);
FORCEBOUNDS(m_vrAttenuation,-9600,0);
m_Sample.Verify();
if (m_pArticulation != NULL)
{
m_pArticulation->Verify();
}
}
CInstrument::CInstrument()
{
m_dwProgram = 0;
}
CInstrument::~CInstrument()
{
while (!m_RegionList.IsEmpty())
{
CSourceRegion *pRegion = m_RegionList.RemoveHead();
delete pRegion;
}
}
void CInstrument::Verify()
{
CSourceRegion *pRegion = m_RegionList.GetHead();
CSourceArticulation *pArticulation = NULL;
for (;pRegion != NULL;pRegion = pRegion->GetNext())
{
if (pRegion->m_pArticulation != NULL)
{
pArticulation = pRegion->m_pArticulation;
}
pRegion->Verify();
}
pRegion = m_RegionList.GetHead();
for (;pRegion != NULL;pRegion = pRegion->GetNext())
{
if (pRegion->m_pArticulation == NULL && pArticulation)
{
pRegion->m_pArticulation = pArticulation;
pArticulation->AddRef();
}
}
}
void CInstrument::SetSampleRate(DWORD dwSampleRate)
{
CSourceRegion *pRegion = m_RegionList.GetHead();
for (;pRegion;pRegion = pRegion->GetNext())
{
pRegion->SetSampleRate(dwSampleRate);
}
}
CSourceRegion * CInstrument::ScanForRegion(DWORD dwNoteValue, DWORD dwVelocity, CSourceRegion *pRegion)
{
if ( pRegion == NULL )
pRegion = m_RegionList.GetHead(); // Starting search
else
pRegion = pRegion->GetNext(); // Continuing search through the rest of the regions
for (;pRegion;pRegion = pRegion->GetNext())
{
if (dwNoteValue >= pRegion->m_bKeyLow &&
dwNoteValue <= pRegion->m_bKeyHigh &&
dwVelocity >= pRegion->m_bVelocityLow &&
dwVelocity <= pRegion->m_bVelocityHigh )
{
break ;
}
}
return pRegion;
}
void CInstManager::SetSampleRate(DWORD dwSampleRate)
{
DWORD dwIndex;
m_dwSampleRate = dwSampleRate;
EnterCriticalSection(&m_CriticalSection);
for (dwIndex = 0; dwIndex < INSTRUMENT_HASH_SIZE; dwIndex++)
{
CInstrument *pInstrument = m_InstrumentList[dwIndex].GetHead();
for (;pInstrument != NULL; pInstrument = pInstrument->GetNext())
{
pInstrument->SetSampleRate(dwSampleRate);
}
}
LeaveCriticalSection(&m_CriticalSection);
}
CInstManager::CInstManager()
{
m_dwSampleRate = 22050;
m_fCSInitialized = FALSE;
InitializeCriticalSection(&m_CriticalSection);
// Note: on pre-Blackcomb OS's, this call can raise an exception; if it
// ever pops in stress, we can add an exception handler and retry loop.
m_fCSInitialized = TRUE;
m_dwSynthMemUse = 0;
}
CInstManager::~CInstManager()
{
if (m_fCSInitialized)
{
DWORD dwIndex;
for (dwIndex = 0; dwIndex < INSTRUMENT_HASH_SIZE; dwIndex++)
{
while (!m_InstrumentList[dwIndex].IsEmpty())
{
CInstrument *pInstrument = m_InstrumentList[dwIndex].RemoveHead();
delete pInstrument;
}
}
for (dwIndex = 0; dwIndex < WAVE_HASH_SIZE; dwIndex++)
{
while (!m_WavePool[dwIndex].IsEmpty())
{
CWave *pWave = m_WavePool[dwIndex].RemoveHead();
pWave->Release();
}
}
while (!m_FreeWavePool.IsEmpty())
{
CWave *pWave = m_FreeWavePool.RemoveHead();
pWave->Release();
}
for(int nCount = 0; nCount < WAVEART_HASH_SIZE; nCount++)
{
while(!m_WaveArtList[nCount].IsEmpty())
{
CWaveArt* pWaveArt = m_WaveArtList[nCount].RemoveHead();
if(pWaveArt)
{
pWaveArt->Release();
}
}
}
DeleteCriticalSection(&m_CriticalSection);
}
}
void CInstManager::Verify()
{
DWORD dwIndex;
EnterCriticalSection(&m_CriticalSection);
for (dwIndex = 0;dwIndex < INSTRUMENT_HASH_SIZE; dwIndex++)
{
CInstrument *pInstrument = m_InstrumentList[dwIndex].GetHead();
for (;pInstrument != NULL;pInstrument = pInstrument->GetNext())
{
pInstrument->Verify();
}
}
LeaveCriticalSection(&m_CriticalSection);
}
CInstrument * CInstManager::GetInstrument(DWORD dwProgram, DWORD dwKey, DWORD dwVelocity)
{
EnterCriticalSection(&m_CriticalSection);
CInstrument *pInstrument = m_InstrumentList[dwProgram % INSTRUMENT_HASH_SIZE].GetHead();
for (;pInstrument != NULL; pInstrument = pInstrument->GetNext())
{
if (pInstrument->m_dwProgram == dwProgram)
{
if (pInstrument->ScanForRegion(dwKey, dwVelocity, NULL) != NULL)
{
break;
}
else
{
Trace(2,"Warning: No region was found in instrument # %lx that matched note %ld\n",
dwProgram,dwKey);
}
}
}
LeaveCriticalSection(&m_CriticalSection);
return (pInstrument);
}
DWORD TimeCents2Samples(long tcTime, DWORD dwSampleRate)
{
if (tcTime == 0x80000000) return (0);
double flTemp = tcTime;
flTemp /= (65536 * 1200);
flTemp = pow(2.0,flTemp);
flTemp *= dwSampleRate;
return (DWORD) flTemp;
}
DWORD PitchCents2PitchFract(long pcRate,DWORD dwSampleRate)
{
double fTemp = pcRate;
fTemp /= 65536;
fTemp -= 6900;
fTemp /= 1200;
fTemp = pow(2.0,fTemp);
fTemp *= 7381975040.0; // (440*256*16*4096);
fTemp /= dwSampleRate;
return (DWORD) (fTemp);
}
HRESULT CSourceArticulation::Download(DMUS_DOWNLOADINFO * pInfo,
void * pvOffsetTable[],
DWORD dwIndex,
DWORD dwSampleRate,
BOOL fNewFormat)
{
if (fNewFormat)
{
DMUS_ARTICULATION2 * pdmArtic =
(DMUS_ARTICULATION2 *) pvOffsetTable[dwIndex];
while (pdmArtic)
{
if (pdmArtic->ulArtIdx)
{
if (pdmArtic->ulArtIdx >= pInfo->dwNumOffsetTableEntries)
{
Trace(1,"Error: Download failed because articulation chunk has an error.\n");
return DMUS_E_BADARTICULATION;
}
DWORD dwPosition;
void *pData = pvOffsetTable[pdmArtic->ulArtIdx];
CONNECTIONLIST * pConnectionList =
(CONNECTIONLIST *) pData;
CONNECTION *pConnection;
dwPosition = sizeof(CONNECTIONLIST);
for (dwIndex = 0; dwIndex < pConnectionList->cConnections; dwIndex++)
{
pConnection = (CONNECTION *) ((BYTE *)pData + dwPosition);
dwPosition += sizeof(CONNECTION);
switch (pConnection->usSource)
{
case CONN_SRC_NONE :
switch (pConnection->usDestination)
{
case CONN_DST_LFO_FREQUENCY :
m_LFO.m_pfFrequency = PitchCents2PitchFract(
pConnection->lScale,dwSampleRate);
break;
case CONN_DST_LFO_STARTDELAY :
m_LFO.m_stDelay = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG1_ATTACKTIME :
m_VolumeEG.m_stAttack = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG1_DECAYTIME :
m_VolumeEG.m_stDecay = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG1_SUSTAINLEVEL :
m_VolumeEG.m_pcSustain =
(SPERCENT) ((long) (pConnection->lScale >> 16));
break;
case CONN_DST_EG1_RELEASETIME :
m_VolumeEG.m_stRelease = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG2_ATTACKTIME :
m_PitchEG.m_stAttack = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG2_DECAYTIME :
m_PitchEG.m_stDecay = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG2_SUSTAINLEVEL :
m_PitchEG.m_pcSustain =
(SPERCENT) ((long) (pConnection->lScale >> 16));
break;
case CONN_DST_EG2_RELEASETIME :
m_PitchEG.m_stRelease = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_PAN :
m_sDefaultPan = (short)
((long) ((long) pConnection->lScale >> 12) / 125);
break;
/* DLS2 */
case CONN_DST_EG1_DELAYTIME:
m_VolumeEG.m_stDelay = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG1_HOLDTIME:
m_VolumeEG.m_stHold = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG2_DELAYTIME:
m_PitchEG.m_stDelay = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_EG2_HOLDTIME:
m_PitchEG.m_stHold = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_VIB_FREQUENCY :
m_LFO2.m_pfFrequency = PitchCents2PitchFract(
pConnection->lScale,dwSampleRate);
break;
case CONN_DST_VIB_STARTDELAY :
m_LFO2.m_stDelay = TimeCents2Samples(
(TCENT) pConnection->lScale,dwSampleRate);
break;
case CONN_DST_FILTER_CUTOFF:
// First, get the filter cutoff frequency, which is relative to a440.
m_Filter.m_prCutoff = (PRELS)
(pConnection->lScale >> 16);
// Then, calculate the resulting prel, taking into consideration
// the sample rate and the base of the filter coefficient lookup
// table, relative to the sample rate (FILTER_FREQ_RANGE).
// This number can then be used directly look up the coefficients in the
// filter table.
m_Filter.m_prCutoffSRAdjust = (PRELS)
FILTER_FREQ_RANGE - m_Filter.m_prSampleRate + m_Filter.m_prCutoff;
break;
case CONN_DST_FILTER_Q:
m_Filter.m_vrQ = (VRELS)
(pConnection->lScale >> 16); //>>>>>>>> not really VRELS, but 1/10th's
m_Filter.m_iQIndex = (DWORD)
((m_Filter.m_vrQ / 15.0f) + 0.5f);
break;
}
break;
case CONN_SRC_LFO :
switch (pConnection->usControl)
{
case CONN_SRC_NONE :
switch (pConnection->usDestination)
{
case CONN_DST_ATTENUATION :
m_LFO.m_vrVolumeScale = (VRELS)
((long) ((pConnection->lScale * 10) >> 16));
break;
case CONN_DST_PITCH :
m_LFO.m_prPitchScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
/* DLS2 */
case CONN_DST_FILTER_CUTOFF:
m_LFO.m_prCutoffScale = (PRELS)
(pConnection->lScale >> 16);
break;
}
break;
case CONN_SRC_CC1 :
switch (pConnection->usDestination)
{
case CONN_DST_ATTENUATION :
m_LFO.m_vrMWVolumeScale = (VRELS)
((long) ((pConnection->lScale * 10) >> 16));
break;
case CONN_DST_PITCH :
m_LFO.m_prMWPitchScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
/* DLS2 */
case CONN_DST_FILTER_CUTOFF:
m_LFO.m_prMWCutoffScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
/* DLS2 */
case CONN_SRC_CHANNELPRESSURE :
switch (pConnection->usDestination)
{
case CONN_DST_ATTENUATION :
m_LFO.m_vrCPVolumeScale = (VRELS)
((long) (pConnection->lScale >> 16));
break;
case CONN_DST_PITCH :
m_LFO.m_prCPPitchScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
/* DLS2 */
case CONN_DST_FILTER_CUTOFF:
m_LFO.m_prCPCutoffScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
}
break;
case CONN_SRC_KEYONVELOCITY :
switch (pConnection->usDestination)
{
case CONN_DST_EG1_ATTACKTIME :
m_VolumeEG.m_trVelAttackScale = (TRELS)
((long) (pConnection->lScale >> 16));
break;
case CONN_DST_EG2_ATTACKTIME :
m_PitchEG.m_trVelAttackScale = (TRELS)
((long) (pConnection->lScale >> 16));
break;
/* DLS2 */
case CONN_DST_FILTER_CUTOFF:
m_Filter.m_prVelScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
case CONN_SRC_KEYNUMBER :
switch (pConnection->usDestination)
{
case CONN_DST_EG1_DECAYTIME :
m_VolumeEG.m_trKeyDecayScale = (TRELS)
((long) (pConnection->lScale >> 16));
break;
case CONN_DST_EG2_DECAYTIME :
m_PitchEG.m_trKeyDecayScale = (TRELS)
((long) (pConnection->lScale >> 16));
break;
/* DLS2 */
case CONN_DST_EG1_HOLDTIME :
m_PitchEG.m_trKeyDecayScale = (TRELS)
((long) (pConnection->lScale >> 16));
break;
case CONN_DST_EG2_HOLDTIME :
m_PitchEG.m_trKeyDecayScale = (TRELS)
((long) (pConnection->lScale >> 16));
case CONN_DST_FILTER_CUTOFF :
m_Filter.m_prKeyScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
case CONN_SRC_EG2 :
switch (pConnection->usDestination)
{
case CONN_DST_PITCH :
m_PitchEG.m_sScale = (short)
((long) (pConnection->lScale >> 16));
break;
/* DLS2 */
case CONN_DST_FILTER_CUTOFF:
m_PitchEG.m_prCutoffScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
/* DLS2 */
case CONN_SRC_VIBRATO :
switch (pConnection->usControl)
{
case CONN_SRC_NONE :
switch (pConnection->usDestination)
{
case CONN_DST_PITCH :
m_LFO2.m_prPitchScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
case CONN_SRC_CC1 :
switch (pConnection->usDestination)
{
case CONN_DST_PITCH :
m_LFO2.m_prMWPitchScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
case CONN_SRC_CHANNELPRESSURE :
switch (pConnection->usDestination)
{
case CONN_DST_PITCH :
m_LFO2.m_prCPPitchScale = (PRELS)
((long) (pConnection->lScale >> 16));
break;
}
break;
}
break;
}
}
}
if (pdmArtic->ulNextArtIdx)
{
if (pdmArtic->ulNextArtIdx >= pInfo->dwNumOffsetTableEntries)
{
Trace(1,"Error: Download failed because articulation chunk has an error.\n");
return DMUS_E_BADARTICULATION;
}
pdmArtic = (DMUS_ARTICULATION2 *) pvOffsetTable[pdmArtic->ulNextArtIdx];
}
else
{
pdmArtic = NULL;
}
}
}
else
{
DMUS_ARTICULATION * pdmArtic =
(DMUS_ARTICULATION *) pvOffsetTable[dwIndex];
if (pdmArtic->ulArt1Idx)
{
if (pdmArtic->ulArt1Idx >= pInfo->dwNumOffsetTableEntries)
{
Trace(1,"Error: Download failed because articulation chunk has an error.\n");
return DMUS_E_BADARTICULATION;
}
DMUS_ARTICPARAMS * pdmArticParams =
(DMUS_ARTICPARAMS *) pvOffsetTable[pdmArtic->ulArt1Idx];
m_LFO.m_pfFrequency = PitchCents2PitchFract(
pdmArticParams->LFO.pcFrequency,dwSampleRate);
m_LFO.m_stDelay = TimeCents2Samples(
(TCENT) pdmArticParams->LFO.tcDelay,dwSampleRate);
m_LFO.m_vrVolumeScale = (VRELS)
((long) ((pdmArticParams->LFO.gcVolumeScale * 10) >> 16));
m_LFO.m_prPitchScale = (PRELS)
((long) (pdmArticParams->LFO.pcPitchScale >> 16));
m_LFO.m_vrMWVolumeScale = (VRELS)
((long) ((pdmArticParams->LFO.gcMWToVolume * 10) >> 16));
m_LFO.m_prMWPitchScale = (PRELS)
((long) (pdmArticParams->LFO.pcMWToPitch >> 16));
m_VolumeEG.m_stAttack = TimeCents2Samples(
(TCENT) pdmArticParams->VolEG.tcAttack,dwSampleRate);
m_VolumeEG.m_stDecay = TimeCents2Samples(
(TCENT) pdmArticParams->VolEG.tcDecay,dwSampleRate);
m_VolumeEG.m_pcSustain =
(SPERCENT) ((long) (pdmArticParams->VolEG.ptSustain >> 16));
m_VolumeEG.m_stRelease = TimeCents2Samples(
(TCENT) pdmArticParams->VolEG.tcRelease,dwSampleRate);
m_VolumeEG.m_trVelAttackScale = (TRELS)
((long) (pdmArticParams->VolEG.tcVel2Attack >> 16));
m_VolumeEG.m_trKeyDecayScale = (TRELS)
((long) (pdmArticParams->VolEG.tcKey2Decay >> 16));
m_PitchEG.m_trKeyDecayScale = (TRELS)
((long) (pdmArticParams->PitchEG.tcKey2Decay >> 16));
m_PitchEG.m_sScale = (short)
((long) (pdmArticParams->PitchEG.pcRange >> 16));
m_PitchEG.m_trVelAttackScale = (TRELS)
((long) (pdmArticParams->PitchEG.tcVel2Attack >> 16));
m_PitchEG.m_stAttack = TimeCents2Samples(
(TCENT) pdmArticParams->PitchEG.tcAttack,dwSampleRate);
m_PitchEG.m_stDecay = TimeCents2Samples(
(TCENT) pdmArticParams->PitchEG.tcDecay,dwSampleRate);
m_PitchEG.m_pcSustain =
(SPERCENT) ((long) (pdmArticParams->PitchEG.ptSustain >> 16));
m_PitchEG.m_stRelease = TimeCents2Samples(
(TCENT) pdmArticParams->PitchEG.tcRelease,dwSampleRate);
m_sDefaultPan = (short)
((long) ((long) pdmArticParams->Misc.ptDefaultPan >> 12) / 125);
}
}
Verify(); // Make sure all parameters are legal.
return S_OK;
}
HRESULT CSourceRegion::Download(DMUS_DOWNLOADINFO * pInfo,
void * pvOffsetTable[],
DWORD *pdwRegionIX,
DWORD dwSampleRate,
BOOL fNewFormat)
{
DMUS_REGION * pdmRegion = (DMUS_REGION *) pvOffsetTable[*pdwRegionIX];
*pdwRegionIX = pdmRegion->ulNextRegionIdx; // Clear to avoid loops.
pdmRegion->ulNextRegionIdx = 0;
// Read the Region chunk...
m_bKeyHigh = (BYTE) pdmRegion->RangeKey.usHigh;
m_bKeyLow = (BYTE) pdmRegion->RangeKey.usLow;
m_bVelocityHigh = (BYTE) pdmRegion->RangeVelocity.usHigh;
m_bVelocityLow = (BYTE) pdmRegion->RangeVelocity.usLow;
//
// Fix DLS Designer bug
// Designer was putting velocity ranges that fail
// on DLS2 synths
//
if ( m_bVelocityHigh == 0 && m_bVelocityLow == 0 )
m_bVelocityHigh = 127;
if (pdmRegion->fusOptions & F_RGN_OPTION_SELFNONEXCLUSIVE)
{
m_bAllowOverlap = TRUE;
}
else
{
m_bAllowOverlap = FALSE;
}
m_bGroup = (BYTE) pdmRegion->usKeyGroup;
// Now, the WSMP and WLOOP chunks...
m_vrAttenuation = (short) ((long) ((pdmRegion->WSMP.lAttenuation) * 10) >> 16);
m_Sample.m_prFineTune = pdmRegion->WSMP.sFineTune;
m_Sample.m_bMIDIRootKey = (BYTE) pdmRegion->WSMP.usUnityNote;
if (pdmRegion->WSMP.cSampleLoops == 0)
{
m_Sample.m_bOneShot = TRUE;
}
else
{
m_Sample.m_dwLoopStart = pdmRegion->WLOOP[0].ulStart;
m_Sample.m_dwLoopEnd = m_Sample.m_dwLoopStart + pdmRegion->WLOOP[0].ulLength;
m_Sample.m_bOneShot = FALSE;
m_Sample.m_dwLoopType = pdmRegion->WLOOP[0].ulType;
}
m_Sample.m_dwSampleRate = dwSampleRate;
m_sWaveLinkOptions = pdmRegion->WaveLink.fusOptions;
m_dwChannel = pdmRegion->WaveLink.ulChannel;
if ( (m_dwChannel != WAVELINK_CHANNEL_LEFT) && !IsMultiChannel() )
{
Trace(1, "Download failed: Attempt to use a non-mono channel without setting the multichannel flag.\n");
return DMUS_E_NOTMONO;
}
m_Sample.m_dwID = (DWORD) pdmRegion->WaveLink.ulTableIndex;
// Does it have its own articulation?
//
if (pdmRegion->ulRegionArtIdx )
{
if (pdmRegion->ulRegionArtIdx >= pInfo->dwNumOffsetTableEntries)
{
Trace(1,"Error: Download failed because articulation chunk has an error.\n");
return DMUS_E_BADARTICULATION;
}
CSourceArticulation *pArticulation = new CSourceArticulation;
if (pArticulation)
{
pArticulation->Init(dwSampleRate);
HRESULT hr = pArticulation->Download(pInfo, pvOffsetTable,
pdmRegion->ulRegionArtIdx, dwSampleRate, fNewFormat);
if (FAILED(hr))
{
delete pArticulation;
return hr;
}
m_pArticulation = pArticulation;
m_pArticulation->AddRef();
}
else
{
return E_OUTOFMEMORY;
}
}
return S_OK;
}
HRESULT CInstManager::DownloadInstrument(LPHANDLE phDownload,
DMUS_DOWNLOADINFO *pInfo,
void *pvOffsetTable[],
void *pvData,
BOOL fNewFormat)
{
DMUS_INSTRUMENT *pdmInstrument = (DMUS_INSTRUMENT *) pvData;
CInstrument *pInstrument = new CInstrument;
if (pInstrument)
{
Trace(3,"Downloading instrument %lx\n",pdmInstrument->ulPatch);
pInstrument->m_dwProgram = pdmInstrument->ulPatch;
DWORD dwRegionIX = pdmInstrument->ulFirstRegionIdx;
pdmInstrument->ulFirstRegionIdx = 0; // Clear to avoid loops.
while (dwRegionIX)
{
if (dwRegionIX >= pInfo->dwNumOffsetTableEntries)
{
Trace(1,"Error: Download failed because instrument has error in region list.\n");
delete pInstrument;
return DMUS_E_BADINSTRUMENT;
}
CSourceRegion *pRegion = new CSourceRegion;
if (!pRegion)
{
delete pInstrument;
return E_OUTOFMEMORY;
}
pInstrument->m_RegionList.AddHead(pRegion);
HRESULT hr = pRegion->Download(pInfo, pvOffsetTable, &dwRegionIX, m_dwSampleRate, fNewFormat);
if (FAILED(hr))
{
delete pInstrument;
return hr;
}
EnterCriticalSection(&m_CriticalSection);
CWave *pWave = m_WavePool[pRegion->m_Sample.m_dwID % WAVE_HASH_SIZE].GetHead();
for (;pWave;pWave = pWave->GetNext())
{
if (pRegion->m_Sample.m_dwID == pWave->m_dwID)
{
pRegion->m_Sample.m_pWave = pWave;
pWave->AddRef();
pRegion->m_Sample.CopyFromWave();
break;
}
}
LeaveCriticalSection(&m_CriticalSection);
}
if (pdmInstrument->ulGlobalArtIdx)
{
if (pdmInstrument->ulGlobalArtIdx >= pInfo->dwNumOffsetTableEntries)
{
Trace(1,"Error: Download failed because of out of range articulation chunk.\n");
delete pInstrument;
return DMUS_E_BADARTICULATION;
}
CSourceArticulation *pArticulation = new CSourceArticulation;
if (pArticulation)
{
pArticulation->Init(m_dwSampleRate);
HRESULT hr = pArticulation->Download(pInfo, pvOffsetTable,
pdmInstrument->ulGlobalArtIdx, m_dwSampleRate, fNewFormat);
if (FAILED(hr))
{
delete pInstrument;
delete pArticulation;
return hr;
}
for (CSourceRegion *pr = pInstrument->m_RegionList.GetHead();
pr != NULL;
pr = pr->GetNext())
{
if (pr->m_pArticulation == NULL)
{
pr->m_pArticulation = pArticulation;
pArticulation->AddRef();
}
}
if (!pArticulation->m_wUsageCount)
{
delete pArticulation;
}
}
else
{
delete pInstrument;
return E_OUTOFMEMORY;
}
}
else
{
for (CSourceRegion *pr = pInstrument->m_RegionList.GetHead();
pr != NULL;
pr = pr->GetNext())
{
if (pr->m_pArticulation == NULL)
{
Trace(1,"Error: Download failed because region has no articulation.\n");
delete pInstrument;
return DMUS_E_NOARTICULATION;
}
}
}
EnterCriticalSection(&m_CriticalSection);
if (pdmInstrument->ulFlags & DMUS_INSTRUMENT_GM_INSTRUMENT)
{
pInstrument->SetNext(NULL);
m_InstrumentList[pInstrument->m_dwProgram % INSTRUMENT_HASH_SIZE].AddTail(pInstrument);
}
else
{
m_InstrumentList[pInstrument->m_dwProgram % INSTRUMENT_HASH_SIZE].AddHead(pInstrument);
}
LeaveCriticalSection(&m_CriticalSection);
*phDownload = (HANDLE) pInstrument;
return S_OK;
}
return E_OUTOFMEMORY;
}
HRESULT CInstManager::DownloadWave(LPHANDLE phDownload,
DMUS_DOWNLOADINFO *pInfo,
void *pvOffsetTable[],
void *pvData)
{
DMUS_WAVE *pdmWave = (DMUS_WAVE *) pvData;
if (pdmWave->WaveformatEx.wFormatTag != WAVE_FORMAT_PCM)
{
Trace(1,"Error: Download failed because wave data is not PCM format.\n");
return DMUS_E_NOTPCM;
}
if (pdmWave->WaveformatEx.nChannels != 1)
{
Trace(1,"Error: Download failed because wave data is not mono.\n");
return DMUS_E_NOTMONO;
}
if (pdmWave->ulWaveDataIdx >= pInfo->dwNumOffsetTableEntries)
{
Trace(1,"Error: Download failed because wave data is at invalid location.\n");
return DMUS_E_BADWAVE;
}
CWave *pWave = new CWave;
if (pWave)
{
DMUS_WAVEDATA *pdmWaveData= (DMUS_WAVEDATA *)
pvOffsetTable[pdmWave->ulWaveDataIdx];
pWave->m_dwID = pInfo->dwDLId;
pWave->m_hUserData = NULL;
pWave->m_lpFreeHandle = NULL;
pWave->m_dwSampleLength = pdmWaveData->cbSize;
pWave->m_pnWave = (short *) &pdmWaveData->byData[0];
pWave->m_dwSampleRate = pdmWave->WaveformatEx.nSamplesPerSec;
if (pdmWave->WaveformatEx.wBitsPerSample == 8)
{
pWave->m_bSampleType = SFORMAT_8;
DWORD dwX;
char *pData = (char *) &pdmWaveData->byData[0];
for (dwX = 0; dwX < pWave->m_dwSampleLength; dwX++)
{
pData[dwX] -= (char) 128;
}
}
else if (pdmWave->WaveformatEx.wBitsPerSample == 16)
{
pWave->m_dwSampleLength >>= 1;
pWave->m_bSampleType = SFORMAT_16;
}
else
{
Trace(1,"Error: Downloading wave %ld, bad wave format.\n",pInfo->dwDLId);
delete pWave;
return DMUS_E_BADWAVE;
}
pWave->m_dwSampleLength++; // We always add one sample to the end for interpolation.
EnterCriticalSection(&m_CriticalSection);
m_WavePool[pWave->m_dwID % WAVE_HASH_SIZE].AddHead(pWave);
LeaveCriticalSection(&m_CriticalSection);
*phDownload = (HANDLE) pWave;
pWave->AddRef();
// Track memory usage
m_dwSynthMemUse += (pWave->m_bSampleType == SFORMAT_16)?pWave->m_dwSampleLength << 1: pWave->m_dwSampleLength;
Trace(3,"Downloading wave %ld memory usage %ld\n",pInfo->dwDLId,m_dwSynthMemUse);
return S_OK;
}
return E_OUTOFMEMORY;
}
HRESULT CInstManager::Download(LPHANDLE phDownload,
void * pvData,
LPBOOL pbFree)
{
V_INAME(IDirectMusicSynth::Download);
V_BUFPTR_READ(pvData,sizeof(DMUS_DOWNLOADINFO));
HRESULT hr = DMUS_E_UNKNOWNDOWNLOAD;
void ** ppvOffsetTable; // Array of pointers to chunks in data.
DMUS_DOWNLOADINFO * pInfo = (DMUS_DOWNLOADINFO *) pvData;
DMUS_OFFSETTABLE* pOffsetTable = (DMUS_OFFSETTABLE *)(((BYTE*)pvData) + sizeof(DMUS_DOWNLOADINFO));
char *pcData = (char *) pvData;
V_BUFPTR_READ(pvData,pInfo->cbSize);
// Code fails if pInfo->dwNumOffsetTableEntries == 0
// Sanity check here for debug
assert(pInfo->dwNumOffsetTableEntries);
ppvOffsetTable = new void *[pInfo->dwNumOffsetTableEntries];
if (ppvOffsetTable) // Create the pointer array and validate.
{
DWORD dwIndex;
for (dwIndex = 0; dwIndex < pInfo->dwNumOffsetTableEntries; dwIndex++)
{
if (pOffsetTable->ulOffsetTable[dwIndex] >= pInfo->cbSize)
{
delete[] ppvOffsetTable;
Trace(1,"Error: Download failed because of corrupt download tables.\n");
return DMUS_E_BADOFFSETTABLE; // Bad!
}
ppvOffsetTable[dwIndex] = (void *) &pcData[pOffsetTable->ulOffsetTable[dwIndex]];
}
if (pInfo->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT) // Instrument.
{
*pbFree = TRUE;
hr = DownloadInstrument(phDownload, pInfo, ppvOffsetTable, ppvOffsetTable[0],FALSE);
}
else if (pInfo->dwDLType == DMUS_DOWNLOADINFO_INSTRUMENT2) // New instrument format.
{
*pbFree = TRUE;
hr = DownloadInstrument(phDownload, pInfo, ppvOffsetTable, ppvOffsetTable[0],TRUE);
}
else if (pInfo->dwDLType == DMUS_DOWNLOADINFO_WAVE) // Wave.
{
*pbFree = FALSE;
hr = DownloadWave(phDownload, pInfo, ppvOffsetTable, ppvOffsetTable[0]);
}
else if (pInfo->dwDLType == DMUS_DOWNLOADINFO_WAVEARTICULATION) // Wave onshot & streaming
{
*pbFree = TRUE;
hr = DownloadWaveArticulation(phDownload, pInfo, ppvOffsetTable, ppvOffsetTable[0]);
}
else if (pInfo->dwDLType == DMUS_DOWNLOADINFO_STREAMINGWAVE) // Streaming
{
*pbFree = FALSE;
hr = DownloadWaveRaw(phDownload, pInfo, ppvOffsetTable, ppvOffsetTable[0]);
}
else if (pInfo->dwDLType == DMUS_DOWNLOADINFO_ONESHOTWAVE) // Wave onshot
{
*pbFree = FALSE;
hr = DownloadWaveRaw(phDownload, pInfo, ppvOffsetTable, ppvOffsetTable[0]);
}
delete[] ppvOffsetTable;
}
else
{
hr = E_OUTOFMEMORY;
}
return hr;
}
HRESULT CInstManager::Unload(HANDLE hDownload,
HRESULT ( CALLBACK *lpFreeHandle)(HANDLE,HANDLE),
HANDLE hUserData)
{
DWORD dwIndex;
EnterCriticalSection(&m_CriticalSection);
for (dwIndex = 0; dwIndex < INSTRUMENT_HASH_SIZE; dwIndex++)
{
CInstrument *pInstrument = m_InstrumentList[dwIndex].GetHead();
for (;pInstrument != NULL; pInstrument = pInstrument->GetNext())
{
if (pInstrument == (CInstrument *) hDownload)
{
Trace(3,"Unloading instrument %lx\n",pInstrument->m_dwProgram);
m_InstrumentList[dwIndex].Remove(pInstrument);
delete pInstrument;
LeaveCriticalSection(&m_CriticalSection);
return S_OK;
}
}
}
for (dwIndex = 0; dwIndex < WAVE_HASH_SIZE; dwIndex++)
{
CWave *pWave = m_WavePool[dwIndex].GetHead();
for (;pWave != NULL;pWave = pWave->GetNext())
{
if (pWave == (CWave *) hDownload)
{
// Track memory usage
m_dwSynthMemUse -= (pWave->m_bSampleType == SFORMAT_16)?pWave->m_dwSampleLength << 1: pWave->m_dwSampleLength;
Trace(3,"Unloading wave %ld memory usage %ld\n",pWave->m_dwID,m_dwSynthMemUse);
m_WavePool[dwIndex].Remove(pWave);
pWave->m_hUserData = hUserData;
pWave->m_lpFreeHandle = lpFreeHandle;
pWave->Release();
LeaveCriticalSection(&m_CriticalSection);
return S_OK;
}
}
}
for (dwIndex = 0; dwIndex < WAVE_HASH_SIZE; dwIndex++)
{
CWaveArt* pWaveArt = m_WaveArtList[dwIndex].GetHead();
for (;pWaveArt != NULL;pWaveArt = pWaveArt->GetNext())
{
if (pWaveArt == (CWaveArt *) hDownload)
{
Trace(3,"Unloading wave articulation %ld\n",pWaveArt->m_dwID,m_dwSynthMemUse);
m_WaveArtList[dwIndex].Remove(pWaveArt);
pWaveArt->Release();
LeaveCriticalSection(&m_CriticalSection);
return S_OK;
}
}
}
LeaveCriticalSection(&m_CriticalSection);
Trace(1,"Error: Unload failed - downloaded object not found.\n");
return E_FAIL;
}
//////////////////////////////////////////////////////////
// Directx8 Methods
CWave * CInstManager::GetWave(DWORD dwDLId)
{
EnterCriticalSection(&m_CriticalSection);
CWave *pWave = m_WavePool[dwDLId % WAVE_HASH_SIZE].GetHead();
for (;pWave;pWave = pWave->GetNext())
{
if (dwDLId == pWave->m_dwID)
{
break;
}
}
LeaveCriticalSection(&m_CriticalSection);
return pWave;
}
CWaveArt * CInstManager::GetWaveArt(DWORD dwDLId)
{
EnterCriticalSection(&m_CriticalSection);
CWaveArt *pWaveArt = m_WaveArtList[dwDLId % WAVEART_HASH_SIZE].GetHead();
for (;pWaveArt;pWaveArt = pWaveArt->GetNext())
{
if (dwDLId == pWaveArt->m_dwID)
{
break;
}
}
LeaveCriticalSection(&m_CriticalSection);
return pWaveArt;
}
HRESULT CInstManager::DownloadWaveArticulation(LPHANDLE phDownload,
DMUS_DOWNLOADINFO *pInfo,
void *pvOffsetTable[],
void *pvData)
{
DMUS_WAVEARTDL* pWaveArtDl = (DMUS_WAVEARTDL*)pvData;
WAVEFORMATEX *pWaveformatEx = (WAVEFORMATEX *) pvOffsetTable[1];
DWORD *dwDlId = (DWORD*)pvOffsetTable[2];
DWORD i;
CWaveArt* pWaveArt = new CWaveArt();
if ( pWaveArt )
{
pWaveArt->m_dwID = pInfo->dwDLId;
pWaveArt->m_WaveArtDl = *pWaveArtDl;;
pWaveArt->m_WaveformatEx = *pWaveformatEx;
if (pWaveformatEx->wBitsPerSample == 8)
{
pWaveArt->m_bSampleType = SFORMAT_8;
}
else if (pWaveformatEx->wBitsPerSample == 16)
{
pWaveArt->m_bSampleType = SFORMAT_16;
}
else
{
Trace(1,"Error: Download failed because wave data is %ld bits instead of 8 or 16.\n",(long) pWaveformatEx->wBitsPerSample);
delete pWaveArt;
return DMUS_E_BADWAVE;
}
for ( i = 0; i < pWaveArtDl->ulBuffers; i++ )
{
// Get wave buffer and fill header with waveformat data
CWave *pWave = GetWave(dwDlId[i]);
assert(pWave);
if (!pWave)
{
delete pWaveArt;
return E_POINTER;
}
pWave->m_dwSampleRate = pWaveformatEx->nSamplesPerSec;
if (pWaveformatEx->wBitsPerSample == 8)
{
DWORD dwX;
char *pData = (char *) pWave->m_pnWave;
for (dwX = 0; dwX < pWave->m_dwSampleLength; dwX++)
{
pData[dwX] -= (char) 128;
}
pWave->m_bSampleType = SFORMAT_8;
}
else if (pWaveformatEx->wBitsPerSample == 16)
{
pWave->m_dwSampleLength >>= 1;
pWave->m_bSampleType = SFORMAT_16;
}
else
{
Trace(1,"Error: Download failed because wave data is %ld bits instead of 8 or 16.\n",(long) pWaveformatEx->wBitsPerSample);
delete pWaveArt;
return DMUS_E_BADWAVE;
}
pWave->m_dwSampleLength++; // We always add one sample to the end for interpolation.
// Default is to duplicate last sample. This will be overrwritten for
// streaming waves.
//
if (pWave->m_dwSampleLength > 1)
{
if (pWave->m_bSampleType == SFORMAT_8)
{
char* pb = (char*)pWave->m_pnWave;
pb[pWave->m_dwSampleLength - 1] = pb[pWave->m_dwSampleLength - 2];
}
else
{
short *pn = pWave->m_pnWave;
pn[pWave->m_dwSampleLength - 1] = pn[pWave->m_dwSampleLength - 2];
}
}
// Create a WaveBuffer listitem and save the wave in and add it to the circular buffer list
CWaveBuffer* pWavBuf = new CWaveBuffer();
if ( pWavBuf == NULL )
{
delete pWaveArt;
return E_OUTOFMEMORY;
}
pWavBuf->m_pWave = pWave;
// This Articulation will be handling streaming data
if ( pWave->m_bStream )
pWaveArt->m_bStream = TRUE;
pWaveArt->m_pWaves.AddTail(pWavBuf);
}
EnterCriticalSection(&m_CriticalSection);
if (pWaveArt)
{
CWaveBuffer* pCurrentBuffer = pWaveArt->m_pWaves.GetHead();
for (; pCurrentBuffer; pCurrentBuffer = pCurrentBuffer->GetNext() )
{
if (pCurrentBuffer->m_pWave)
{
pCurrentBuffer->m_pWave->AddRef();
}
}
}
m_WaveArtList[pWaveArt->m_dwID % WAVEART_HASH_SIZE].AddHead(pWaveArt);
LeaveCriticalSection(&m_CriticalSection);
*phDownload = (HANDLE) pWaveArt;
return S_OK;
}
return E_OUTOFMEMORY;
}
HRESULT CInstManager::DownloadWaveRaw(LPHANDLE phDownload,
DMUS_DOWNLOADINFO *pInfo,
void *pvOffsetTable[],
void *pvData)
{
CWave *pWave = new CWave;
if (pWave)
{
DMUS_WAVEDATA *pdmWaveData= (DMUS_WAVEDATA *)pvData;
Trace(3,"Downloading raw wave data%ld\n",pInfo->dwDLId);
pWave->m_dwID = pInfo->dwDLId;
pWave->m_hUserData = NULL;
pWave->m_lpFreeHandle = NULL;
pWave->m_dwSampleLength = pdmWaveData->cbSize;
pWave->m_pnWave = (short *) &pdmWaveData->byData[0];
if ( pInfo->dwDLType == DMUS_DOWNLOADINFO_STREAMINGWAVE )
{
pWave->m_bStream = TRUE;
pWave->m_bValid = TRUE;
}
EnterCriticalSection(&m_CriticalSection);
m_WavePool[pWave->m_dwID % WAVE_HASH_SIZE].AddHead(pWave);
LeaveCriticalSection(&m_CriticalSection);
*phDownload = (HANDLE) pWave;
pWave->AddRef();
m_dwSynthMemUse += pWave->m_dwSampleLength;
return S_OK;
}
return E_OUTOFMEMORY;
}