HRESULT CParamsManager::GetParam(DWORD dwParamIndex,MP_DATA *pValue) { V_INAME(CParams::GetParam); V_PTR_WRITE(pValue, MP_DATA); if (dwParamIndex >= m_cParams) return E_INVALIDARG; EnterCriticalSection(&m_ParamsCriticalSection); CCurveList *pList = &m_pCurveLists[dwParamIndex]; ParamInfo *pInfo = &m_pParamInfos[dwParamIndex]; // if no points, then neutral value CCurveItem *pCurve = pList->GetHead(); if (pCurve) { *pValue = pCurve->m_Envelope.valEnd; } else { *pValue = pInfo->MParamInfo.mpdNeutralValue; } LeaveCriticalSection(&m_ParamsCriticalSection); return S_OK; }
HRESULT CParamsManager::AddEnvelope( DWORD dwParamIndex, DWORD cPoints, MP_ENVELOPE_SEGMENT *ppEnvelope) { V_INAME(CParams::AddEnvelope); V_PTR_READ(ppEnvelope, *ppEnvelope); if (dwParamIndex >= m_cParams) return E_INVALIDARG; if (!m_pParamInfos) return DMUS_E_NOT_INIT; HRESULT hr = S_OK; EnterCriticalSection(&m_ParamsCriticalSection); m_fDirty = TRUE; CCurveList *pList = &m_pCurveLists[dwParamIndex]; ParamInfo *pInfo = &m_pParamInfos[dwParamIndex]; DWORD dwCount; for (dwCount = 0; dwCount < cPoints; dwCount++) { CCurveItem *pCurve = new CCurveItem; if (!pCurve) { hr = E_OUTOFMEMORY; break; } pCurve->m_Envelope = ppEnvelope[dwCount]; pCurve->m_Envelope.valEnd = ValRange(pCurve->m_Envelope.valEnd, pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue); pCurve->m_Envelope.valStart = ValRange(pCurve->m_Envelope.valStart, pInfo->MParamInfo.mpdMinValue, pInfo->MParamInfo.mpdMaxValue); pList->AddHead(pCurve); // next call to UpdateActiveParams will ensure the parameter's value is recalculated m_dwActiveBits |= 1 << dwParamIndex; //TraceI(6, "DMO envelope: time %I64d-%I64d, param #%d, value %hf-%hf\n", // pCurve->m_Envelope.rtStart, pCurve->m_Envelope.rtEnd, // dwParamIndex, pCurve->m_Envelope.valStart, pCurve->m_Envelope.valEnd); } LeaveCriticalSection(&m_ParamsCriticalSection); return hr; }
HRESULT CParamsManager::SetParam(DWORD dwParamIndex,MP_DATA value) { V_INAME(CParams::SetParam); if (dwParamIndex >= m_cParams) return E_INVALIDARG; EnterCriticalSection(&m_ParamsCriticalSection); m_fDirty = TRUE; CCurveList *pList = &m_pCurveLists[dwParamIndex]; // ParamInfo *pInfo = &m_pParamInfos[dwParamIndex]; // If we've already got a list, just force the most recent curve item to this value. // Otherwise, create a node and add it. CCurveItem *pCurve = pList->GetHead(); if (!pCurve) { pCurve = new CCurveItem; if (pCurve) { pCurve->m_Envelope.rtStart = 0x8000000000000000; // Max negative. pCurve->m_Envelope.rtEnd = 0x7FFFFFFFFFFFFFFF; // Max positive. pCurve->m_Envelope.flags = 0; pList->AddHead(pCurve); } else { LeaveCriticalSection(&m_ParamsCriticalSection); return E_OUTOFMEMORY; } } pCurve->m_Envelope.valStart = value; pCurve->m_Envelope.valEnd = value; pCurve->m_Envelope.iCurve = MP_CURVE_JUMP; LeaveCriticalSection(&m_ParamsCriticalSection); return S_OK; }
HRESULT CParamsManager::FlushEnvelope( DWORD dwParamIndex, REFERENCE_TIME refTimeStart, REFERENCE_TIME refTimeEnd) { if (dwParamIndex >= m_cParams) return E_INVALIDARG; if (!m_pParamInfos) return DMUS_E_NOT_INIT; if (refTimeStart >= refTimeEnd) return E_INVALIDARG; EnterCriticalSection(&m_ParamsCriticalSection); m_fDirty = TRUE; CCurveList *pList = &m_pCurveLists[dwParamIndex]; CCurveList TempList; CCurveItem *pCurve; while ((pCurve = pList->RemoveHead()) != 0) { if ((pCurve->m_Envelope.rtStart >= refTimeStart) && (pCurve->m_Envelope.rtEnd <= refTimeEnd)) { delete pCurve; } else { TempList.AddHead(pCurve); } } while ((pCurve = TempList.RemoveHead()) != 0) { pList->AddHead(pCurve); } LeaveCriticalSection(&m_ParamsCriticalSection); return S_OK; }
HRESULT CParamsManager::GetParamFloat(DWORD dwParamIndex,REFERENCE_TIME rtTime,float *pval) { HRESULT hr = S_OK; if (dwParamIndex >= m_cParams) return E_INVALIDARG; EnterCriticalSection(&m_ParamsCriticalSection); CCurveList *pList = &m_pCurveLists[dwParamIndex]; ParamInfo *pInfo = &m_pParamInfos[dwParamIndex]; // if no points, then neutral value CCurveItem *pCurveHead = pList->GetHead(); if (!pCurveHead) { *pval = pInfo->MParamInfo.mpdNeutralValue; LeaveCriticalSection(&m_ParamsCriticalSection); return S_FALSE; } // Find the curve during or before the requested time // If the time is during a curve, we will use that. // If not, we need the end value of the previous curve. // Our list keeps these in backwards order, so we are scanning from the // highest point in time backwards. for (CCurveItem *pCurve = pCurveHead; pCurve && pCurve->m_Envelope.rtStart > rtTime;pCurve = pCurve->GetNext()); // If there is no pCurve, there was no curve prior to or during rtTime. Give up. if (!pCurve) { *pval = pInfo->MParamInfo.mpdNeutralValue; LeaveCriticalSection(&m_ParamsCriticalSection); return S_OK; } // Now, if pCurve ends before the requested time, // return the final value of pCurve, since that will hold until the start of the next curve. if (pCurve->m_Envelope.rtEnd < rtTime) { *pval = pCurve->m_Envelope.valEnd; LeaveCriticalSection(&m_ParamsCriticalSection); if (pCurve == pCurveHead) return S_FALSE; // past last curve else return S_OK; // there are more curves ahead } // If we get this far, the curve must bound rtTime. if (pCurve->m_Envelope.iCurve & MP_CURVE_JUMP) { *pval = pCurve->m_Envelope.valEnd; LeaveCriticalSection(&m_ParamsCriticalSection); return S_OK; } REFERENCE_TIME rtTimeChange = pCurve->m_Envelope.rtEnd - pCurve->m_Envelope.rtStart; REFERENCE_TIME rtTimeIntermediate = rtTime - pCurve->m_Envelope.rtStart; float fltScalingX = static_cast<float>(rtTimeIntermediate) / rtTimeChange; // horizontal distance along curve between 0 and 1 float fltScalingY; // height of curve at that point between 0 and 1 based on curve function switch (pCurve->m_Envelope.iCurve) { case MP_CURVE_SQUARE: fltScalingY = fltScalingX * fltScalingX; break; case MP_CURVE_INVSQUARE: fltScalingY = (float) sqrt(fltScalingX); break; case MP_CURVE_SINE: // §§ Maybe we should have a lookup table here? fltScalingY = (float) (sin(fltScalingX * 3.1415926535 - (3.1415926535/2)) + 1) / 2; break; case MP_CURVE_LINEAR: default: fltScalingY = fltScalingX; } // Find out if we need to pull the start point from the previous curve, // the default neutral value, or the current curve. float fStartVal = pCurve->m_Envelope.valStart; if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_NEUTRALVAL) { fStartVal = pInfo->MParamInfo.mpdNeutralValue; } // Currentval, if it exists, will override neutralval. if (pCurve->m_Envelope.flags & MPF_ENVLP_BEGIN_CURRENTVAL) { // Take advantage of the fact that these are inserted in backwards order. // Scan for the previous curve that ends before this time. CCurveItem *pPrevious = pCurve->GetNext(); for (;pPrevious && pPrevious->m_Envelope.rtEnd > rtTime;pPrevious = pPrevious->GetNext()); if (pPrevious) { fStartVal = pPrevious->m_Envelope.valEnd; } } // Apply that scaling to the range of the actual points *pval = (pCurve->m_Envelope.valEnd - fStartVal) * fltScalingY + fStartVal; LeaveCriticalSection(&m_ParamsCriticalSection); return hr; }