|
|
#include <objbase.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <dsoundp.h>
#include "debug.h"
#include "dmusicc.h"
#include "dmusici.h"
#include "validate.h"
#include "riff.h"
#include "dswave.h"
#include "waveutil.h"
#include "riff.h"
#include <regstr.h>
#include <share.h>
// CWaveViewPort(IStream *pStream); // Constructor receives stream.
// ~CWaveViewPort(); // Destructor releases memory, streams, etc.
//
// STDMETHODIMP Init();
// STDMETHODIMP GetFormat(LPWAVEFORMATEX pWaveFormatEx, LPDWORD pdwWaveFormatExSize);
// STDMETHODIMP Seek(DWORD dwSample);
// STDMETHODIMP Read(LPVOID *ppvBuffer, DWORD cpvBuffer, LPDWORD pcb);
CWaveViewPort::CWaveViewPort() : m_dwDecompressedStart(0), m_dwDecompStartOffset(0), m_dwDecompStartOffsetPCM(0), m_dwDecompStartDelta(0) { V_INAME(CWaveViewPort::CWaveViewPort);
InterlockedIncrement(&g_cComponent);
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_cRef = 1;
// General stuff...
m_pStream = NULL; m_cSamples = 0L; m_cbStream = 0L; m_dwStart = 0L;
// Viewport info...
m_pwfxTarget = NULL; ZeroMemory(&m_ash, sizeof(ACMSTREAMHEADER)); m_hStream = NULL; m_pDst = NULL; m_pRaw = NULL; m_fdwOptions = 0L;
m_dwPreCacheFilePos = 0; m_dwFirstPCMSample = 0; m_dwPCMSampleOut = 0;
return; }
CWaveViewPort::~CWaveViewPort() { V_INAME(CWaveViewPort::~CWaveViewPort);
if (m_pStream) m_pStream->Release(); if (m_hStream) { acmStreamUnprepareHeader(m_hStream, &m_ash, 0L); acmStreamClose(m_hStream, 0); } if (NULL != m_pwfxTarget) { GlobalFreePtr(m_pwfxTarget); } if (NULL != m_ash.pbDst) { GlobalFreePtr(m_ash.pbDst); } if (NULL != m_ash.pbSrc) { GlobalFreePtr(m_ash.pbSrc); } DeleteCriticalSection(&m_CriticalSection);
InterlockedDecrement(&g_cComponent);
return; }
STDMETHODIMP CWaveViewPort::QueryInterface ( const IID &iid, void **ppv ) { V_INAME(CWaveViewPort::QueryInterface);
if (iid == IID_IUnknown || iid == IID_IDirectSoundSource) { *ppv = static_cast<IDirectSoundSource*>(this); } else { *ppv = NULL; Trace(4,"Warning: Request to query unknown interface on Viewport\n"); return E_NOINTERFACE; } reinterpret_cast<IUnknown*>(this)->AddRef(); return S_OK; }
STDMETHODIMP_(ULONG) CWaveViewPort::AddRef() { V_INAME(CWaveViewPort::AddRef);
return InterlockedIncrement(&m_cRef); }
STDMETHODIMP_(ULONG) CWaveViewPort::Release() { V_INAME(CWaveViewPort::Release);
if (!InterlockedDecrement(&m_cRef)) { delete this; return 0; }
return m_cRef; }
STDMETHODIMP CWaveViewPort::SetSink ( IDirectSoundConnect *pSinkConnect ) { V_INAME(CWaveViewPort::Init); return S_OK; }
STDMETHODIMP CWaveViewPort::GetFormat ( LPWAVEFORMATEX pwfx, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten ) { DWORD cbSize;
V_INAME(CWaveViewPort::GetFormat);
if (!pwfx && !pdwSizeWritten) { Trace(1, "ERROR: GetFormat (Viewport): Must request either the format or the required size"); return E_INVALIDARG; }
if (!m_pwfxTarget) { return DSERR_BADFORMAT; }
// Note: Assuming that the wave object fills the cbSize field even
// on PCM formats...
if (WAVE_FORMAT_PCM == m_pwfxTarget->wFormatTag) { cbSize = sizeof(PCMWAVEFORMAT); } else { cbSize = sizeof(WAVEFORMATEX) + m_pwfxTarget->cbSize; }
if (pdwSizeWritten) { V_PTR_WRITE(pdwSizeWritten, DWORD); *pdwSizeWritten = cbSize; }
if (pwfx) { V_BUFPTR_WRITE(pwfx, dwSizeAllocated); if (dwSizeAllocated < cbSize) { return DSERR_INVALIDPARAM; } else { CopyMemory(pwfx, m_pwfxTarget, cbSize); // Set the cbSize field in destination if we have room
if (WAVE_FORMAT_PCM == m_pwfxTarget->wFormatTag && dwSizeAllocated >= sizeof(WAVEFORMATEX)) { pwfx->cbSize = 0; } } }
return S_OK; }
STDMETHODIMP CWaveViewPort::Seek ( ULONGLONG ullPosition ) { LARGE_INTEGER li; HRESULT hr; MMRESULT mmr; DWORD cbSize;
V_INAME(CWaveViewPort::Seek);
m_fdwOptions &= ~DSOUND_WVP_STREAMEND; // rsw clear this on seek: no longer at stream end
if (m_fdwOptions & DSOUND_WVP_NOCONVERT) { if ((DWORD) ullPosition >= m_cbStream) { // Seek past end of stream
//
m_fdwOptions |= DSOUND_WVP_STREAMEND; m_dwOffset = m_cbStream;
return S_OK; }
m_dwOffset = (DWORD) ullPosition; // rsw initialize offset to Seek position
if (0 != (ullPosition % m_pwfxTarget->nBlockAlign)) { // Seek position not block aligned?
Trace(1, "ERROR: Seek (wave): Seek position is not block-aligned.\n"); return (DMUS_E_BADWAVE); }
li.HighPart = 0; li.LowPart = ((DWORD)ullPosition) + m_dwStartPos;
hr = m_pStream->Seek(li, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) { Trace(1, "ERROR: Seek (Viewport): Seeking the vieport's stream failed.\n"); return (DMUS_E_BADWAVE); } } else { // Estimating source stream position...
//
// Should we create lookup table?!
cbSize = (DWORD)ullPosition;
if (cbSize) { mmr = acmStreamSize(m_hStream, cbSize, &cbSize, ACM_STREAMSIZEF_DESTINATION);
if (MMSYSERR_NOERROR != mmr) { Trace(1, "ERROR: Seek (viewport): Could not convert target stream size to source format.\n"); return (DMUS_E_BADWAVE); } }
if (cbSize >= m_cbStream) { // Seek past end of stream
//
m_fdwOptions |= DSOUND_WVP_STREAMEND; m_dwOffset = m_cbStream;
return S_OK; }
// If this is a seek to the precache end we know where to start reading from
if((m_fdwOptions & DSOUND_WAVEF_ONESHOT) == 0) { // Go back to the block that was read for the end of the precached data
if(cbSize != 0 && m_dwPCMSampleOut == ullPosition) { m_dwOffset = m_dwPreCacheFilePos; li.HighPart = 0; li.LowPart = m_dwOffset + m_dwStartPos; } else { m_dwOffset = cbSize; // rsw initialize offset to Seek position
li.HighPart = 0; li.LowPart = cbSize + m_dwStartPos;
}
hr = m_pStream->Seek(li, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) { Trace(1, "ERROR: Seek (viewport): Seeking the viewport's stream failed.\n"); return (DMUS_E_BADWAVE); }
// Since we're restarting, re-initialize.
m_fdwOptions &= (~DSOUND_WVP_CONVERTMASK); m_fdwOptions |= DSOUND_WVP_CONVERTSTATE_01;
m_ash.cbSrcLength = (DWORD)m_ash.dwSrcUser; m_ash.cbSrcLengthUsed = m_ash.cbSrcLength;
m_ash.dwDstUser = 0L; m_ash.cbDstLengthUsed = 0L;
}
/////////////////////////////////////////////////////////////////////////////////////
// If we're starting the wave, re-seek the stream (one-shots always need to re-seek).
// NOTE: The following assumes that compressed waves always seek from the beginning,
// since the value returned by acmStreamSize is pretty unreliable.
/////////////////////////////////////////////////////////////////////////////////////
else if ( cbSize == 0 || (m_fdwOptions & DSOUND_WAVEF_ONESHOT) ) { m_dwOffset = cbSize; // rsw initialize offset to Seek position
li.HighPart = 0; li.LowPart = cbSize + m_dwStartPos;
hr = m_pStream->Seek(li, STREAM_SEEK_SET, NULL);
if (FAILED(hr)) { Trace(1, "ERROR: Seek (viewport): Seeking the viewport's stream failed.\n"); return (DMUS_E_BADWAVE); }
// Since we're restarting, re-initialize.
m_fdwOptions &= (~DSOUND_WVP_CONVERTMASK); m_fdwOptions |= DSOUND_WVP_CONVERTSTATE_01;
m_ash.cbSrcLength = (DWORD)m_ash.dwSrcUser; m_ash.cbSrcLengthUsed = m_ash.cbSrcLength;
m_ash.dwDstUser = 0L; m_ash.cbDstLengthUsed = 0L;
} }
TraceI(5, "Seek (Viewport): Succeeded.\n"); return S_OK; }
static inline HRESULT MMRESULTToHRESULT( MMRESULT mmr) { switch (mmr) { case MMSYSERR_NOERROR: return S_OK;
case MMSYSERR_ALLOCATED: return DSERR_ALLOCATED;
case MMSYSERR_NOMEM: return E_OUTOFMEMORY; }
return E_FAIL; }
HRESULT CWaveViewPort::acmRead ( void ) { DWORD cbSize; DWORD dwOffset; DWORD fdwConvert = 0; MMRESULT mmr; HRESULT hr;
V_INAME(CWaveViewPort::acmRead); for (m_ash.cbDstLengthUsed = 0; 0 == m_ash.cbDstLengthUsed; ) { // Did we use up the entire buffer?
if (m_ash.cbSrcLengthUsed == m_ash.cbSrcLength) { // Yep!
dwOffset = 0L; cbSize = (DWORD)m_ash.dwSrcUser; } else { // Nope!
dwOffset = m_ash.cbSrcLength - m_ash.cbSrcLengthUsed; cbSize = (DWORD)m_ash.dwSrcUser - dwOffset;
// Moving the remaining data from the end of buffer to the beginning
MoveMemory( m_ash.pbSrc, // Base address
&(m_ash.pbSrc[m_ash.cbSrcLengthUsed]), // Address of unused bytes
dwOffset); // Number of unused bytes
}
// Are we at the end of the stream?
cbSize = min(cbSize, m_cbStream - m_dwOffset);
if (0 == cbSize) { if (dwOffset) { m_ash.cbSrcLength = dwOffset; } } else { hr = m_pStream->Read(&(m_ash.pbSrc[dwOffset]), cbSize, &cbSize);
if (FAILED(hr)) { Trace(1, "ERROR: Read (Viewport): Attempt to read source stream returned 0x%08lx\n", hr); //>>>>>>>>>>>>>>>>>>>>
m_fdwOptions &= (~DSOUND_WVP_CONVERTMASK); m_fdwOptions |= DSOUND_WVP_STREAMEND; return(DMUS_E_CANNOTREAD); //>>>>>>>>>>>>>>>>>>>>
}
m_dwOffset += cbSize; m_ash.cbSrcLength = cbSize + dwOffset; }
switch (m_fdwOptions & DSOUND_WVP_CONVERTMASK) { case DSOUND_WVP_CONVERTSTATE_01: fdwConvert = ACM_STREAMCONVERTF_BLOCKALIGN; break;
case DSOUND_WVP_CONVERTSTATE_02: fdwConvert = ACM_STREAMCONVERTF_BLOCKALIGN | ACM_STREAMCONVERTF_END; break;
case DSOUND_WVP_CONVERTSTATE_03: fdwConvert = ACM_STREAMCONVERTF_END; break;
default: TraceI(3, "CWaveViewPort::acmRead: Default case?!\n"); break; }
mmr = acmStreamConvert(m_hStream, &m_ash, fdwConvert);
if (MMSYSERR_NOERROR != mmr) { Trace(1, "ERROR: Read (Viewport): Attempt to convert wave to PCM failed.\n"); return (MMRESULTToHRESULT(mmr)); }
if (0 != m_ash.cbDstLengthUsed) { m_ash.dwDstUser = 0L; return (S_OK); }
// No data returned?
switch (m_fdwOptions & DSOUND_WVP_CONVERTMASK) { case DSOUND_WVP_CONVERTSTATE_01: if (0 == cbSize) { // We're at the end of the stream..
m_fdwOptions &= (~DSOUND_WVP_CONVERTMASK); m_fdwOptions |= DSOUND_WVP_CONVERTSTATE_02; TraceI(5, "CWaveViewPort::acmRead: Moving to stage 2\n"); }
// Otherwise, continue converting data as normal.
break;
case DSOUND_WVP_CONVERTSTATE_02: // We have hit the last partial block!
m_fdwOptions &= (~DSOUND_WVP_CONVERTMASK); m_fdwOptions |= DSOUND_WVP_CONVERTSTATE_03; TraceI(5, "CWaveViewPort::acmRead: Moving to stage 3\n"); break;
case DSOUND_WVP_CONVERTSTATE_03: // No more data after end flag, NO MORE DATA!!
m_fdwOptions &= (~DSOUND_WVP_CONVERTMASK); m_fdwOptions |= DSOUND_WVP_STREAMEND; Trace(2, "WARNING: Read (Viewport): End of source stream.\n"); return (DMUS_E_BADWAVE);
default: TraceI(3, "CWaveViewPort::acmRead: Default case?!\n"); break; } }
TraceI(3, "CWaveViewPort::acmRead: We should never get here!\n");
return (S_OK); }
//////////////////////////////////////////////////////////////////////////////
//
// ppvBuffer[] contains cpvBuffer pointers-to-samples, each to be filled with
// *pcb bytes of data. On output *pcb will contain the number of bytes (per
// buffer) actually read.
//
// pdwBusIds and pdwFuncIds are used to specify the bus and functionality
// of each buffer, but these are ignored by the wave object.
//
STDMETHODIMP CWaveViewPort::Read ( LPVOID *ppvBuffer, LPDWORD pdwBusIds, LPDWORD pdwFuncIds, LPLONG plPitchShifts, DWORD cpvBuffer, ULONGLONG *pcb ) { HRESULT hr = S_OK; DWORD cbRead; DWORD dwOffset; DWORD cbSize;
V_INAME(CWaveViewPort::Read); V_BUFPTR_READ(ppvBuffer, (cpvBuffer * sizeof(LPVOID))); V_BUFPTR_READ_OPT(pdwBusIds, (cpvBuffer * sizeof(LPDWORD))); V_BUFPTR_READ_OPT(pdwFuncIds, (cpvBuffer * sizeof(LPDWORD)));
for (cbRead = cpvBuffer, cbSize = (DWORD)*pcb; cbRead; cbRead--) { V_BUFPTR_WRITE(ppvBuffer[cbRead - 1], cbSize); }
if (m_fdwOptions & DSOUND_WVP_STREAMEND) { *pcb = 0; Trace(2, "WARNING: Read (Viewport): Attempt to read at end of stream.\n"); return (S_FALSE); }
LPVOID *ppvWriteBuffers = ppvBuffer; DWORD dwWriteBufferCount = cpvBuffer;
if (m_fdwOptions & DSOUND_WVP_NOCONVERT) { // Total number of bytes to read... size of each buffer * number of buffers
cbRead = ((DWORD)*pcb) * dwWriteBufferCount; dwOffset = 0;
TraceI(5, "CWaveViewPort::Read - No conversion [%d bytes]\n", cbRead);
do { // Calculate read size... It's going to be the size of:
// 1. Remaining bytes to read.
// 2. Size of the buffer.
// 3. Remaining bytes in the stream.
// Whichever happens to be the smallest.
cbSize = min(cbRead, m_ash.cbDstLength); cbSize = min(cbSize, m_cbStream - m_dwOffset);
TraceI(5, "CWaveViewPort::Read - Trying to read %d bytes\n", cbSize);
DWORD _cbSize = cbSize; cbSize = 0; // Read may not set cbSize to zero
hr = m_pStream->Read(m_ash.pbDst, _cbSize, &cbSize);
TraceI(5, "CWaveViewPort::Read - Read %d bytes\n", cbSize);
if (FAILED(hr)) { Trace(2, "WARNING: Read (Viewport): Attempt to read returned 0x%08lx.\n", hr); break; }
dwOffset = DeinterleaveBuffers( m_pwfxTarget, m_ash.pbDst, (LPBYTE *)ppvWriteBuffers, dwWriteBufferCount, cbSize, dwOffset);
cbRead -= cbSize; m_dwOffset += cbSize;
if (m_dwOffset >= m_cbStream) { m_fdwOptions |= DSOUND_WVP_STREAMEND; break; } } while (0 != cbRead);
if (SUCCEEDED(hr)) { *pcb = dwOffset; } } else { // If this is the read for the precache then we should remember the fileposition,
// start sample for the decompressed block and the last sample passed back so we
// can accurately pick up from there when refilling buffers
// We use the LPLONG plPitchShifts in the read method as a boolean
// this is a HACK!! We need to change this...
// *plPitchShifts == 2 is to remember the precache offset
// *plPitchShifts == 1 is to read from there
bool fRememberPreCache = false; if(plPitchShifts != NULL && *plPitchShifts == 2 && (m_fdwOptions & DSOUND_WAVEF_ONESHOT) == 0) { fRememberPreCache = true; }
bool bRemoveSilence = false; cbRead = ((DWORD)*pcb) * dwWriteBufferCount; dwOffset = 0;
TraceI(5, "CWaveViewPort::Read - Conversion needed\n");
do { if(m_dwDecompressedStart > 0 && m_dwOffset <= m_dwDecompStartOffset) { bRemoveSilence = true; }
// Is there any remnant data in destination buffer?
if (m_ash.dwDstUser >= m_ash.cbDstLengthUsed) { if(fRememberPreCache) { // Go back on block
m_dwPreCacheFilePos = m_dwOffset - m_ash.cbSrcLength; m_dwFirstPCMSample = dwOffset * dwWriteBufferCount; }
if(plPitchShifts != NULL && *plPitchShifts == 1) { // Seek to the right place first
Seek(m_dwPCMSampleOut);
// Read one block since we're starting one block behind
hr = acmRead(); if(FAILED(hr)) { break; } }
hr = acmRead(); }
if (FAILED(hr)) { // acmRead spews when it fails; no need to do it again here
break; }
DWORD dwDstOffset = (ULONG)m_ash.dwDstUser;
if(bRemoveSilence) { // We have partial data to throw away
if(m_dwDecompStartOffset <= m_dwOffset) { if(dwDstOffset > 0) { dwDstOffset += m_dwDecompStartDelta; } else { // This is the first decompressed block so we go straight to the value we know
dwDstOffset += m_dwDecompStartOffsetPCM; }
m_ash.dwDstUser = dwDstOffset; bRemoveSilence = false; } else { // This is all throw away data
bRemoveSilence = false; cbSize = min(cbRead, m_ash.cbDstLengthUsed - dwDstOffset); m_ash.dwDstUser += cbSize; continue; } }
// We use the LPLONG plPitchShifts in the read method as a boolean
// this is a HACK!! We need to change this...
if(plPitchShifts && *plPitchShifts == 1) { dwDstOffset = m_dwPCMSampleOut - m_dwFirstPCMSample; m_ash.dwDstUser = dwDstOffset; plPitchShifts = 0; }
cbSize = min(cbRead, m_ash.cbDstLengthUsed - dwDstOffset);
dwOffset = DeinterleaveBuffers( m_pwfxTarget, &(m_ash.pbDst[dwDstOffset]), (LPBYTE *)ppvWriteBuffers, dwWriteBufferCount, cbSize, dwOffset);
cbRead -= cbSize; m_ash.dwDstUser += cbSize;
if ((m_fdwOptions & DSOUND_WVP_STREAMEND) && (m_ash.dwDstUser >= m_ash.cbDstLengthUsed)) { break; } } while(0 != cbRead);
if(fRememberPreCache) { m_dwPCMSampleOut = dwOffset * dwWriteBufferCount; }
if (SUCCEEDED(hr)) { *pcb = dwOffset; } }
TraceI(5, "CWaveViewPort::Read returning %x (%d bytes)\n", hr, dwOffset); return hr; }
STDMETHODIMP CWaveViewPort::GetSize ( ULONGLONG *pcb ) { V_INAME(CWaveViewPort::GetSize); V_PTR_WRITE(pcb, ULONGLONG); TraceI(5, "CWaveViewPort::GetSize [%d samples]\n", m_cSamples); HRESULT hr = S_OK;
if (m_fdwOptions & DSOUND_WVP_NOCONVERT) { // No conversion. This is trivial
*pcb = (SAMPLE_TIME)(m_cbStream); } else if (!m_pwfxTarget) { hr = DSERR_UNINITIALIZED; } else { // Conversion required; let's hope target format is PCM
if (WAVE_FORMAT_PCM == m_pwfxTarget->wFormatTag) { // Cool. This is simply the number of samples X the block align
*pcb = (SAMPLE_TIME)((m_cSamples - m_dwDecompressedStart) * m_pwfxTarget->nBlockAlign); } else { Trace(1, "ERROR: GetSize (Viewport): Conversion required and target is not PCM.\n"); hr = DSERR_BADFORMAT; } }
return (hr); }
HRESULT CWaveViewPort::Create ( PCREATEVIEWPORT pCreate ) { DWORD cbSize; MMRESULT mmr; HRESULT hr; LARGE_INTEGER li; LPWAVEFORMATEX pwfxSrc = pCreate->pwfxSource; LPWAVEFORMATEX pwfxDst = pCreate->pwfxTarget;
V_INAME(CWaveViewPort::Create); TraceI(5, "CWaveViewPort::Create [%d samples]\n", pCreate->cSamples);
EnterCriticalSection(&m_CriticalSection);
// Clone source stream...
hr = pCreate->pStream->Clone(&m_pStream);
if (FAILED(hr)) { LeaveCriticalSection(&m_CriticalSection); return (hr); }
// Misc assignments
m_cSamples = pCreate->cSamples; m_cbStream = pCreate->cbStream; m_dwOffset = 0L; m_fdwOptions = pCreate->fdwOptions; m_dwDecompressedStart = pCreate->dwDecompressedStart; m_dwDecompStartOffset = 0L; m_dwDecompStartOffsetPCM = 0L; m_dwDecompStartDelta = 0L;
TraceI(5, "CWaveViewPort:: %d samples\n", m_cSamples);
// Allocate destination format
cbSize = SIZEOFFORMATEX(pwfxDst);
m_pwfxTarget = (LPWAVEFORMATEX)GlobalAllocPtr(GHND, cbSize);
if (NULL == m_pwfxTarget) { LeaveCriticalSection(&m_CriticalSection); TraceI(1, "OUT OF MEMORY: CWaveViewPort::Create - size: %d \n", cbSize); return (E_OUTOFMEMORY); }
// We don't own the buffer for pwfxDst, so we can't touch its cbSize.
// We have to set the size manually on PCM, we KNOW the buffer is
// large enough.
CopyFormat(m_pwfxTarget, pwfxDst); if (WAVE_FORMAT_PCM == m_pwfxTarget->wFormatTag) { m_pwfxTarget->cbSize = 0; }
// Calculating (block-aligned) size of destination buffer...
cbSize = (pwfxDst->nAvgBytesPerSec * CONVERTLENGTH) / 1000; cbSize = BLOCKALIGN(cbSize, pwfxDst->nBlockAlign);
m_ash.pbDst = (LPBYTE)GlobalAllocPtr(GHND, cbSize);
if (NULL == m_ash.pbDst) { LeaveCriticalSection(&m_CriticalSection); TraceI(1, "OUT OF MEMORY: CWaveViewPort::Create 01\n"); return (E_OUTOFMEMORY); }
m_ash.cbDstLength = cbSize;
// Getting stream starting offset...
li.HighPart = 0; li.LowPart = 0; hr = m_pStream->Seek(li, STREAM_SEEK_CUR, (ULARGE_INTEGER *)(&li));
m_dwStartPos = li.LowPart;
// Do we need to use the ACM?
if (FormatCmp(pwfxSrc, pwfxDst)) { // Formats compare!! All we need to do is to copy the data straight
// from the source stream. Way Cool!!
TraceI(5, "Source and Destination formats are similar!\n");
m_fdwOptions |= DSOUND_WVP_NOCONVERT; } else { // Source and destination formats are different...
TraceI(5, "CWaveViewPort:Create: Formats are different... Use ACM!\n");
m_fdwOptions |= DSOUND_WVP_CONVERTSTATE_01;
mmr = acmStreamOpen(&m_hStream, NULL, pwfxSrc, pwfxDst, NULL, 0, 0, 0);
if (MMSYSERR_NOERROR != mmr) { Trace(1, "ERROR: Create (Viewport): Attempt to open a conversion stream failed.\n"); LeaveCriticalSection(&m_CriticalSection); return MMRESULTToHRESULT(mmr); }
mmr = acmStreamSize(m_hStream, cbSize, &cbSize, ACM_STREAMSIZEF_DESTINATION);
if (MMSYSERR_NOERROR != mmr) { Trace(1, "ERROR: Create(Viewport): Could not convert target stream size to source format.\n"); LeaveCriticalSection(&m_CriticalSection); return MMRESULTToHRESULT(mmr); }
m_ash.cbSrcLength = cbSize; m_ash.pbSrc = (LPBYTE)GlobalAllocPtr(GHND, cbSize);
if (NULL == m_ash.pbSrc) { TraceI(1, "OUT OF MEMORY: CWaveViewPort:Create: GlobalAlloc failed.\n"); LeaveCriticalSection(&m_CriticalSection); return E_OUTOFMEMORY; }
// Also get the position for the actual start for the decompressed data
if(m_dwDecompressedStart > 0) { m_dwDecompStartOffsetPCM = m_dwDecompressedStart * (pwfxDst->wBitsPerSample / 8) * pwfxDst->nChannels; mmr = acmStreamSize(m_hStream, m_dwDecompStartOffsetPCM, &m_dwDecompStartOffset, ACM_STREAMSIZEF_DESTINATION); DWORD dwDelta = 0; mmr = acmStreamSize(m_hStream, m_dwDecompStartOffset, &dwDelta, ACM_STREAMSIZEF_SOURCE);
m_dwDecompStartDelta = m_dwDecompStartOffsetPCM - dwDelta; m_dwDecompStartOffset += m_dwStartPos; }
// For the source buffer, it is the full buffer size.
m_ash.dwSrcUser = m_ash.cbSrcLength; m_ash.cbSrcLengthUsed = m_ash.cbSrcLength;
// For the destination buffer, it is the offset into the buffer
// where the data can be found.
m_ash.dwDstUser = 0L; m_ash.cbDstLengthUsed = 0L;
m_ash.cbStruct = sizeof(ACMSTREAMHEADER);
mmr= acmStreamPrepareHeader(m_hStream, &m_ash, 0L);
if (MMSYSERR_NOERROR != mmr) { Trace(1, "ERROR: Create (Viewport): Attempt to prepare header for conversion stream failed.\n"); LeaveCriticalSection(&m_CriticalSection); return MMRESULTToHRESULT(mmr); } }
LeaveCriticalSection(&m_CriticalSection); return S_OK; }
|