// // Copyright (c) 1996-2001 Microsoft Corporation // Instrument.cpp // #ifdef DMSYNTH_MINIPORT #include "common.h" #else #include "simple.h" #include #include #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 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; }