home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / mac / SiteBldr / AMOVIE / SDK / _SETUP / COMMON.Z / synth.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-17  |  29.3 KB  |  1,262 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (c) 1992 - 1996  Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. // synth.cpp
  13. //
  14. // Audio Signal Generator Source Filter
  15.  
  16.  
  17. #include <windows.h>
  18. #include <streams.h>
  19. #include <math.h>
  20.  
  21. #include <initguid.h>
  22. #include <olectl.h>
  23. #include <olectlid.h>
  24.  
  25. #define _AUDIOSYNTH_IMPLEMENTATION_
  26.  
  27. #include "isynth.h"
  28. #include "synth.h"
  29. #include "synthprp.h"
  30.  
  31. // setup data
  32.  
  33. AMOVIESETUP_MEDIATYPE sudOpPinTypes = { &MEDIATYPE_Audio      // clsMajorType
  34.                                       , &MEDIASUBTYPE_NULL }; // clsMinorType
  35.  
  36. AMOVIESETUP_PIN sudOpPin = { L"Output"          // strName
  37.                            , FALSE              // bRendered
  38.                            , TRUE               // bOutput
  39.                            , FALSE              // bZero
  40.                            , FALSE              // bMany
  41.                            , &CLSID_NULL        // clsConnectsToFilter
  42.                            , L"Input"           // strConnectsToPin
  43.                            , 1                  // nTypes
  44.                            , &sudOpPinTypes };  // lpTypes
  45.  
  46. AMOVIESETUP_FILTER sudSynth = { &CLSID_SynthFilter     // clsID
  47.                                 , L"Audio Synthesizer" // strName
  48.                                 , MERIT_UNLIKELY       // dwMerit
  49.                                 , 1                    // nPins
  50.                                 , &sudOpPin };         // lpPin
  51.  
  52. // -------------------------------------------------------------------------
  53. // g_Templates
  54. // -------------------------------------------------------------------------
  55. // COM global table of objects in this dll
  56.  
  57. CFactoryTemplate g_Templates[2] = {
  58.  
  59.     {L"Audio Synthesizer", &CLSID_SynthFilter, CSynthFilter::CreateInstance},
  60.     {L"Audio Synthesizer Property Page", &CLSID_SynthPropertyPage, CSynthProperties::CreateInstance}
  61.  
  62. };
  63. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
  64.  
  65. // -------------------------------------------------------------------------
  66. // CSynthFilter, the main filter object
  67. // -------------------------------------------------------------------------
  68. //
  69. // CreateInstance
  70. //
  71. // The only allowed way to create Synthesizers
  72.  
  73. CUnknown *CSynthFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) {
  74.  
  75.     CUnknown *punk = new CSynthFilter(lpunk, phr);
  76.     if (punk == NULL) {
  77.         *phr = E_OUTOFMEMORY;
  78.     }
  79.  
  80.     return punk;
  81. }
  82.  
  83. //
  84. // GetSetupData
  85. //
  86. LPAMOVIESETUP_FILTER CSynthFilter::GetSetupData()
  87. {
  88.   return &sudSynth;
  89. }
  90.  
  91. //
  92. // CSynthFilter::Constructor
  93. //
  94. // initialise a CSynthStream object so that we have a pin.
  95.  
  96. CSynthFilter::CSynthFilter(LPUNKNOWN lpunk, HRESULT *phr)
  97.     : CSource(NAME("Audio Synthesizer Filter"),lpunk, CLSID_SynthFilter, phr)
  98.     , CPersistStream(lpunk, phr)
  99.     , m_hWndPropertyPage (NULL) 
  100. {
  101.     CAutoLock l(&m_cStateLock);
  102.  
  103.     m_paStreams    = (CSourceStream **) new CSynthStream*[1];
  104.     if (m_paStreams == NULL) {
  105.         *phr = E_OUTOFMEMORY;
  106.         return;
  107.     }
  108.  
  109.     m_paStreams[0] = new CSynthStream(phr, this, L"Audio Synth Stream");
  110.     if (m_paStreams[0] == NULL) {
  111.         *phr = E_OUTOFMEMORY;
  112.         return;
  113.     }
  114. }
  115.  
  116. //
  117. // CSynthFilter::Destructor
  118. //
  119. CSynthFilter::~CSynthFilter(void) {
  120.  
  121.     //
  122.     //  Base class will free our pins
  123.     //
  124. }
  125.  
  126. //
  127. // NonDelegatingQueryInterface
  128. //
  129. // Reveal our property page, persistance, and control interfaces
  130.  
  131. STDMETHODIMP CSynthFilter::NonDelegatingQueryInterface(REFIID riid, void **ppv) {
  132.  
  133.     CAutoLock l(&m_cStateLock);
  134.  
  135.     if (riid == IID_ISynth) {
  136.         return GetInterface((ISynth *) this, ppv);
  137.     }
  138.     else if (riid == IID_IPersistStream) {
  139.         return GetInterface((IPersistStream *) this, ppv);
  140.     }
  141.     else if (riid == IID_ISpecifyPropertyPages) {
  142.         return GetInterface((ISpecifyPropertyPages *) this, ppv);
  143.     } else {
  144.         return CSource::NonDelegatingQueryInterface(riid, ppv);
  145.     }
  146. }
  147.  
  148.  
  149. //
  150. // GetPages
  151. //
  152. STDMETHODIMP CSynthFilter::GetPages(CAUUID * pPages) {
  153.  
  154.     CAutoLock l(&m_cStateLock);
  155.  
  156.     pPages->cElems = 1;
  157.     pPages->pElems = (GUID *) CoTaskMemAlloc(sizeof(GUID));
  158.     if (pPages->pElems == NULL) {
  159.         return E_OUTOFMEMORY;
  160.     }
  161.     *(pPages->pElems) = CLSID_SynthPropertyPage;
  162.  
  163.     return NOERROR;
  164.  
  165. }
  166.  
  167. // -------------------------------------------------------------------------
  168. // --- IPersistStream ---
  169. // -------------------------------------------------------------------------
  170.  
  171. #define WRITEOUT(var)   hr = pStream->Write(&var, sizeof(var), NULL); \
  172.                         if (FAILED(hr)) return hr;
  173.  
  174. #define READIN(var)     hr = pStream->Read(&var, sizeof(var), NULL); \
  175.                         if (FAILED(hr)) return hr;
  176.  
  177. STDMETHODIMP CSynthFilter::GetClassID(CLSID *pClsid)
  178. {
  179.     *pClsid = CLSID_SynthFilter;
  180.     return NOERROR;
  181. }
  182.  
  183. int CSynthFilter::SizeMax ()
  184. {
  185.     return sizeof (int) * 8;
  186. }
  187.  
  188. HRESULT CSynthFilter::WriteToStream(IStream *pStream)
  189. {
  190.     HRESULT hr;
  191.     int i, k;
  192.  
  193.     get_Frequency (&i);  // don't we wish we'd used a structure, now?
  194.     WRITEOUT(i);
  195.     get_Waveform (&i);
  196.     WRITEOUT(i);
  197.     get_Channels (&i);
  198.     WRITEOUT(i);
  199.     get_BitsPerSample (&i);
  200.     WRITEOUT(i);
  201.     get_SamplesPerSec (&i);
  202.     WRITEOUT(i);
  203.     get_Amplitude (&i);
  204.     WRITEOUT(i);
  205.     get_SweepRange (&i, &k);
  206.     WRITEOUT(i);
  207.     WRITEOUT(k);
  208.  
  209.     return hr;
  210. }
  211.  
  212.  
  213. HRESULT CSynthFilter::ReadFromStream(IStream *pStream)
  214. {
  215.     HRESULT hr;
  216.     int i, k;
  217.  
  218.     READIN(i);
  219.     put_Frequency(i);
  220.     READIN(i);
  221.     put_Waveform (i);
  222.     READIN(i);
  223.     put_Channels (i);
  224.     READIN(i);
  225.     put_BitsPerSample (i);
  226.     READIN(i);
  227.     put_SamplesPerSec (i);
  228.     READIN(i);
  229.     put_Amplitude (i);
  230.     READIN(i);
  231.     READIN(k);
  232.     put_SweepRange (i, k);
  233.  
  234.     return hr;
  235. }
  236.  
  237. // -------------------------------------------------------------------------
  238. // ISynth, the control interface for the synthesizer
  239. // -------------------------------------------------------------------------
  240.  
  241. //
  242. // get_Frequency
  243. //
  244. STDMETHODIMP CSynthFilter::get_Frequency(int *Frequency) {
  245.  
  246.     m_Synth->get_Frequency(Frequency);
  247.  
  248.     DbgLog((LOG_TRACE, 1, TEXT("get_Frequency: %d"), *Frequency));
  249.  
  250.     return NOERROR;
  251. }
  252.  
  253.  
  254. //
  255. // put_Frequency
  256. //
  257. STDMETHODIMP CSynthFilter::put_Frequency(int Frequency) {
  258.  
  259.     m_Synth->put_Frequency (Frequency);
  260.  
  261.     DbgLog((LOG_TRACE, 1, TEXT("put_Frequency: %d"), Frequency));
  262.  
  263.     return NOERROR;
  264. }
  265.  
  266. //
  267. // get_Waveform
  268. //
  269. STDMETHODIMP CSynthFilter::get_Waveform(int *Waveform) {
  270.  
  271.     m_Synth->get_Waveform (Waveform);
  272.  
  273.     DbgLog((LOG_TRACE, 1, TEXT("get_Waveform: %d"), *Waveform));
  274.  
  275.     return NOERROR;
  276. }
  277.  
  278.  
  279. //
  280. // put_Waveform
  281. //
  282. STDMETHODIMP CSynthFilter::put_Waveform(int Waveform) {
  283.  
  284.     m_Synth->put_Waveform (Waveform);
  285.  
  286.     DbgLog((LOG_TRACE, 1, TEXT("put_Waveform: %d"), Waveform));
  287.  
  288.     return NOERROR;
  289. }
  290.  
  291. //
  292. // get_Channels
  293. //
  294. STDMETHODIMP CSynthFilter::get_Channels(int *Channels) {
  295.  
  296.     m_Synth->get_Channels (Channels);
  297.  
  298.     DbgLog((LOG_TRACE, 1, TEXT("get_Channels: %d"), *Channels));
  299.  
  300.     return NOERROR;
  301. }
  302.  
  303. //
  304. // If the format changes, we need to reconnect
  305. //
  306. void CSynthFilter::ReconnectWithNewFormat(void) {
  307.  
  308. //    CAutoLock l(&m_SynthLock);
  309.  
  310.     HRESULT hr;
  311.     IMediaControl *pmc;
  312.     FILTER_STATE  State;
  313.  
  314.     if (!m_pGraph)
  315.         return;
  316.  
  317.     hr = m_pGraph->QueryInterface(IID_IMediaControl, (void **) &pmc);
  318.     if (FAILED(hr)) {
  319.         DbgLog((LOG_TRACE, 1, TEXT("Couldn't get IID_IMediaControl")));
  320.         return;
  321.     }
  322.  
  323.     // Get the state and confirm that the graph is stopped
  324.     GetState (0, &State);
  325.     if (State != State_Stopped)
  326.         return;
  327.  
  328.     CBasePin *pPin = GetPin(0);
  329.     hr = m_pGraph->Reconnect (pPin);       // Renegotiate the format
  330.     if (FAILED(hr)) {
  331.         DbgLog((LOG_TRACE, 1, TEXT("Reconnect")));
  332.         return;
  333.     }
  334.  
  335.     hr = pmc->Release();
  336. }
  337.  
  338.  
  339. //
  340. // put_Channels
  341. //
  342. STDMETHODIMP CSynthFilter::put_Channels(int Channels) {
  343.  
  344.     m_Synth->put_Channels (Channels);
  345.  
  346.     ReconnectWithNewFormat ();
  347.  
  348.     DbgLog((LOG_TRACE, 1, TEXT("put_Channels: %d"), Channels));
  349.  
  350.     return NOERROR;
  351. }
  352.  
  353. //
  354. // get_BitsPerSample
  355. //
  356. STDMETHODIMP CSynthFilter::get_BitsPerSample(int *BitsPerSample) {
  357.  
  358.     m_Synth->get_BitsPerSample (BitsPerSample);
  359.  
  360.     DbgLog((LOG_TRACE, 1, TEXT("get_BitsPerSample: %d"), *BitsPerSample));
  361.  
  362.     return NOERROR;
  363. }
  364.  
  365.  
  366. //
  367. // put_BitsPerSample
  368. //
  369. STDMETHODIMP CSynthFilter::put_BitsPerSample(int BitsPerSample) {
  370.  
  371.     m_Synth->put_BitsPerSample (BitsPerSample);
  372.  
  373.     ReconnectWithNewFormat ();
  374.  
  375.     DbgLog((LOG_TRACE, 1, TEXT("put_BitsPerSample: %d"), BitsPerSample));
  376.  
  377.     return NOERROR;
  378. }
  379.  
  380. //
  381. // get_SamplesPerSec
  382. //
  383. STDMETHODIMP CSynthFilter::get_SamplesPerSec(int *SamplesPerSec) {
  384.  
  385.     m_Synth->get_SamplesPerSec (SamplesPerSec);
  386.  
  387.     DbgLog((LOG_TRACE, 1, TEXT("get_SamplesPerSec: %d"), *SamplesPerSec));
  388.  
  389.     return NOERROR;
  390. }
  391.  
  392.  
  393. //
  394. // put_SamplesPerSec
  395. //
  396. STDMETHODIMP CSynthFilter::put_SamplesPerSec(int SamplesPerSec) {
  397.  
  398.     m_Synth->put_SamplesPerSec (SamplesPerSec);
  399.  
  400.     ReconnectWithNewFormat ();
  401.  
  402.     DbgLog((LOG_TRACE, 1, TEXT("put_SamplesPerSec: %d"), SamplesPerSec));
  403.  
  404.     return NOERROR;
  405. }
  406.  
  407. //
  408. // get_Amplitude
  409. //
  410. STDMETHODIMP CSynthFilter::get_Amplitude(int *Amplitude) {
  411.  
  412.     m_Synth->get_Amplitude (Amplitude);
  413.  
  414.     DbgLog((LOG_TRACE, 1, TEXT("get_Amplitude: %d"), *Amplitude));
  415.  
  416.     return NOERROR;
  417. }
  418.  
  419.  
  420. //
  421. // put_Amplitude
  422. //
  423. STDMETHODIMP CSynthFilter::put_Amplitude(int Amplitude) {
  424.  
  425.     m_Synth->put_Amplitude (Amplitude);
  426.  
  427.     DbgLog((LOG_TRACE, 1, TEXT("put_Amplitude: %d"), Amplitude));
  428.  
  429.     return NOERROR;
  430. }
  431.  
  432.  
  433. //
  434. // get_SweepRange
  435. //
  436. STDMETHODIMP CSynthFilter::get_SweepRange(int *SweepStart, int *SweepEnd) {
  437.  
  438.     m_Synth->get_SweepRange (SweepStart, SweepEnd);
  439.  
  440.     DbgLog((LOG_TRACE, 1, TEXT("get_SweepStart: %d %d"), *SweepStart, *SweepEnd));
  441.  
  442.     return NOERROR;
  443. }
  444.  
  445.  
  446. //
  447. // put_SweepRange
  448. //
  449. STDMETHODIMP CSynthFilter::put_SweepRange(int SweepStart, int SweepEnd) {
  450.  
  451.     m_Synth->put_SweepRange (SweepStart, SweepEnd);
  452.  
  453.     DbgLog((LOG_TRACE, 1, TEXT("put_SweepRange: %d %d"), SweepStart, SweepEnd));
  454.  
  455.     return NOERROR;
  456. }
  457.  
  458.  
  459. //
  460. // put_PropertyPagehWnd
  461. // Our property page passes it's hWnd on creation so we can notify it, via
  462. // a PostMessage, when it needs to disable the controls which affect the
  463. // format.
  464. STDMETHODIMP CSynthFilter::put_PropertyPagehWnd (HWND hWnd) {
  465.  
  466.     m_hWndPropertyPage = hWnd;
  467.  
  468.     DbgLog((LOG_TRACE, 1, TEXT("put_PropertyPagehWnd: %d" ), hWnd));
  469.  
  470.     return NOERROR;
  471. }
  472.  
  473. //
  474. // get_FilterIsStopped
  475. //
  476. // Our property page needs to know if the filter is stopped so it
  477. // can decide whether to enable format change buttons
  478. //
  479. STDMETHODIMP CSynthFilter::get_FilterIsStopped (BOOL *fStopped) {
  480.  
  481.     FILTER_STATE State;
  482.  
  483.     GetState (0, &State);
  484.  
  485.     *fStopped = (State == State_Stopped);
  486.  
  487.     DbgLog((LOG_TRACE, 1, TEXT("get_FilterIsStopped: %d" ), *fStopped));
  488.  
  489.     return NOERROR;
  490. }
  491.  
  492. // -------------------------------------------------------------------------
  493. // CSynthStream, the output pin
  494. // -------------------------------------------------------------------------
  495.  
  496. //
  497. // CSynthStream::Constructor
  498. //
  499.  
  500. CSynthStream::CSynthStream(HRESULT *phr, CSynthFilter *pParent, LPCWSTR pName)
  501.     : CSourceStream(NAME("Audio Synth output pin"),phr, pParent, pName) {
  502.  
  503.     CAutoLock l(m_pFilter->pStateLock());
  504.  
  505.     {
  506.         CAutoLock l(&m_cSharedState);
  507.  
  508.         m_Synth = new CAudioSynth( );
  509.         pParent->m_Synth = m_Synth;
  510.         if (m_Synth == NULL) {
  511.             *phr = E_OUTOFMEMORY;
  512.             return;
  513.         }
  514.     }
  515. }
  516.  
  517.  
  518. //
  519. // CSynthStream::Destructor
  520. //
  521. CSynthStream::~CSynthStream(void) {
  522.  
  523.     CAutoLock l(&m_cSharedState);
  524.  
  525.     delete m_Synth;
  526. }
  527.  
  528.  
  529. //
  530. // FillBuffer
  531. //
  532. // Stuffs the buffer with data
  533. HRESULT CSynthStream::FillBuffer(IMediaSample *pms) {
  534.  
  535.     BYTE *pData;
  536.     long lDataLen;
  537.     int nSamplesPerSec;
  538.     int nBitsPerSample;
  539.     int nChannels;
  540.  
  541.     pms->GetPointer(&pData);
  542.     lDataLen = pms->GetSize();
  543.  
  544.     CAutoLock lShared(&m_cSharedState);
  545.     m_Synth->FillAudioBuffer (pData, lDataLen);
  546.  
  547.     CRefTime rtStart  = m_rtSampleTime;  // the current time is the sample's start
  548.  
  549.     m_Synth->get_SamplesPerSec (&nSamplesPerSec);
  550.     m_Synth->get_BitsPerSample (&nBitsPerSample);
  551.     m_Synth->get_Channels (&nChannels);
  552.  
  553.     m_rtSampleTime += (long) (1000 * lDataLen /
  554.             (nSamplesPerSec * nChannels * nBitsPerSample / 8));
  555.  
  556.     pms->SetTime((REFERENCE_TIME*)&rtStart,
  557.                  (REFERENCE_TIME*)&m_rtSampleTime);
  558.  
  559.     return NOERROR;
  560. }
  561.  
  562.  
  563. //
  564. // Format Support
  565. //
  566.  
  567. //
  568. // GetMediaType
  569. //
  570. HRESULT CSynthStream::GetMediaType(CMediaType *pmt) {
  571.  
  572.     CAutoLock l(m_pFilter->pStateLock());
  573.  
  574.     WAVEFORMATEX *pwf = (WAVEFORMATEX *) pmt->AllocFormatBuffer(sizeof(WAVEFORMATEX));
  575.  
  576.     pwf->wFormatTag = WAVE_FORMAT_PCM;
  577.     int iV;
  578.     m_Synth->get_Channels (&iV);
  579.     pwf->nChannels = (WORD) iV;
  580.     m_Synth->get_SamplesPerSec (&iV);
  581.     pwf->nSamplesPerSec = (DWORD) iV;
  582.     m_Synth->get_BitsPerSample (&iV);
  583.     pwf->wBitsPerSample = (WORD) iV;
  584.     pwf->nBlockAlign = pwf->wBitsPerSample * pwf->nChannels / 8;
  585.     pwf->nAvgBytesPerSec = (int) ((DWORD) pwf->nBlockAlign *
  586.                            pwf->nSamplesPerSec);
  587.     pwf->cbSize = 0;
  588.  
  589.     pmt->SetType(&MEDIATYPE_Audio);
  590.     pmt->SetTemporalCompression(FALSE);
  591.     pmt->SetSubtype(&GUID_NULL);
  592.  
  593.     return NOERROR;
  594. }
  595.  
  596.  
  597. //
  598. // CheckMediaType
  599. //
  600. // Returns E_INVALIDARG if the mediatype is not acceptable, S_OK if it is
  601. HRESULT CSynthStream::CheckMediaType(const CMediaType *pMediaType) {
  602.  
  603.     CAutoLock l(m_pFilter->pStateLock());
  604.  
  605.     if (   (*(pMediaType->Type()) != MEDIATYPE_Audio)   // only output video!
  606.         || (pMediaType->IsTemporalCompressed())         // ...in uncompressed form
  607.         || !(pMediaType->IsFixedSize()) ) {             // ...in fixed size samples
  608.         return E_INVALIDARG;
  609.     }
  610.  
  611.     // Check for the subtypes we support
  612.  
  613.     // Get the format area of the media type
  614.  
  615.     return S_OK;  // This format is acceptable.
  616. }
  617.  
  618. //
  619. // DecideBufferSize
  620. //
  621. // This will always be called after the format has been sucessfully
  622. // negotiated. So we have a look at m_mt to see what format we agreed to.
  623. // Then we can ask for buffers of the correct size to contain them.
  624. HRESULT CSynthStream::DecideBufferSize(IMemAllocator *pAlloc,
  625.                                        ALLOCATOR_PROPERTIES *pProperties)
  626. {
  627.     CAutoLock l(m_pFilter->pStateLock());
  628.     ASSERT(pAlloc);
  629.     ASSERT(pProperties);
  630.     HRESULT hr = NOERROR;
  631.  
  632.     pProperties->cbBuffer = WaveBufferSize;
  633.  
  634.     int nBitsPerSample;
  635.     int nSamplesPerSec;
  636.     int nChannels;
  637.  
  638.     m_Synth->get_SamplesPerSec (&nSamplesPerSec);
  639.     m_Synth->get_BitsPerSample (&nBitsPerSample);
  640.     m_Synth->get_Channels (&nChannels);
  641.  
  642.     pProperties->cBuffers = nChannels * (nSamplesPerSec / pProperties->cbBuffer) * (nBitsPerSample / 8);
  643.     // Get 1/2 second worth of buffers
  644.     pProperties->cBuffers /= 2;
  645.  
  646.     // Ask the allocator to reserve us the memory
  647.  
  648.     ALLOCATOR_PROPERTIES Actual;
  649.     hr = pAlloc->SetProperties(pProperties,&Actual);
  650.     if (FAILED(hr)) {
  651.         return hr;
  652.     }
  653.  
  654.     // Is this allocator unsuitable
  655.  
  656.     if (Actual.cbBuffer < pProperties->cbBuffer) {
  657.         return E_FAIL;
  658.     }
  659.     return NOERROR;
  660. }
  661.  
  662.  
  663. //
  664. // SetMediaType
  665. //
  666. // Overriden from CBasePin.
  667. HRESULT CSynthStream::SetMediaType(const CMediaType *pMediaType) {
  668.  
  669.     CAutoLock l(m_pFilter->pStateLock());
  670.  
  671.     HRESULT hr;         // return code from base class calls
  672.  
  673.     // Pass the call up to my base class
  674.     hr = CSourceStream::SetMediaType(pMediaType);
  675.     if (SUCCEEDED(hr))
  676.         return NOERROR;
  677.     else
  678.         return hr;
  679.  
  680. }
  681.  
  682.  
  683. //
  684. // OnThreadCreate
  685. //
  686. // as we go active reset the stream time to zero
  687. HRESULT CSynthStream::OnThreadCreate(void) {
  688.  
  689.     CAutoLock lShared(&m_cSharedState);
  690.  
  691.     m_rtSampleTime = 0;
  692.  
  693.     return NOERROR;
  694. }
  695.  
  696. //
  697. // Active
  698. //
  699. // Send a message to the property page telling it to disable
  700. // buttons which change the format when the graph starts running
  701. HRESULT CSynthStream::Active  (void) {
  702.     PostMessage (((CSynthFilter *)m_pFilter)->m_hWndPropertyPage, WM_PROPERTYPAGE_ENABLE, 0, 0);
  703.     return CSourceStream::Active();
  704. }
  705.  
  706.  
  707. //
  708. // Inactive
  709. //
  710. // Send a message to the property page telling it to enable
  711. // buttons which change the format when the graph stops running
  712. HRESULT CSynthStream::Inactive  (void) {
  713.     PostMessage (((CSynthFilter *)m_pFilter)->m_hWndPropertyPage, WM_PROPERTYPAGE_ENABLE, 0, 1);
  714.     return CSourceStream::Inactive();
  715. }
  716.  
  717. // -------------------------------------------------------------------------
  718. // CAudioSynth
  719. // -------------------------------------------------------------------------
  720. // Object that knows nothing about ActiveMovie, but just synthesizes
  721. // waveforms
  722.  
  723. CAudioSynth::CAudioSynth(
  724.                 int Frequency,
  725.                 int Waveform,
  726.                 int iBitsPerSample,
  727.                 int iChannels,
  728.                 int iSamplesPerSec,
  729.                 int iAmplitude
  730.                 )
  731.     : m_bWaveCache(NULL),
  732.       m_wWaveCache(NULL)
  733. {
  734.  
  735.     ASSERT(Waveform >= WAVE_SINE);
  736.     ASSERT(Waveform <  WAVE_LAST);
  737.  
  738.     m_iFrequency = Frequency;
  739.     m_iWaveform = Waveform;
  740.     m_iAmplitude = iAmplitude;
  741.     m_iSweepStart = DefaultSweepStart;
  742.     m_iSweepEnd = DefaultSweepEnd;
  743.  
  744.     // init our WAVEFORMATEX structure
  745.     wfex.wFormatTag = WAVE_FORMAT_PCM;
  746.     wfex.wBitsPerSample = iBitsPerSample;
  747.     wfex.nChannels = iChannels;
  748.     wfex.nSamplesPerSec = iSamplesPerSec;
  749.     wfex.nBlockAlign = wfex.wBitsPerSample * wfex.nChannels / 8;
  750.     wfex.nAvgBytesPerSec = ((DWORD) wfex.nBlockAlign *
  751.                            wfex.nSamplesPerSec);
  752.     wfex.cbSize = 0;
  753. }
  754.  
  755. //
  756. // AllocWaveCache
  757. //
  758. //
  759. void CAudioSynth::AllocWaveCache (void) {
  760.     m_iWaveCacheCycles = m_iFrequency;
  761.     m_iWaveCacheSize = (int) wfex.nSamplesPerSec;
  762.  
  763.     if (m_bWaveCache) {
  764.         delete [] m_bWaveCache;
  765.         m_bWaveCache = NULL;
  766.     }
  767.     if (m_wWaveCache) {
  768.         delete [] m_wWaveCache;
  769.         m_wWaveCache = NULL;
  770.     }
  771.  
  772.     if (wfex.wBitsPerSample == 8)
  773.         m_bWaveCache = new BYTE [m_iWaveCacheSize];
  774.     else
  775.         m_wWaveCache = new WORD [m_iWaveCacheSize];
  776. }
  777.  
  778. //
  779. // FillAudioBuffer
  780. //
  781. //
  782. //
  783. void CAudioSynth::FillAudioBuffer (BYTE pBuf[], int iSize) {
  784.     BOOL fCalcCache = FALSE;
  785.  
  786.     CAutoLock l(&m_SynthLock);
  787.  
  788.     // Only realloc the cache if the format has changed !
  789.  
  790.     if ((wfex.nChannels != wfexLast.nChannels) ||
  791.         (wfex.wBitsPerSample != wfexLast.wBitsPerSample) ||
  792.         (wfex.nSamplesPerSec != wfexLast.nSamplesPerSec)) {
  793.  
  794.             fCalcCache = TRUE;
  795.             AllocWaveCache();
  796.             wfexLast = wfex;
  797.     }
  798.     if (m_iFrequency != m_iFrequencyLast) {
  799.             fCalcCache = TRUE;
  800.             m_iFrequencyLast = m_iFrequency;
  801.             wfexLast = wfex;
  802.     }
  803.     if (m_iWaveform != m_iWaveformLast) {
  804.              fCalcCache = TRUE;
  805.              m_iWaveformLast = m_iWaveform;
  806.     }
  807.     if (m_iAmplitude != m_iAmplitudeLast) {
  808.             fCalcCache = TRUE;
  809.             m_iAmplitudeLast = m_iAmplitude;
  810.     }
  811.  
  812.     if (fCalcCache) {
  813.         switch (m_iWaveform) {
  814.  
  815.         case WAVE_SINE:
  816.                 CalcCacheSine ();
  817.                 break;
  818.  
  819.         case WAVE_SQUARE:
  820.                 CalcCacheSquare ();
  821.                 break;
  822.  
  823.         case WAVE_SAWTOOTH:
  824.                 CalcCacheSawtooth ();
  825.                 break;
  826.  
  827.         case WAVE_SINESWEEP:
  828.                 CalcCacheSweep ();
  829.                 break;
  830.  
  831.         }
  832.     }
  833.  
  834.     // Copy cache to output buffers
  835.     if (wfex.wBitsPerSample == 8 && wfex.nChannels == 1) {
  836.         while (iSize--) {
  837.             *pBuf++ = m_bWaveCache[m_iWaveCacheIndex++];
  838.             if (m_iWaveCacheIndex >= m_iWaveCacheSize)
  839.                 m_iWaveCacheIndex = 0;
  840.         }
  841.     }
  842.     else if (wfex.wBitsPerSample == 8 && wfex.nChannels == 2) {
  843.         iSize /= 2;
  844.         while (iSize--) {
  845.             *pBuf++ = m_bWaveCache[m_iWaveCacheIndex];
  846.             *pBuf++ = m_bWaveCache[m_iWaveCacheIndex++];
  847.             if (m_iWaveCacheIndex >= m_iWaveCacheSize)
  848.                 m_iWaveCacheIndex = 0;
  849.         }
  850.     }
  851.     else if (wfex.wBitsPerSample == 16 && wfex.nChannels == 1) {
  852.         WORD * pW = (WORD *) pBuf;
  853.         iSize /= 2;
  854.         while (iSize--) {
  855.             *pW++ = m_wWaveCache[m_iWaveCacheIndex++];
  856.             if (m_iWaveCacheIndex >= m_iWaveCacheSize)
  857.                 m_iWaveCacheIndex = 0;
  858.         }
  859.     }
  860.     else if (wfex.wBitsPerSample == 16 && wfex.nChannels == 2) {
  861.         WORD * pW = (WORD *) pBuf;
  862.         iSize /= 4;
  863.         while (iSize--) {
  864.             *pW++ = m_wWaveCache[m_iWaveCacheIndex];
  865.             *pW++ = m_wWaveCache[m_iWaveCacheIndex++];
  866.             if (m_iWaveCacheIndex >= m_iWaveCacheSize)
  867.                 m_iWaveCacheIndex = 0;
  868.         }
  869.     }
  870.  
  871. }
  872.  
  873. //
  874. // CalcCacheSine
  875. //
  876. //
  877. void CAudioSynth::CalcCacheSine (void) {
  878.  
  879.     int i;
  880.     double d;
  881.     double amplitude;
  882.     double FTwoPIDivSpS;
  883.  
  884.     amplitude = ((wfex.wBitsPerSample == 8) ? 127 : 32767 )
  885.                     * m_iAmplitude / 100;
  886.  
  887.     FTwoPIDivSpS = m_iFrequency * TWOPI / wfex.nSamplesPerSec;
  888.  
  889.     m_iWaveCacheIndex = 0;
  890.     m_iCurrentSample = 0;
  891.  
  892.     if (wfex.wBitsPerSample == 8) {
  893.         BYTE * pB = m_bWaveCache;
  894.  
  895.         for (i = 0; i < m_iWaveCacheSize; i++) {
  896.             d = FTwoPIDivSpS * i;
  897.             *pB++ = (BYTE) (sin (d) * amplitude) + 128;
  898.         }
  899.     }
  900.     else {
  901.         PWORD pW = (PWORD) m_wWaveCache;
  902.  
  903.         for (i = 0; i < m_iWaveCacheSize; i++) {
  904.             d = FTwoPIDivSpS * i;
  905.             *pW++ = (WORD) (sin (d) * amplitude);
  906.         }
  907.     }
  908.  
  909. }
  910.  
  911. //
  912. // CalcCacheSquare
  913. //
  914. //
  915. void CAudioSynth::CalcCacheSquare (void) {
  916.  
  917.     int i;
  918.     double d;
  919.     double FTwoPIDivSpS;
  920.     BYTE b0, b1;
  921.     WORD w0, w1;
  922.  
  923.     b0 = (BYTE) 128 - (127 * m_iAmplitude / 100);
  924.     b1 = (BYTE) 128 + (127 * m_iAmplitude / 100);
  925.     w0 = (WORD) (32767. * m_iAmplitude / 100);
  926.     w1 = (WORD) - (32767. * m_iAmplitude / 100);
  927.  
  928.     FTwoPIDivSpS = m_iFrequency * TWOPI / wfex.nSamplesPerSec;
  929.  
  930.     m_iWaveCacheIndex = 0;
  931.     m_iCurrentSample = 0;
  932.  
  933.     if (wfex.wBitsPerSample == 8) {
  934.         BYTE * pB = m_bWaveCache;
  935.  
  936.         for (i = 0; i < m_iWaveCacheSize; i++) {
  937.             d = FTwoPIDivSpS * i;
  938.             *pB++ = (BYTE) ((sin (d) >= 0) ? b1 : b0);
  939.         }
  940.     }
  941.     else {
  942.         PWORD pW = (PWORD) m_wWaveCache;
  943.  
  944.         for (i = 0; i < m_iWaveCacheSize; i++) {
  945.             d = FTwoPIDivSpS * i;
  946.             *pW++ = (WORD) ((sin (d) >= 0) ? w1 : w0);
  947.         }
  948.     }
  949. }
  950.  
  951. //
  952. // CalcCacheSawtooth
  953. //
  954. void CAudioSynth::CalcCacheSawtooth (void) {
  955.  
  956.     int i;
  957.     double d;
  958.     double amplitude;
  959.     double FTwoPIDivSpS;
  960.     double step;
  961.     double curstep;
  962.     BOOL fLastWasNeg = TRUE;
  963.     BOOL fPositive;
  964.  
  965.     amplitude = ((wfex.wBitsPerSample == 8) ? 255 : 65535 )
  966.                     * m_iAmplitude / 100;
  967.  
  968.     FTwoPIDivSpS = m_iFrequency * TWOPI / wfex.nSamplesPerSec;
  969.     step = amplitude * m_iFrequency / wfex.nSamplesPerSec;
  970.  
  971.     m_iWaveCacheIndex = 0;
  972.     m_iCurrentSample = 0;
  973.  
  974.     BYTE * pB = m_bWaveCache;
  975.     PWORD pW = (PWORD) m_wWaveCache;
  976.  
  977.     for (i = 0; i < m_iWaveCacheSize; i++) {
  978.         d = FTwoPIDivSpS * i;
  979.  
  980.         // OneShot triggered on positive zero crossing
  981.         fPositive = (sin (d) >= 0);
  982.  
  983.         if (fLastWasNeg && fPositive) {
  984.             if (wfex.wBitsPerSample == 8)
  985.                 curstep = 128 - amplitude / 2;
  986.             else
  987.                 curstep = 32768 - amplitude / 2;
  988.         }
  989.         fLastWasNeg = !fPositive;
  990.  
  991.         if (wfex.wBitsPerSample == 8)
  992.             *pB++ = (BYTE) curstep;
  993.         else
  994.             *pW++ = (WORD) (-32767 + curstep);
  995.  
  996.         curstep += step;
  997.     }
  998. }
  999.  
  1000. //
  1001. // CalcCacheSweep
  1002. //
  1003. void CAudioSynth::CalcCacheSweep (void) {
  1004.  
  1005.     int i;
  1006.     double d;
  1007.     double amplitude;
  1008.     double FTwoPIDivSpS;
  1009.     double CurrentFreq;
  1010.     double DeltaFreq;
  1011.  
  1012.     amplitude = ((wfex.wBitsPerSample == 8) ? 127 : 32767 )
  1013.                     * m_iAmplitude / 100;
  1014.  
  1015.     DeltaFreq = ((double) m_iSweepEnd - m_iSweepStart) / m_iWaveCacheSize;
  1016.     CurrentFreq = m_iSweepStart;
  1017.  
  1018.     m_iWaveCacheIndex = 0;
  1019.     m_iCurrentSample = 0;
  1020.  
  1021.     if (wfex.wBitsPerSample == 8) {
  1022.         BYTE * pB = m_bWaveCache;
  1023.         d = 0.0;
  1024.  
  1025.         for (i = 0; i < m_iWaveCacheSize; i++) {
  1026.             FTwoPIDivSpS = (int) CurrentFreq * TWOPI / wfex.nSamplesPerSec;
  1027.             CurrentFreq += DeltaFreq;
  1028.             d += FTwoPIDivSpS;
  1029.             *pB++ = (BYTE) (sin (d) * amplitude) + 128;
  1030.         }
  1031.     }
  1032.     else {
  1033.         PWORD pW = (PWORD) m_wWaveCache;
  1034.         d = 0.0;
  1035.  
  1036.         for (i = 0; i < m_iWaveCacheSize; i++) {
  1037.             FTwoPIDivSpS = (int) CurrentFreq * TWOPI / wfex.nSamplesPerSec;
  1038.             CurrentFreq += DeltaFreq;
  1039.             d += FTwoPIDivSpS;
  1040.             *pW++ = (WORD) (sin (d) * amplitude);
  1041.         }
  1042.     }
  1043. }
  1044.  
  1045. //
  1046. // get_Frequency
  1047. //
  1048. STDMETHODIMP CAudioSynth::get_Frequency(int *Frequency) {
  1049.  
  1050.     *Frequency = m_iFrequency;
  1051.  
  1052.     DbgLog((LOG_TRACE, 1, TEXT("get_Frequency: %d"), *Frequency));
  1053.  
  1054.     return NOERROR;
  1055. }
  1056.  
  1057.  
  1058. //
  1059. // put_Frequency
  1060. //
  1061. STDMETHODIMP CAudioSynth::put_Frequency(int Frequency) {
  1062.  
  1063.     CAutoLock l(&m_SynthLock);
  1064.  
  1065.     m_iFrequency = Frequency;
  1066.  
  1067.     DbgLog((LOG_TRACE, 1, TEXT("put_Frequency: %d"), Frequency));
  1068.  
  1069.     return NOERROR;
  1070. }
  1071.  
  1072. //
  1073. // get_Waveform
  1074. //
  1075. STDMETHODIMP CAudioSynth::get_Waveform(int *Waveform) {
  1076.  
  1077.     *Waveform = m_iWaveform;
  1078.  
  1079.     DbgLog((LOG_TRACE, 1, TEXT("get_Waveform: %d"), *Waveform));
  1080.  
  1081.     return NOERROR;
  1082. }
  1083.  
  1084.  
  1085. //
  1086. // put_Waveform
  1087. //
  1088. STDMETHODIMP CAudioSynth::put_Waveform(int Waveform) {
  1089.  
  1090.     CAutoLock l(&m_SynthLock);
  1091.  
  1092.     m_iWaveform = Waveform;
  1093.  
  1094.     DbgLog((LOG_TRACE, 1, TEXT("put_Waveform: %d"), Waveform));
  1095.  
  1096.     return NOERROR;
  1097. }
  1098.  
  1099. //
  1100. // get_Channels
  1101. //
  1102. STDMETHODIMP CAudioSynth::get_Channels(int *Channels) {
  1103.  
  1104.     *Channels = wfex.nChannels;
  1105.  
  1106.     DbgLog((LOG_TRACE, 1, TEXT("get_Channels: %d"), *Channels));
  1107.  
  1108.     return NOERROR;
  1109. }
  1110.  
  1111.  
  1112. //
  1113. // put_Channels
  1114. //
  1115. STDMETHODIMP CAudioSynth::put_Channels(int Channels) {
  1116.  
  1117.     CAutoLock l(&m_SynthLock);
  1118.  
  1119.     wfex.nChannels = Channels;
  1120.  
  1121.     DbgLog((LOG_TRACE, 1, TEXT("put_Channels: %d"), Channels));
  1122.  
  1123.     return NOERROR;
  1124. }
  1125.  
  1126. //
  1127. // get_BitsPerSample
  1128. //
  1129. STDMETHODIMP CAudioSynth::get_BitsPerSample(int *BitsPerSample) {
  1130.  
  1131.     *BitsPerSample = wfex.wBitsPerSample;
  1132.  
  1133.     DbgLog((LOG_TRACE, 1, TEXT("get_BitsPerSample: %d"), *BitsPerSample));
  1134.  
  1135.     return NOERROR;
  1136. }
  1137.  
  1138.  
  1139. //
  1140. // put_BitsPerSample
  1141. //
  1142. STDMETHODIMP CAudioSynth::put_BitsPerSample(int BitsPerSample) {
  1143.  
  1144.     CAutoLock l(&m_SynthLock);
  1145.  
  1146.     wfex.wBitsPerSample = BitsPerSample;
  1147.  
  1148.     DbgLog((LOG_TRACE, 1, TEXT("put_BitsPerSample: %d"), BitsPerSample));
  1149.  
  1150.     return NOERROR;
  1151. }
  1152.  
  1153. //
  1154. // get_SamplesPerSec
  1155. //
  1156. STDMETHODIMP CAudioSynth::get_SamplesPerSec(int *SamplesPerSec) {
  1157.  
  1158.     *SamplesPerSec = wfex.nSamplesPerSec;
  1159.  
  1160.     DbgLog((LOG_TRACE, 1, TEXT("get_SamplesPerSec: %d"), *SamplesPerSec));
  1161.  
  1162.     return NOERROR;
  1163. }
  1164.  
  1165.  
  1166. //
  1167. // put_SamplesPerSec
  1168. //
  1169. STDMETHODIMP CAudioSynth::put_SamplesPerSec(int SamplesPerSec) {
  1170.  
  1171.     CAutoLock l(&m_SynthLock);
  1172.  
  1173.     wfex.nSamplesPerSec = SamplesPerSec;
  1174.  
  1175.     DbgLog((LOG_TRACE, 1, TEXT("put_SamplesPerSec: %d"), SamplesPerSec));
  1176.  
  1177.     return NOERROR;
  1178. }
  1179.  
  1180. //
  1181. // get_Amplitude
  1182. //
  1183. STDMETHODIMP CAudioSynth::get_Amplitude(int *Amplitude) {
  1184.  
  1185.     *Amplitude =  m_iAmplitude;
  1186.  
  1187.     DbgLog((LOG_TRACE, 1, TEXT("get_Amplitude: %d"), *Amplitude));
  1188.  
  1189.     return NOERROR;
  1190. }
  1191.  
  1192.  
  1193. //
  1194. // put_Amplitude
  1195. //
  1196. STDMETHODIMP CAudioSynth::put_Amplitude(int Amplitude) {
  1197.  
  1198.     CAutoLock l(&m_SynthLock);
  1199.  
  1200.     if (Amplitude > MaxAmplitude || Amplitude < MinAmplitude)
  1201.         return E_INVALIDARG;
  1202.  
  1203.     m_iAmplitude = Amplitude;
  1204.  
  1205.     DbgLog((LOG_TRACE, 1, TEXT("put_Amplitude: %d"), Amplitude));
  1206.  
  1207.     return NOERROR;
  1208. }
  1209.  
  1210.  
  1211. //
  1212. // get_SweepRange
  1213. //
  1214. STDMETHODIMP CAudioSynth::get_SweepRange(int *SweepStart, int *SweepEnd) {
  1215.  
  1216.     *SweepStart = m_iSweepStart;
  1217.     *SweepEnd = m_iSweepEnd;
  1218.  
  1219.     DbgLog((LOG_TRACE, 1, TEXT("get_SweepStart: %d %d"), *SweepStart, *SweepEnd));
  1220.  
  1221.     return NOERROR;
  1222. }
  1223.  
  1224.  
  1225. //
  1226. // put_SweepRange
  1227. //
  1228. STDMETHODIMP CAudioSynth::put_SweepRange(int SweepStart, int SweepEnd) {
  1229.  
  1230.     CAutoLock l(&m_SynthLock);
  1231.  
  1232.     m_iSweepStart = SweepStart;
  1233.     m_iSweepEnd = SweepEnd;
  1234.  
  1235.     DbgLog((LOG_TRACE, 1, TEXT("put_SweepRange: %d %d"), SweepStart, SweepEnd));
  1236.  
  1237.     return NOERROR;
  1238. }
  1239.  
  1240. /******************************Public*Routine******************************\
  1241. * exported entry points for registration and
  1242. * unregistration (in this case they only call
  1243. * through to default implmentations).
  1244. *
  1245. *
  1246. *
  1247. * History:
  1248. *
  1249. \**************************************************************************/
  1250. HRESULT
  1251. DllRegisterServer()
  1252. {
  1253.   return AMovieDllRegisterServer();
  1254. }
  1255.  
  1256. HRESULT
  1257. DllUnregisterServer()
  1258. {
  1259.   return AMovieDllUnregisterServer();
  1260. }
  1261.  
  1262.