2025-04-27 07:49:33 -04:00

314 lines
9.1 KiB
C++

// Simple.cpp : Implementation of CSimple
#include <stdafx.h>
#include <dmobase.h>
#include "Xform.h"
#include "Simple.h"
/////////////////////////////////////////////////////////////////////////////
// CSimple
// Our only supported WAVE format
WAVEFORMATEX wfmtFormat = {
WAVE_FORMAT_PCM,
2, // nChannels
44100, // nSamplesPerSec
176400, // nAvgBytesPerSec
4, // nBlockAlign
16, // wBitsPerSample
0 // extra
};
FORMATENTRY InputFormats[] =
{
{
&MEDIATYPE_Audio, &MEDIASUBTYPE_PCM, &FORMAT_WaveFormatEx, sizeof(WAVEFORMATEX), (BYTE*)&wfmtFormat
}
};
FORMATENTRY OutputFormats[] =
{
{
&MEDIATYPE_Audio, &MEDIASUBTYPE_PCM, &FORMAT_WaveFormatEx, sizeof(WAVEFORMATEX), (BYTE*)&wfmtFormat
}
};
INPUTSTREAMDESCRIPTOR InputStreams[] =
{
{
1, // 1 format
InputFormats,
4, // minimum buffer size
FALSE, // holds buffers
0 // lookahead - doesn't apply because we don't hold buffers
}
};
OUTPUTSTREAMDESCRIPTOR OutputStreams[] =
{
{
1,
OutputFormats,
16384 // minimum buffer size
}
};
//
// Verify that our object supports this format
//
HRESULT VerifyFormat(WAVEFORMATEX *pWaveFormat, ULONG ulSize) {
if (ulSize != sizeof(WAVEFORMATEX)) {
return E_FAIL;
}
if (pWaveFormat->wFormatTag != WAVE_FORMAT_PCM) {
return E_FAIL;
}
if ((pWaveFormat->nChannels != 1) && (pWaveFormat->nChannels != 2)) {
return E_FAIL;
}
if ((pWaveFormat->wBitsPerSample != 8) && (pWaveFormat->wBitsPerSample != 16)) {
return E_FAIL;
}
if ((pWaveFormat->nSamplesPerSec < 2000) || (pWaveFormat->nSamplesPerSec > 500000)) {
return E_FAIL;
}
return NOERROR;
}
HRESULT CSimple::SetFormat(WAVEFORMATEX *pWaveFormat) {
m_bFormatSet = TRUE;
m_nChannels = pWaveFormat->nChannels;
m_b8bit = (pWaveFormat->wBitsPerSample == 8);
m_dwSamplingRate = pWaveFormat->nSamplesPerSec;
return NOERROR;
}
HRESULT CSimple::CompareFormat(WAVEFORMATEX *pWaveFormat) {
if (m_bFormatSet) {
if (pWaveFormat->nChannels != m_nChannels) {
return E_FAIL;
}
if ((pWaveFormat->wBitsPerSample == 8) != m_b8bit) {
return E_FAIL;
}
if (pWaveFormat->nSamplesPerSec != m_dwSamplingRate) {
return E_FAIL;
}
return NOERROR;
}
else {
return NOERROR; // nothing to compare to
}
}
/*
HRESULT CSimple::InputSetType(long lStreamIndex, DMO_MEDIA_TYPE *pmt) {
HRESULT hr;
hr = CGenericDMO::InputSetType(lStreamIndex, pmt);
if (FAILED(hr))
return hr;
hr = VerifyFormat((WAVEFORMATEX*)(pmt->pbFormat), pmt->cbFormat);
if (FAILED(hr))
return hr;
return SetFormat((WAVEFORMATEX*)(pmt->pbFormat));
}
HRESULT CSimple::OutputSetType(long lStreamIndex, DMO_MEDIA_TYPE *pmt) {
HRESULT hr;
hr = CGenericDMO::OutputSetType(lStreamIndex, pmt);
if (FAILED(hr))
return hr;
hr = VerifyFormat(((WAVEFORMATEX*)pmt->pbFormat), pmt->cbFormat);
if (FAILED(hr))
return hr;
if (m_bFormatSet) {
//
// Accept this output format only if it matches the one already set.
// I.e., once a format has been set it must be changed on the input pin,
// then on the output pin.
//
return CompareFormat((WAVEFORMATEX*)(pmt->pbFormat));
}
else {
return SetFormat((WAVEFORMATEX*)pmt->pbFormat);
}
}
*/
#ifndef SIZEOF_ARRAY
#define SIZEOF_ARRAY(ar) (sizeof(ar)/sizeof((ar)[0]))
#endif // !defined(SIZEOF_ARRAY)
HRESULT CSimple::SetupStreams()
{
HRESULT hr;
hr = CreateInputStreams(InputStreams, SIZEOF_ARRAY(InputStreams));
if (FAILED(hr)) {
return hr;
}
hr = CreateOutputStreams(OutputStreams, SIZEOF_ARRAY(OutputStreams));
if (FAILED(hr)) {
return hr;
}
// bugbug - not quite the right place to initialize these
m_bFormatSet = TRUE;
m_nChannels = 2;
m_b8bit = FALSE;
m_dwSamplingRate = 44100;
m_Phase = 0;
m_Period = 2000;
m_Shape = 0;
m_pBuffer = NULL;
return S_OK;
}
HRESULT CSimple::DoProcess(INPUTBUFFER *pInput, OUTPUTBUFFER *pOutput) {
if (!m_bFormatSet)
return DMO_E_TYPE_NOT_SET;
//
// Figure out how many bytes we can process
//
DWORD dwProcess = (pInput->cbSize < pOutput->cbSize) ? pInput->cbSize : pOutput->cbSize; // min
DWORD dwGranularity = (m_b8bit ? 1 : 2) * m_nChannels;
DWORD dwSamples = dwProcess / dwGranularity;
dwProcess = dwSamples * dwGranularity; // process whole samples only
pOutput->cbUsed = dwProcess;
pInput->cbUsed = dwProcess;
if (pInput->cbSize - dwProcess < dwGranularity)
// anything we didn't process is useless by itself
pInput->dwFlags = INPUT_STATUSF_RESIDUAL;
else
pInput->dwFlags = 0;
// Copy any timestamps / flags
pOutput->dwFlags = 0;
if (pInput->dwFlags & DMO_INPUT_DATA_BUFFERF_SYNCPOINT)
pOutput->dwFlags |= DMO_OUTPUT_DATA_BUFFERF_SYNCPOINT;
if (pInput->dwFlags & DMO_INPUT_DATA_BUFFERF_TIME) {
pOutput->dwFlags |= DMO_OUTPUT_DATA_BUFFERF_TIME;
pOutput->rtTimestamp = pInput->rtTimestamp;
}
if (pInput->dwFlags & DMO_INPUT_DATA_BUFFERF_TIMELENGTH) {
pOutput->dwFlags |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
pOutput->rtTimelength = pInput->rtTimelength;
}
Gargle(pInput->pData, pOutput->pData, dwSamples);
return NOERROR;
}
void CSimple::Gargle(BYTE *pIn, BYTE *pOut, DWORD dwSamples) {
//
// Gargle !
//
DWORD cSample, cChannel;
for (cSample = 0; cSample < dwSamples; cSample++) {
// If m_Shape is 0 (triangle) then we multiply by a triangular waveform
// that runs 0..Period/2..0..Period/2..0... else by a square one that
// is either 0 or Period/2 (same maximum as the triangle) or zero.
//
// m_Phase is the number of samples from the start of the period.
// We keep this running from one call to the next,
// but if the period changes so as to make this more
// than Period then we reset to 0 with a bang. This may cause
// an audible click or pop (but, hey! it's only a sample!)
//
++m_Phase;
if (m_Phase>m_Period) m_Phase = 0;
int M = m_Phase; // m is what we modulate with
if (m_Shape ==0 ) { // Triangle
if (M>m_Period/2) M = m_Period-M; // handle downslope
} else { // Square wave
if (M<=m_Period/2) M = m_Period/2; else M = 0;
}
for (cChannel = 0; cChannel < m_nChannels; cChannel++) {
if (m_b8bit==1) {
// 8 bit sound uses 0..255 representing -128..127
// Any overflow, even by 1, would sound very bad.
// so we clip paranoically after modulating.
// I think it should never clip by more than 1
//
int i = pIn[cSample * m_nChannels + cChannel] - 128; // sound sample, zero based
i = (i*M*2)/m_Period; // modulate
if (i>127) i = 127; // clip
if (i<-128) i = -128;
pOut[cSample * m_nChannels + cChannel] = (unsigned char)(i+128); // reset zero offset to 128
} else {
// 16 bit sound uses 16 bits properly (0 means 0)
// We still clip paranoically
//
int i = ((short*)pIn)[cSample * m_nChannels + cChannel];// in a register, we might hope
i = (i*M*2)/m_Period; // modulate
if (i>32767) i = 32767; // clip
if (i<-32768) i = -32768;
((short*)pOut)[cSample * m_nChannels + cChannel] = (short)i;
}
}
}
}
/*
HRESULT CSimple::DoProcess(BYTE *pIn,
DWORD dwAvailable,
DWORD *pdwConsumed,
BOOL fInEOS,
BYTE *pOut,
DWORD dwBufferSize,
DWORD *pdwProduced,
BOOL *pfOutEOS) {
if (!m_bFormatSet)
return SHELLOBJECT_E_TYPE_NOT_SET;
if (dwAvailable == 0) {
*pdwProduced = 0;
return NOERROR; // this is normal after EndOfStream
}
//
// Find out how many samples/bytes we want to process
//
DWORD dwProcess = (dwAvailable < dwBufferSize) ? dwAvailable : dwBufferSize; // min
DWORD dwGranularity = (m_b8bit ? 1 : 2) * m_nChannels;
DWORD dwSamples = dwProcess / dwGranularity;
dwProcess = dwSamples * dwGranularity; // process whole samples only
//
// This object does not buffer anything, so an EnfOfStream
// on the input translates directly into one on the output.
// Unless the output buffer is too short to process all of
// the input.
//
if (dwProcess / dwGranularity < dwAvailable / dwGranularity)
*pfOutEOS = FALSE; // can't process everything.
else
*pfOutEOS = fInEOS;
*pdwConsumed = dwProcess;
*pdwProduced = dwProcess;
return NOERROR;
}
*/