home *** CD-ROM | disk | FTP | other *** search
- //==========================================================================;
- //
- // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
- // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
- // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
- // PURPOSE.
- //
- // Copyright (c) 1992 - 1996 Microsoft Corporation. All Rights Reserved.
- //
- //--------------------------------------------------------------------------;
-
- /*
- * Gargle Filter - A Transform filter that turns humans into daleks!!!
- *
- * Known problems:
- * 1. The properties sheet does NOT give real-time control.
- * It affects the samples that are being processed. This
- * means that there can be a long latency between moving the knob
- * and anything actually happening
- * 2. It doesn't handle read-only streams.
- * 3. The track bar doesn't get initialised with the current setting
- *
- */
-
- /* An example of a transform-in-place filter.
- This filter has one input pin, one output pin and
- does its transform in-place (i.e. without copying the data)
- on the push thread (i.e. it is called with a buffer, which it
- transforms and gives to the next filter downstream. It is
- then blocked until that filter returns. It then returns
- to its own caller.
-
- The filter modulates sound by multiplying the value of each sample
- by a relatively slowly varying triangular waveform. Depending on
- the frequency of the modulation it will sound like recurent fading,
- like a tremolo or like a sort of distortion.
-
- It has a properties page which allows control of one property
- (the frequency of the modulating waveform). It exports a private
- interface (IGargle) which the properties page uses to get or set
- the frequency.
-
- As far as possible the properties page code has been separated into
- is implemented in the files GargProp.* whereas the basic filter
- code is in this file.
-
- The word "sample" is used in two senses. It means either a sound sample
- which is 8 or 16 bits of data representing the instantanious sound pressure
- or else it means a quartz sample which is the unit of data that is passed
- between filters, i.e. a buffer full of sound samples.
- */
-
-
- #include <streams.h> // quartz, includes windows
-
- #include <initguid.h>
- #include <olectl.h>
- #include <olectlid.h>
-
- #include "GargUids.h" // our own uuids
-
- // The next two are only concerned with properties.
- #include "IGargle.h" // IGargle (properties)
- #include "GargProp.h" // CGargleProperties
- #include "Gargle.h" // CGargle
-
- // Put out the name of the function and instance on the debugger.
- #define DbgFunc(a) DbgLog(( LOG_TRACE \
- , 2 \
- , TEXT("CGargle(Instance %d)::%s") \
- , m_nThisInstance \
- , TEXT(a) \
- ));
-
- // setup data
-
- AMOVIESETUP_MEDIATYPE sudPinTypes = { &MEDIATYPE_Audio // clsMajorType
- , &MEDIASUBTYPE_NULL } ; // clsMinorType
-
- AMOVIESETUP_PIN psudPins[] = { { L"Input" // strName
- , FALSE // bRendered
- , FALSE // bOutput
- , FALSE // bZero
- , FALSE // bMany
- , &CLSID_NULL // clsConnectsToFilter
- , L"Output" // strConnectsToPin
- , 1 // nTypes
- , &sudPinTypes } // lpTypes
- , { L"Output" // strName
- , FALSE // bRendered
- , TRUE // bOutput
- , FALSE // bZero
- , FALSE // bMany
- , &CLSID_NULL // clsConnectsToFilter
- , L"Input" // strConnectsToPin
- , 1 // nTypes
- , &sudPinTypes } }; // lpTypes
-
-
- AMOVIESETUP_FILTER sudGargle = { &CLSID_Gargle // clsID
- , L"Gargle Filter" // strName
- , MERIT_DO_NOT_USE // dwMerit
- , 2 // nPins
- , psudPins }; // lpPin
-
-
- // Needed for the CreateInstance mechanism
- CFactoryTemplate g_Templates[2]=
- { { L"Gargle filter" , &CLSID_Gargle , CGargle::CreateInstance }
- , { L"Gargle filter Property Page", &CLSID_GargProp, CGargleProperties::CreateInstance}
- };
-
- int g_cTemplates = sizeof(g_Templates)/sizeof(g_Templates[0]);
-
- // initialise the static instance count.
- int CGargle::m_nInstanceCount = 0;
-
- //
- // CGargle::Constructor
- //
- CGargle::CGargle(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr)
- : CTransInPlaceFilter (tszName, punk, CLSID_Gargle, phr)
- , CPersistStream(punk, phr)
- , m_DefaultGargleRate (DefaultGargleRate)
- , m_GargleRate (DefaultGargleRate)
- , m_SamplesPerSec (0)
- , m_BytesPerSample (0)
- , m_Channels (0)
- , m_Phase (0)
- , m_Shape (0)
- {
- m_nThisInstance = ++m_nInstanceCount;
-
- DbgFunc("CGargle");
- } // (CGargle constructor)
-
-
- //
- // CreateInstance
- //
- // Provide the way for COM to create a CGargle object
- CUnknown *CGargle::CreateInstance(LPUNKNOWN punk, HRESULT *phr) {
-
- CGargle *pNewObject = new CGargle(NAME("Gargle Filter"), punk, phr);
- if (pNewObject == NULL) {
- *phr = E_OUTOFMEMORY;
- }
-
- return pNewObject;
- } // CreateInstance
-
-
- //
- // GetSetupData
- //
- LPAMOVIESETUP_FILTER CGargle::GetSetupData()
- {
- return &sudGargle;
- }
-
- //
- // NonDelegatingQueryInterface
- //
- // Reveal our persistent stream, property pages and IGargle interfaces
- STDMETHODIMP CGargle::NonDelegatingQueryInterface(REFIID riid, void **ppv) {
-
- if (riid == IID_IGargle) {
- return GetInterface((IGargle *) this, ppv);
- } else if (riid == IID_ISpecifyPropertyPages) {
- return GetInterface((ISpecifyPropertyPages *) this, ppv);
- } else if (riid == IID_IPersistStream) {
- AddRef(); // Add a reference count to ourselves
- *ppv = (void *)(IPersistStream *)this;
- return NOERROR;
-
- // was: return GetInterface((IPersistStream *) this, ppv);
- // but after reading combase.cpp GetInterface, I didn't understand that.
- } else {
- return CTransInPlaceFilter::NonDelegatingQueryInterface(riid, ppv);
- }
- } // NonDelegatingQueryInterface
-
-
- STDMETHODIMP CGargle::GetClassID(CLSID *pClsid)
- {
- if (pClsid==NULL) {
- return E_POINTER;
- }
- *pClsid = CLSID_Gargle;
- return NOERROR;
- }
-
-
- int CGargle::SizeMax()
- {
- return 24;
- }
-
- HRESULT CGargle::WriteToStream(IStream *pStream)
- {
- HRESULT hr;
- hr = WriteInt(pStream, m_GargleRate);
- if (FAILED(hr)) return hr;
- hr = WriteInt(pStream, m_Shape);
- if (FAILED(hr)) return hr;
- return NOERROR;
- }
-
-
- HRESULT CGargle::ReadFromStream(IStream *pStream)
- {
- HRESULT hr;
- m_GargleRate = ReadInt(pStream, hr);
- if (FAILED(hr)) return hr;
- m_Shape = ReadInt(pStream, hr);
- if (FAILED(hr)) return hr;
- return NOERROR;
- }
-
-
- // We make a total mess of the sound by modulating it with a waveform.
- // We know the frequency of the modulation (from the slider setting).
- // Uses and updates m_Phase
- // Uses m_SamplesPerSec, m_Channels, m_GargleRate, m_Shape
- void CGargle::MessItAbout(PBYTE pb, int cb)
- {
- // We know how many samples per sec and how
- // many channels so we can calculate the modulation period in samples.
- CAutoLock foo(&m_GargleLock);
-
- int Period = (m_SamplesPerSec * m_Channels) / m_GargleRate;
-
-
- while (cb>0) {
- --cb;
-
- // multiply by a triangular waveform
- // that runs 0..Period/2..0..Period/2..0...
- // or a square wave that is either 0 or Period/2
- {
- // 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.
- ++m_Phase;
- if (m_Phase>Period) m_Phase = 0;
-
- int M = m_Phase; // m is what we modulate with
- if (m_Shape ==0 ) {
- // Triangle
- if (M>Period/2) M = Period-M; // downslope
- } else {
- // Square wave
- if (M<=Period/2) M = Period/2; else M = 0;
- }
-
- if (m_BytesPerSample==1) {
- // 8 bit sound uses 0..255 representing -128..127
- int i = *pb-128; // sound sample, zero based
- i = (i*M*2)/Period;
- if (i>127) i = 127;
- if (i<-128) i = -128;
- *pb = (unsigned char)(i+128); // reset zero
- } else if (m_BytesPerSample==2) {
- // 16 bit sound uses 16 bits properly (0 means 0)
- short int *psi = (short int *)pb;
- int i = *psi;
- i = (i*M*2)/Period;
- if (i>32767) i = 32767;
- if (i<-32768) i = -32768;
- *psi = (short)i;
- ++pb; // nudge it on another 8 bits here
- --cb; // and nudge the count too.
- } else {
- DbgBreak("Too many bytes per sample");
- // just leave it alone!
- }
- }
- ++pb; // move on 8 bits to next sound sample
- }
- } // MessItAbout
-
-
-
- //
- // Transform
- //
- // Convert the input quartz sample into the output quartz sample.
- //
- HRESULT CGargle::Transform(IMediaSample *pSample) {
-
- DbgFunc("Transform");
-
- // Get the details of the data (address, length)
-
- BYTE *pSampleBuffer;
- int iSize = pSample->GetSize();
- pSample->GetPointer(&pSampleBuffer);
-
-
- // Actually transform the data
-
- MessItAbout(pSampleBuffer, iSize );
-
- return NOERROR;
-
- } // Transform
-
-
-
- //
- // CheckInputType
- //
- // We only work for wave audio, 8 or 16 bit, uncompressed.
- //
- HRESULT CGargle::CheckInputType(const CMediaType *pmt) {
- DbgFunc("CheckInputType");
-
- WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmt->pbFormat;
- DbgLog((LOG_TRACE,1,TEXT("Format length %d"),pmt->cbFormat));
-
- #ifdef DEBUG
-
- const int iGUID_STRING = 128;
-
- // Dump the GUID types
-
- DbgLog((LOG_TRACE,2,TEXT("Major type %s"),GuidNames[pmt->majortype]));
- DbgLog((LOG_TRACE,2,TEXT("Subtype %s"),GuidNames[pmt->subtype]));
-
- // Dump the generic media types
-
- DbgLog((LOG_TRACE,2,TEXT("Fixed size sample %d"),pmt->bFixedSizeSamples));
- DbgLog((LOG_TRACE,2,TEXT("Temporal compression %d"),pmt->bTemporalCompression));
- DbgLog((LOG_TRACE,2,TEXT("Sample size %d"),pmt->lSampleSize));
- DbgLog((LOG_TRACE,2,TEXT("Format size %d"),pmt->cbFormat));
-
- #endif
-
-
- // reject non-Audio type
- if (pmt->majortype != MEDIATYPE_Audio) {
- return E_INVALIDARG;
- }
-
-
- #ifdef DEBUG
-
- // Now that we know it's audio we can
- // Dump the contents of the WAVEFORMATEX type-specific format structure
-
- DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag));
- DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels));
- DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec));
- DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec));
- DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign));
- DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample));
-
- // PCM uses a WAVEFORMAT and does not have the extra size field
-
- if (pmt->cbFormat >= sizeof(WAVEFORMATEX)) {
- DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize));
- }
-
- #endif
-
- // Reject invalid format blocks
- if (pmt->cbFormat < sizeof(PCMWAVEFORMAT))
- return E_INVALIDARG;
-
- // Reject compressed audio
- if (pmt->bTemporalCompression) {
- return E_INVALIDARG;
- }
-
- // Accept only 8 or 16 bit
- if (pwfx->wBitsPerSample!=8 && pwfx->wBitsPerSample!=16) {
- return E_INVALIDARG;
- }
-
- return NOERROR;
- } // CheckInputType
-
-
- //
- // SetMediaType
- //
- // This is called when a connection attempt has succeeded. If the output pin
- // is being connected and the input pin's media type does not agree then we
- // reconnect the input (thus allowing its media type to change,) and vice versa.
- //
- HRESULT CGargle::SetMediaType(PIN_DIRECTION direction,const CMediaType *pmt){
-
- DbgFunc("SetMediaType");
-
- // Record what we need for doing the actual transform
-
- WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmt->Format();
- m_Channels = pwfx->nChannels;
- m_SamplesPerSec = pwfx->nSamplesPerSec;
- // Ignored: pwfx->nAvgBytesPerSec;
- // Ignored: pwfx->nBlockAlign;
- m_BytesPerSample = pwfx->wBitsPerSample/8;
-
- // Call the base class to do its thing
- CTransInPlaceFilter::SetMediaType(direction, pmt);
-
- if( m_pInput->IsConnected() && m_pOutput->IsConnected() ){
- FILTER_INFO fInfo;
-
- QueryFilterInfo( &fInfo );
-
- if (direction == PINDIR_OUTPUT && *pmt != m_pInput->CurrentMediaType() )
- fInfo.pGraph->Reconnect( m_pInput );
-
- QueryFilterInfoReleaseGraph( fInfo );
-
- ASSERT(!(direction == PINDIR_INPUT && *pmt != m_pOutput->CurrentMediaType()));
- }
-
- return NOERROR;
-
- } // SetMediaType
-
-
- // ==============Implementation of the private IGargle Interface ==========
- // ==================== neded to support the property page ===============
-
-
- //
- // get_GargleRate
- //
- // Set *GargleRate to our current rate (Hz)
- //
- STDMETHODIMP CGargle::get_GargleRate(int *GargleRate) {
-
- CAutoLock foo(&m_GargleLock);
-
- *GargleRate = m_GargleRate;
-
- DbgLog((LOG_TRACE, 1, TEXT("get_GargleRate: %d"), *GargleRate));
-
- return NOERROR;
- } // get_GargleRate
-
-
-
-
- //
- // put_GargleRate
- //
- // set the current rate from GargleRate
- //
- STDMETHODIMP CGargle::put_GargleRate(int GargleRate) {
-
- CAutoLock foo(&m_GargleLock);
-
- m_GargleRate = GargleRate;
- SetDirty(TRUE); // Need to scribble
-
- DbgLog((LOG_TRACE, 1, TEXT("put_GargleRate: %x"), m_GargleRate));
-
- return NOERROR;
- } // put_GargleRate
-
-
- //
- // put_DefaultGargleRate
- //
- // Setthe current gargle rate to the default
- //
- STDMETHODIMP CGargle::put_DefaultGargleRate(void) {
-
- CAutoLock foo(&m_GargleLock);
-
- DbgLog((LOG_TRACE, 1, TEXT("put_DefaultGargleRate")));
-
- m_GargleRate = m_DefaultGargleRate;
- SetDirty(TRUE); // Need to scribble
-
- return NOERROR;
- } // put_DefaultGargleRate
-
-
- //
- // put_GargleShape
- //
- // Alter the waveform between triangle and square
- //
- STDMETHODIMP CGargle::put_GargleShape(int iGargleShape) {
- if (iGargleShape<0 || iGargleShape>1)
- return E_INVALIDARG;
- m_Shape = iGargleShape;
- SetDirty(TRUE); // Need to scribble
- return NOERROR;
- }
-
-
- //
- // get_GargleShape
- //
- // Return 0 if the current shape is triangle, 1 if it's square
- //
- STDMETHODIMP CGargle::get_GargleShape(int *GargleShape) {
- *GargleShape = m_Shape;
- return NOERROR;
- }
-
-
- // ==============Implementation of the IPropertypages Interface ===========
-
- //
- // GetPages
- //
-
- STDMETHODIMP CGargle::GetPages(CAUUID * pPages) {
-
- pPages->cElems = 1;
- pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
- if (pPages->pElems == NULL) {
- return E_OUTOFMEMORY;
- }
- *(pPages->pElems) = CLSID_GargProp;
-
- return NOERROR;
-
- } // GetPages
-
- /******************************Public*Routine******************************\
- * exported entry points for registration and
- * unregistration (in this case they only call
- * through to default implmentations).
- *
- *
- *
- * History:
- *
- \**************************************************************************/
- HRESULT
- DllRegisterServer()
- {
- return AMovieDllRegisterServer();
- }
-
- HRESULT
- DllUnregisterServer()
- {
- return AMovieDllUnregisterServer();
- }
-
- #pragma warning(disable: 4514) // "unreferenced inline function has been removed"
-
-