home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the 3D Game Programming Gurus / gurus.iso / DirectX / dx9sdkcp.exe / SDK (C++) / Bin / DXUtils / Visual Studio 6.0 Wizards / AEDMOWiz.awx / TEMPLATE / CLASSNAME.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2002-12-11  |  67.7 KB  |  2,241 lines

  1. //------------------------------------------------------------------------------
  2. // File: $$CLASS_NAME$$.cpp
  3. //
  4. // Desc: Audio Effect DMO Wizard generated code - Implementation of $$CLASS_NAME$$
  5. //
  6. // Author: $$DSDMO_AUTHOR$$
  7. //
  8. // Copyright (c) Microsoft Corporation.  All rights reserved.
  9. //------------------------------------------------------------------------------
  10.  
  11. /////////////////////////////////////////////////////////////////////////////
  12. // TODO List:
  13. //  - Implement DoProcess()
  14. //  - Complete implementation of $$CLASS_NAME$$() and ~$$CLASS_NAME$$() if necessary
  15. //  - Complete implementation of UpdateStatesInternal() if necessary
  16. //  - Modify implementation of Process() if necessary
  17. //  - Complete or modify implementation of InternalProcessInput() if necessary
  18. //  - Complete or modify implementation of InternalProcessOutput() if necessary
  19. $$IF(SUPPORT_DS_IMEDPARAM || SUPPORT_DS_DMP)
  20. //  - Complete implementation of SetAllParameters()
  21. //  - Complete implementation of GetAllParameters()
  22. //  - Complete implementation of SetParamInternal()
  23. $$ENDIF
  24. //  - Implement your custom member functions
  25. //
  26. //  Optional to Implement or Complete Implementation of:
  27. //  - InternalAllocateStreamingResources()
  28. //  - InternalFreeStreamingResources()
  29. //  - InternalAcceptingInput()
  30. //  - InternalDiscontinuity()
  31. //  - InternalFlush()
  32. //  - InternalSetInputMaxLatency()
  33. //  - InternalGetInputMaxLatency()
  34. //  - GetLatency()
  35. //
  36. /////////////////////////////////////////////////////////////////////////////
  37.  
  38.  
  39. #include "stdafx.h"
  40.  
  41. #define _ATL_FREE_THREADED
  42. #define _ATL_STATIC_REGISTRY
  43.  
  44. #include <atlbase.h>
  45. //You may derive a class from CComModule and use it if you want to override
  46. //something, but do not change the name of _Module
  47. extern CComModule _Module;
  48. #include <atlcom.h>
  49. #include <atlctl.h>
  50. #include <statreg.h>
  51. #include <statreg.cpp>
  52. #include <atlimpl.cpp>
  53.  
  54. #include "resource.h"
  55. #define FIX_LOCK_NAME
  56. #include <dmo.h>
  57. #include <dmoimpl.h>
  58. #include <initguid.h>
  59. $$IF(SUPPORT_DS_IMEDPARAM || SUPPORT_DS_DMP)
  60. #include "param.h"        // (param.h must come before uuids to avoid redefinitions)
  61. $$ENDIF
  62.  
  63. #include "$$CLASS_NAME$$.h"
  64. #include <mmreg.h>
  65.  
  66.  
  67. /////////////////////////////////////////////////////////////////////////////
  68. // $$CLASS_NAME$$
  69.  
  70. ///////////////////////
  71. //
  72. // $$CLASS_NAME$$::$$CLASS_NAME$$
  73. //
  74. //  Constructor for $$CLASS_NAME$$.
  75. //
  76. $$CLASS_NAME$$::$$CLASS_NAME$$()
  77. {
  78.     // Initialization
  79.     m_fDirty = TRUE;
  80.     m_fInitialized = FALSE;
  81.  
  82. $$IF(SUPPORT_DS_IMEDPARAM || SUPPORT_DS_DMP)
  83.     // Initialize parameters in IMediaParam
  84.     InitParams(1, &GUID_TIME_REFERENCE, 0, 0, sizeof(g_params)/sizeof(*g_params), g_params);
  85.  
  86. $$ENDIF
  87.     // These variables will get reintialized when input type is set
  88.     m_nChannels = 0;
  89.     m_wBitsPerSample = 0;
  90.     m_nSamplesPerSec = 0;
  91.  
  92. // TODO: Initialize member variables here if necessary.
  93. $$IF(EMPTY_DSDMO)
  94.     // Example:
  95.     m_dwParam1 = 0;
  96.     // End of Example
  97. $$ELSE    // Sample DMO
  98.     m_fFreq = 6;
  99.     m_fWidth = 0.85f;
  100.  
  101.     m_ulPeriod = 0;
  102.     m_fSineTablePeriod = 0;
  103.     m_ulPhase = 0;
  104. $$ENDIF
  105.  
  106. };
  107.  
  108.  
  109. ///////////////////////
  110. //
  111. // $$CLASS_NAME$$::~$$CLASS_NAME$$
  112. //
  113. //  Destructor for $$CLASS_NAME$$.
  114. //
  115. $$CLASS_NAME$$::~$$CLASS_NAME$$()
  116. {
  117.     // Free streaming resources in case it hasn't been done by the client
  118.     InternalFreeStreamingResources();
  119.  
  120. // TODO: Add to the destructor if necessary
  121.  
  122. };
  123.  
  124.  
  125. ///////////////////////
  126. //
  127. // $$CLASS_NAME$$::UpdateStatesInternal
  128. //
  129. //  Update internal states
  130. //
  131. HRESULT $$CLASS_NAME$$::UpdateStatesInternal()
  132. {
  133.     HRESULT hr = S_OK;
  134.  
  135. // TODO: Update DMO states here
  136. $$IF(!EMPTY_DSDMO)    // Sample DMO
  137.         m_ulPeriod = (LONG)(m_nSamplesPerSec / m_fFreq);
  138.         m_fSineTablePeriod = (float)( (m_ulPeriod / 4.0) / SINE_TABLE_SIZE );
  139. $$ENDIF
  140.  
  141.     return hr;
  142. }
  143.  
  144.  
  145. ///////////////////////////////
  146. //
  147. // IMediaObjectInPlace Methods
  148. //
  149.  
  150. ///////////////////////
  151. //
  152. // IMediaObjectInPlace::Process
  153. //
  154. //  The Process method processes a block of data. The application supplies a
  155. //  pointer to a block of input data. The DMO processes the data in place.
  156. //
  157. //  Parameters
  158. //
  159. //      ulSize
  160. //          [in] Size of the data, in bytes.
  161. //
  162. //      pData
  163. //          [in, out] Pointer to a buffer of size ulSize. On input, the buffer
  164. //          holds the input data. If the method returns successfully, the
  165. //          buffer contains the output data.
  166. //
  167. //      refTimeStart
  168. //          [in] Start time of the data.
  169. //
  170. //      dwFlags
  171. //          [in] Either DMO_INPLACE_NORMAL or DMO_INPLACE_ZERO. See Remarks
  172. //          for more information.
  173. //
  174. //  Return Value
  175. //      S_FALSE Success. There is still data to process.
  176. //      S_TRUE Success. There is no remaining data to process.
  177. //      E_FAIL Failure.
  178. //
  179. //  If the method fails, the buffer might contain garbage. The application
  180. //  should not use the contents of the buffer.
  181. //
  182. //  The DMO might produce output data beyond the length of the input data. This
  183. //  is called an effect tail. For example, a reverb effect continues after the
  184. //  input reaches silence. If the DMO has an effect tail, this method returns
  185. //  S_FALSE.
  186. //
  187. //  While the application has input data for processing, call the Process
  188. //  method with the dwFlags parameter set to DMO_INPLACE_NORMAL. If the last
  189. //  such call returns S_FALSE, call Process again, this time with a zeroed input
  190. //  buffer and the DMO_INPLACE_ZERO flag. The DMO will now fill the zeroed buffer
  191. //  with the effect tail. Continue calling Process in this way until the return
  192. //  value is S_TRUE, indicating that the DMO has finished processing the effect
  193. //  tail.
  194. //
  195. //  If the DMO has no effect tail, this method always returns S_TRUE (or an error code).
  196. //
  197. HRESULT $$CLASS_NAME$$::Process(ULONG ulSize, BYTE *pData, REFERENCE_TIME refTimeStart, DWORD dwFlags)
  198. {
  199.  
  200. // TODO: Modify implementation of Process() if necessary
  201.  
  202.     HRESULT hr = S_OK;
  203.  
  204.     if (!m_fInitialized)
  205.     {
  206.         hr = AllocateStreamingResources();
  207.     }
  208.  
  209.     if (SUCCEEDED(hr))
  210.     {
  211.  
  212. $$IF(SUPPORT_DS_IMEDPARAM || SUPPORT_DS_DMP)
  213.         // Update parameter values from any curves that may be in effect.
  214.         // We pick up the current values stored in the CParamsManager helper for time rtStart.
  215.  
  216.         // Note that we are using IMediaParams in a less than
  217.         // perfect way. We update at the beginning of every time slice instead of smoothly over the curve.
  218.         // This is okay for an effect like gargle as long as the time slice is consistently small (which
  219.         // it conveniently is when hosted in DirectSound).
  220.  
  221.         // Here are some suggestions of how it can be done, with increasing degree of accuracy. Different
  222.         // types of effects and effect parameters require different levels of accuracy, so no solution is the best
  223.         // solution for all (especially if you are concerned about CPU cost.)
  224.         // 1) Break the time slice up into mini pieces of some number of milliseconds
  225.         // each and run through all the steps in Process for each sub slice. This guarantees the
  226.         // stair stepping is small enough not to be noticable. This approach will work well for parameters
  227.         // that don't create an audible stair stepping noise (or "zipper") noise when controled in this way.
  228.         // Control over volume, for example, does not work well.
  229.         // 2) Use the above mechanism, but pass the start and end values for each parameter to the
  230.         // processing engine. It, in turn, applies linear interpolation to each parameter. This results
  231.         // in a smooth approximation of the parameter curve and removes all but the most subtle aliasing noise.
  232.         // 3) Pass the curves directly to the processing engine, which accurately calculates each sample
  233.         // mathematically. This is obviously the best, but most complex and CPU intensive.
  234.         this->UpdateActiveParams(refTimeStart, *this);
  235. $$ENDIF
  236.  
  237.         // Process the data
  238.         hr = DoProcess(pData, pData, ulSize / WaveFormat()->nBlockAlign);
  239.     }
  240.     return hr;
  241. }
  242.  
  243.  
  244. /////////////////////
  245. //
  246. //  IMediaObjectInPlace::Clone
  247. //
  248. //  The Clone method creates a copy of the DMO in its current state.
  249. //
  250. //  Parameters
  251. //
  252. //      ppMediaObject
  253. //          [out] Address of a pointer to receive the new DMO's
  254. //          IMediaObjectInPlace interface.
  255. //
  256. //  Return Value
  257. //      Returns S_OK if successful. Otherwise, returns an HRESULT value
  258. //      indicating the cause of the error.
  259. //
  260. //  If the method succeeds, the IMediaObjectInPlace interface that it returns
  261. //  has an outstanding reference count. Be sure to release the interface when
  262. //  you are finished using it.
  263. //
  264. HRESULT $$CLASS_NAME$$::Clone(IMediaObjectInPlace **ppMediaObject)
  265. {
  266.     // Check the input pointer
  267.     if (!ppMediaObject)
  268.     {
  269.         return E_POINTER;
  270.     }
  271.  
  272.     // This will be cleaned up when client releases the newly created object
  273.     // or if there's some error along the way
  274.     $$CLASS_NAME$$ * pNew$$DSDMOID_NAME$$ = new CComObject<$$CLASS_NAME$$>;
  275.     if( !pNew$$DSDMOID_NAME$$ )
  276.     {
  277.         return E_OUTOFMEMORY;
  278.     }
  279.  
  280.     HRESULT hr = S_OK;
  281.  
  282.     hr = pNew$$DSDMOID_NAME$$->UpdateStatesInternal();
  283.  
  284.     IMediaObject * pCloned = NULL;
  285.     if( SUCCEEDED( hr ) )
  286.     {
  287.         IUnknown *pUnk;
  288.         hr = pNew$$DSDMOID_NAME$$->QueryInterface( IID_IUnknown, (void **) &pUnk );
  289.         if( SUCCEEDED( hr ) )
  290.         {
  291.             hr = pUnk->QueryInterface( IID_IMediaObject, (void **) &pCloned );
  292.             pUnk->Release();
  293.         }
  294.     }
  295.  
  296. $$IF(SUPPORT_DS_IMEDPARAM || SUPPORT_DS_DMP)
  297.     // Copy parameter control information
  298.     if (SUCCEEDED(hr))
  299.     {
  300.         hr = pNew$$DSDMOID_NAME$$->CopyParamsFromSource((CParamsManager *) this);
  301.     }
  302.  
  303.     // Copy current parameter values
  304.     $$DSDMOID_NAME$$Params params;
  305.     if (SUCCEEDED(hr))
  306.     {
  307.         hr = GetAllParameters(¶ms);
  308.     }
  309.  
  310.     if (SUCCEEDED(hr))
  311.     {
  312.         hr = pNew$$DSDMOID_NAME$$->SetAllParameters(¶ms);
  313.     }
  314. $$ENDIF
  315.  
  316.     // Copy the input and output types
  317.     if (SUCCEEDED(hr))
  318.     {
  319.         DMO_MEDIA_TYPE mt;
  320.         DWORD cInputStreams = 0;
  321.         DWORD cOutputStreams = 0;
  322.         GetStreamCount(&cInputStreams, &cOutputStreams);
  323.  
  324.         for (DWORD i = 0; i < cInputStreams && SUCCEEDED(hr); ++i)
  325.         {
  326.             hr = GetInputCurrentType(i, &mt);
  327.             if (hr == DMO_E_TYPE_NOT_SET)
  328.             {
  329.                 hr = S_OK; // great, don't need to set the cloned DMO
  330.             }
  331.             else if (SUCCEEDED(hr))
  332.             {
  333.                 hr = pCloned->SetInputType(i, &mt, 0);
  334.                 MoFreeMediaType( &mt );
  335.             }
  336.         }
  337.  
  338.         for (i = 0; i < cOutputStreams && SUCCEEDED(hr); ++i)
  339.         {
  340.             hr = GetOutputCurrentType(i, &mt);
  341.             if (hr == DMO_E_TYPE_NOT_SET)
  342.             {
  343.                 hr = S_OK; // great, don't need to set the cloned DMO
  344.             }
  345.             else if (SUCCEEDED(hr))
  346.             {
  347.                 hr = pCloned->SetOutputType(i, &mt, 0);
  348.                 MoFreeMediaType( &mt );
  349.             }
  350.         }
  351.  
  352.         if (SUCCEEDED(hr))
  353.         {
  354.             hr = pCloned->QueryInterface(IID_IMediaObjectInPlace, (void**)ppMediaObject);
  355.         }
  356.  
  357.         // Release the object's original ref.  If clone succeeded (made it through QI) then returned pointer
  358.         // has one ref.  If we failed, refs drop to zero, freeing the object.
  359.         pCloned->Release();
  360.     }
  361.  
  362.     // Something went wrong, clean up for client
  363.     if (FAILED(hr))
  364.     {
  365.         delete pNew$$DSDMOID_NAME$$;
  366.     }
  367.  
  368.     return hr;
  369. }
  370.  
  371.  
  372. ////////////////////////////
  373. //
  374. //  IMediaObjectInPlace::GetLatency
  375. //
  376. //  The GetLatency method retrieves the latency introduced by this DMO.
  377. //
  378. //  Parameters
  379. //
  380. //      pLatencyTime
  381. //          [out] Pointer to a variable that receives the latency, in
  382. //          100-nanosecond units.
  383. //
  384. //  Return Value
  385. //      Returns S_OK if successful. Otherwise, returns an HRESULT value
  386. //      indicating the cause of the error.
  387. //
  388. //  This method returns the average time required to process each buffer.
  389. //  This value usually depends on factors in the run-time environment, such
  390. //  as the processor speed and the CPU load. One possible way to implement
  391. //  this method is for the DMO to keep a running average based on historical
  392. //  data.
  393. //
  394. HRESULT $$CLASS_NAME$$::GetLatency(REFERENCE_TIME *pLatencyTime)
  395. {
  396.     // Check the input arguments;
  397.     if (!pLatencyTime)
  398.     {
  399.         return E_POINTER;
  400.     }
  401.  
  402. // TODO: Calculate some reasonable average latency if this DMO is going to
  403. //         be used with DirectShow. For now, 5 is used as the default latency.
  404.  
  405.     *pLatencyTime= static_cast<REFERENCE_TIME>(5);
  406.  
  407.     return S_OK;
  408. }
  409.  
  410.  
  411. ////////////////////////////////
  412. //
  413. // IMediaObjectImpl Methods
  414. //
  415.  
  416. ///////////////////////////////
  417. //
  418. //  IMediaObjectImpl::InternalAllocateStreamingResources
  419. //
  420. //  *** Called by AllocateStreamingResources, description below ***
  421. //
  422. //  The AllocateStreamingResources method allocates any resources needed by
  423. //  the DMO. Calling this method is always optional.
  424. //
  425. //  An application can call this method as a streaming optimization. It gives
  426. //  the DMO an opportunity to perform any time-consuming initializations
  427. //  before streaming begins. If you call this method, do so after you set
  428. //  the media types on the DMO, but before you make the first calls to
  429. //  ProcessInput or ProcessOutput.
  430. //
  431. //  This method is optional in the following sense:
  432. //
  433. //  *  If the DMO does not support this method, the method returns S_OK.
  434. //
  435. //  *  If the application never calls this method, the DMO allocates resources
  436. //     within a call to ProcessInput or ProcessOutput or Process.
  437. //
  438. //  If the DMO supports this method, it should also support the
  439. //  FreeStreamingResources method.
  440. //
  441. //  Note:
  442. //
  443. //  The template keeps a private flag that indicates whether this method has
  444. //  been called. If the method is called when the flag is already TRUE, it
  445. //  returns S_OK without calling the InternalAllocateStreamingResources
  446. //  method. The FreeStreamingResources method resets the flag to FALSE.
  447. //
  448. HRESULT $$CLASS_NAME$$::InternalAllocateStreamingResources(void)
  449. {
  450.     HRESULT hr = S_OK;
  451.  
  452. // TODO: Our initialization should be done here.
  453. // TODO: If necessary, allocate resources needed to process the current input type
  454.  
  455.     if( SUCCEEDED(hr) )
  456.     {
  457.         hr = UpdateStatesInternal();
  458.         m_fInitialized = TRUE;
  459.     }
  460.  
  461.     return hr;
  462. }
  463.  
  464.  
  465. ////////////////////////////////
  466. //
  467. // IMediaObjectImpl::InternalDiscontinuity
  468. //
  469. //  *** Called by Discontinuity, description below ***
  470. //
  471. // The Discontinuity method signals a discontinuity on the specified input
  472. // stream.
  473. //
  474. // Possible Return Values:
  475. //  S_OK                        Success
  476. //  DMO_E_INVALIDSTREAMINDEX    Invalid streamindex
  477. //
  478. // A discontinuity represents a break in the input. A discontinuity might
  479. // occur because no more data is expected, the format is changing, or there
  480. // is a gap in the data. After a discontinuity, the DMO does not accept further
  481. // input on that stream until all pending data has been processed. The
  482. // application should call the ProcessOutput method until none of the streams
  483. // returns the DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE flag.
  484. //
  485. HRESULT $$CLASS_NAME$$::InternalDiscontinuity(DWORD dwInputStreamIndex)
  486. {
  487.  
  488. // TODO: Implement Discontinuity if necessary
  489.  
  490.     return S_OK;
  491. }
  492.  
  493.  
  494. /////////////////////////
  495. //
  496. //  IMediaObjectImpl::InternalFlush
  497. //
  498. //  *** Called by Flush, description below ***
  499. //
  500. //  The Flush method flushes all internally buffered data.
  501. //
  502. // Return Value:
  503. // Returns S_OK if successful. Otherwise, returns an HRESULT value indicating
  504. // the cause of the error.
  505. //
  506. //  The DMO performs the following actions when this method is called:
  507. //  *  Releases any IMediaBuffer references it holds.
  508. //
  509. //  *  Discards any values that specify the time stamp or sample length for a
  510. //     media buffer.
  511. //
  512. //  *  Reinitializes any internal states that depend on the contents of a
  513. //     media sample.
  514. //
  515. //  Media types, maximum latency, and locked state do not change.
  516. //
  517. //  When the method returns, every input stream accepts data. Output streams
  518. //  cannot produce any data until the application calls the ProcessInput method
  519. //  on at least one input stream.
  520. //
  521. //  Note:
  522. //
  523. //  The template keeps a private flag that indicates the object's flushed
  524. //  state. The Flush method sets the flag to TRUE, and the ProcessInput method
  525. //  resets it to FALSE. If Flush is called when the flag is already TRUE, the
  526. //  method returns S_OK without calling the InternalFlush method.
  527. //
  528. HRESULT $$CLASS_NAME$$::InternalFlush(void)
  529. {
  530.  
  531. // TODO: Change implementation if necessary
  532.  
  533.     // Right now, just clear out the buffer
  534.     m_pBuffer = NULL;
  535.  
  536.     return S_OK;
  537. }
  538.  
  539.  
  540. ////////////////////
  541. //
  542. // IMediaObjectImpl::InternalFreeStreamingResources
  543. //
  544. //  *** Called by FreeStreamingResources, description below ***
  545. //
  546. // The FreeStreamingResources method frees resources allocated by the DMO.
  547. // Calling this method is always optional.
  548. //
  549. // Return Value
  550. //
  551. // Returns S_OK if successful. Otherwise, returns an HRESULT value indicating
  552. // the cause of the error.
  553. //
  554. // This method releases any resources that the AllocateStreamingResources
  555. // method initializes.
  556. //
  557. // If the DMO does not support this method, the method returns S_OK. If you
  558. // call this method during streaming, the method fails and the DMO does not
  559. // release any resources.
  560. //
  561. // Regardless of whether the method fails or succeeds, the application can
  562. // continue to call other methods on the DMO. The DMO might need to
  563. // re-initialize resources that were previously freed.
  564. //
  565. HRESULT $$CLASS_NAME$$::InternalFreeStreamingResources(void)
  566. {
  567.  
  568. // TODO: Implement this function if InternalAllocateStreamingResources() was implemented
  569.  
  570.     return S_OK;
  571. }
  572.  
  573.  
  574. ////////////////////////////////////////
  575. //
  576. //  IMediaObjectImpl::InternalGetInputMaxLatency
  577. //
  578. //  *** Called by GetInputMaxLatency, description below ***
  579. //
  580. //  The GetInputMaxLatency method retrieves the maximum latency on a specified
  581. //   input stream.
  582. //
  583. //  Parameters
  584. //   dwInputStreamIndex:    Zero-based index of an input stream on the DMO.
  585. //   prtMaxLatency:         [out] Pointer to a variable that receives the maximum latency.
  586. //
  587. // Return Value
  588. // Returns an HRESULT value. The following are possible return values.
  589. //  S_OK                        Success
  590. //  DMO_E_INVALIDSTREAMINDEX    Invalid stream index
  591. //  E_FAIL                      Failure
  592. //  E_NOTIMPL                   Not implemented. Assume zero latency
  593. //
  594. // The latency is the difference between a time stamp on the input stream and
  595. // the corresponding time stamp on the output stream. The maximum latency is
  596. // the largest possible difference in the time stamps. For a DMO, determine the
  597. // maximum latency as follows:
  598. //
  599. // *  Process input buffers until the DMO can produce output.
  600. //
  601. // *  Process as many output buffers as possible.
  602. //
  603. // *  The maximum latency is the largest delta between input time stamps and
  604. //    output time stamps (taken as an absolute value).
  605. //
  606. //    Under this definition, latency does not include the time that it takes
  607. //    to process samples. Nor does it include any latency introduced by the
  608. //    size of the input buffer.
  609. //
  610. // For the special case where a DMO processes exactly one sample at a time,
  611. // the maximum latency is simply the difference in time stamps.
  612. //
  613. // Latency is defined only when samples have time stamps, and the time stamps
  614. // increase or decrease monotonically. Maximum latency might depend on the
  615. // media types for the input and output streams.
  616. //
  617.  
  618. HRESULT $$CLASS_NAME$$::InternalGetInputMaxLatency(DWORD dwInputStreamIndex, REFERENCE_TIME *prtMaxLatency)
  619. {
  620.  
  621. // TODO: Provide a good max latency if this DMO is going to be used with DirectShow.
  622. //         For now, 30 is used as the default max latency.
  623.  
  624.     *prtMaxLatency = 30;
  625.  
  626.     return S_OK;
  627. }
  628.  
  629.  
  630. /////////////////////////////////////////
  631. //
  632. //  IMediaObjectImpl::InternalSetInputMaxLatency
  633. //
  634. //  *** Called by SetInputMaxLatency, description below ***
  635. //
  636. //  The SetInputMaxLatency method sets the maximum latency on a specified input
  637. //  stream. For the definition of maximum latency, see GetInputMaxLatency.
  638. //
  639. //  Parameters
  640. //
  641. //      dwInputStreamIndex
  642. //          Zero-based index of an input stream on the DMO.
  643. //
  644. //      rtMaxLatency
  645. //          Maximum latency.
  646. //
  647. //  Return Value
  648. //      S_OK Success
  649. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  650. //      E_FAIL Failure
  651. //      E_NOTIMPL Not implemented
  652. //
  653. HRESULT $$CLASS_NAME$$::InternalSetInputMaxLatency(DWORD dwInputStreamIndex, REFERENCE_TIME rtMaxLatency)
  654. {
  655.     // Method not implemented
  656.     return E_NOTIMPL;
  657. }
  658.  
  659.  
  660. ////////////////////////////////////
  661. //
  662. //  IMediaObjectImpl::InternalGetInputSizeInfo
  663. //
  664. //  *** Called by GetInputSizeInfo, description below ***
  665. //
  666. //  The GetInputSizeInfo method retrieves the buffer requirements for a
  667. //  specified input stream.
  668. //
  669. //  Parameters
  670. //
  671. //  dwInputStreamIndex:     Zero-based index of an input stream on the DMO.
  672. //
  673. //  pcbSize:                [out] Pointer to a variable that receives
  674. //      the minimum size of an input buffer for this stream, in bytes.
  675. //
  676. //  pulSizeMaxLookahead:        [out] Pointer to a variable that receives the
  677. //      maximum amount of data that the DMO will hold for lookahead, in bytes.
  678. //      If the DMO does not perform lookahead on the stream, the value is zero.
  679. //
  680. //  pulSizeAlignment            [out] Pointer to a variable that receives the
  681. //      required buffer alignment, in bytes. If the input stream has no
  682. //      alignment requirement, the value is 1.
  683. //
  684. //  Return Value
  685. //      S_OK Success
  686. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  687. //      DMO_E_TYPE_NOT_SET Media type was not set
  688. //
  689. //  The buffer requirements may depend on the media types of the various
  690. //  streams. Before calling this method, set the media type of each stream
  691. //  by calling the SetInputType and SetOutputType methods. If the media types
  692. //  have not been set, this method might return an error.
  693. //
  694. //  If the DMO performs lookahead on the input stream, it returns the
  695. //  DMO_INPUT_STREAMF_HOLDS_BUFFERS flag in the GetInputStreamInfo method.
  696. //  During processing, the DMO holds up to the number of bytes indicated by the
  697. //  pulSizeMaxLookahead parameter. The application must allocate enough buffers for
  698. //  the DMO to hold this much data.
  699. //
  700. //  A buffer is aligned if the buffer's start address is a multiple of
  701. //  *pulSizeAlignment. The alignment must be a power of two. Depending on the
  702. //  microprocessor, reads and writes to an aligned buffer might be faster than
  703. //  to an unaligned buffer. Also, some microprocessors do not support unaligned
  704. //  reads and writes.
  705. //
  706. //  Note:
  707. //
  708. //  GetInputSizeInfo returns DMO_E_TYPE_NOT_SET unless all of the non-optional
  709. //  streams have media types. Therefore, in the derived class, the internal
  710. //  methods can assume that all of the non-optional streams have media types.
  711. //
  712. HRESULT $$CLASS_NAME$$::InternalGetInputSizeInfo(DWORD dwInputStreamIndex, DWORD *pcbSize, DWORD *pulSizeMaxLookahead, DWORD *pulSizeAlignment)
  713. {
  714.     // We don't have to do any validation, because it is all done in the base class
  715.  
  716.     HRESULT hr = S_OK;
  717.     const DMO_MEDIA_TYPE* pmt;
  718.     pmt = InputType(0);
  719.     const WAVEFORMATEX* pwfx = reinterpret_cast<const WAVEFORMATEX*>(pmt->pbFormat);
  720.     *pcbSize = pwfx->nChannels * pwfx->wBitsPerSample / 8;
  721.     *pulSizeMaxLookahead = 0;    // no look ahead
  722.     *pulSizeAlignment = 1;        // no alignment requirement
  723.  
  724.     return hr;
  725. }
  726.  
  727.  
  728. //////////////////////////////////////
  729. //
  730. //  IMediaObjectImpl::InternalGetOutputSizeInfo
  731. //
  732. //  *** Called by GetOutputSizeInfo, description below ***
  733. //
  734. //  The GetOutputSizeInfo method retrieves the buffer requirements for a
  735. //  specified output stream.
  736. //
  737. //  Parameters
  738. //
  739. //      dwOutputStreamIndex
  740. //          Zero-based index of an output stream on the DMO.
  741. //
  742. //      pcbSize
  743. //          [out] Pointer to a variable that receives the minimum size of an
  744. //          output buffer for this stream, in bytes.
  745. //
  746. //      pulSizeAlignment
  747. //          [out] Pointer to a variable that receives the required buffer
  748. //          alignment, in bytes. If the output stream has no alignment
  749. //          requirement, the value is 1.
  750. //
  751. //  Return Value
  752. //      S_OK Success
  753. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  754. //      DMO_E_TYPE_NOT_SET Media type was not set
  755. //
  756. //  The buffer requirements may depend on the media types set for each of the
  757. //  streams.
  758. //
  759. //  Before calling this method, set the media type of each stream by calling
  760. //  the SetInputType and SetOutputType methods. If the media types have not
  761. //  been set, this method might return an error. However, if a stream is
  762. //  optional, and the application will not use the stream, you do not have to
  763. //  set the media type for the stream.
  764. //
  765. //  A buffer is aligned if the buffer's start address is a multiple of
  766. //  *pulSizeAlignment. Depending on the architecture of the microprocessor, it is
  767. //  faster to read and write to an aligned buffer than to an unaligned buffer.
  768. //  On some microprocessors, reading and writing to an unaligned buffer is not
  769. //  supported and can cause the program to crash. Zero is not a valid alignment.
  770. //
  771. //  Note:
  772. //
  773. //  GetOutputSizeInfo returns DMO_E_TYPE_NOT_SET unless all of the non-optional
  774. //  streams have media types. Therefore, in the derived class, the internal
  775. //  methods can assume that all of the non-optional streams have media types.
  776. //
  777. HRESULT $$CLASS_NAME$$::InternalGetOutputSizeInfo(DWORD dwOutputStreamIndex, DWORD *pcbSize, DWORD *pulSizeAlignment)
  778. {
  779.     // We don't have to do any validation, because it is all done in the base class
  780.     HRESULT hr = S_OK;
  781.     const DMO_MEDIA_TYPE* pmt;
  782.     pmt = OutputType(0);
  783.     const WAVEFORMATEX* pwfx = reinterpret_cast<const WAVEFORMATEX*>(pmt->pbFormat);
  784.     *pcbSize = pwfx->nChannels * pwfx->wBitsPerSample / 8;
  785.     *pulSizeAlignment = 1;
  786.  
  787.     return hr;
  788. }
  789.  
  790.  
  791. ////////////////////////////////////////
  792. //
  793. //  IMediaObjectImpl::InternalGetInputStreamInfo
  794. //
  795. //  *** Called by GetInputStreamInfo, description below ***
  796. //
  797. //  The GetInputStreamInfo method retrieves information about an input stream,
  798. //  such as any restrictions on the number of samples per buffer, and whether
  799. //  the stream performs lookahead on the input data. This information never
  800. //  changes.
  801. //
  802. //  Parameters
  803. //      dwInputStreamIndex:
  804. //          Zero-based index of an input stream on the DMO.
  805. //
  806. //      pdwFlags:
  807. //          [out] Pointer to a variable that receives a bitwise combination of
  808. //          zero or more DMO_INPUT_STREAM_INFO_FLAGS flags.
  809. //
  810. //  Return Value
  811. //      S_OK Success
  812. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  813. //      E_POINTER NULL pointer argument
  814. //
  815. //  The DMO_INPUT_STREAMF_HOLDS_BUFFERS flag indicates that the DMO performs
  816. //  lookahead on the incoming data.
  817. //
  818. //  The application must be sure to allocate sufficient buffers for the DMO
  819. //  to process the input. Call the GetInputSizeInfo method to determine the
  820. //  buffer requirements.
  821. //
  822. HRESULT $$CLASS_NAME$$::InternalGetInputStreamInfo(DWORD dwInputStreamIndex, DWORD *pdwFlags)
  823. {
  824.     *pdwFlags = DMO_OUTPUT_STREAMF_WHOLE_SAMPLES;
  825.     *pdwFlags |= DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE;
  826.  
  827.     return S_OK;
  828. }
  829.  
  830.  
  831. //////////////////////////////////////////
  832. //
  833. //  IMediaObjectImpl::InternalGetOutputStreamInfo
  834. //
  835. //  *** Called by GetOutputStreamInfo, description below ***
  836. //
  837. //  The GetOutputStreamInfo method retrieves information about an output
  838. //  stream; for example, whether the stream is discardable, and whether
  839. //  it uses a fixed sample size. This information never changes.
  840. //
  841. //  Parameters
  842. //      dwOutputStreamIndex
  843. //          Zero-based index of an output stream on the DMO.
  844. //
  845. //      pdwFlags
  846. //          [out] Pointer to a variable that receives a bitwise combination
  847. //          of zero or more DMO_OUTPUT_STREAM_INFO_FLAGS flags.
  848. //
  849. //  Return Value
  850. //
  851. //      S_OK Success
  852. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  853. //      E_POINTER NULL pointer argument
  854. //
  855. HRESULT $$CLASS_NAME$$::InternalGetOutputStreamInfo(DWORD dwOutputStreamIndex, DWORD *pdwFlags)
  856. {
  857.     *pdwFlags = DMO_OUTPUT_STREAMF_WHOLE_SAMPLES;
  858.     *pdwFlags |= DMO_OUTPUT_STREAMF_FIXED_SAMPLE_SIZE;
  859.  
  860.     return S_OK;
  861. }
  862.  
  863.  
  864. /////////////////////////////////
  865. //
  866. //  IMediaObjectImpl::InternalGetInputType
  867. //
  868. //  *** Called by GetInputType, description below ***
  869. //
  870. //  The GetInputType method retrieves a preferred media type for a specified
  871. //  input stream.
  872. //
  873. //  Parameters
  874. //
  875. //      dwInputStreamIndex
  876. //          Zero-based index of an input stream on the DMO.
  877. //
  878. //      dwTypeIndex
  879. //          Zero-based index on the set of acceptable media types.
  880. //
  881. //      pmt
  882. //          [out] Pointer to a DMO_MEDIA_TYPE structure allocated by the caller.
  883. //          The method fills the structure with the media type. The format block
  884. //          might be NULL, in which case the format type GUID is GUID_NULL.
  885. //
  886. //  Return Value
  887. //      S_OK Success
  888. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  889. //      DMO_E_NO_MORE_ITEMS Type index is out of range
  890. //      E_OUTOFMEMORY Insufficient memory
  891. //      E_POINTER NULL pointer argument
  892. //
  893. //  Call this method to enumerate an input stream's preferred media types. The
  894. //  DMO assigns each media type an index value in order of preference. The most
  895. //  preferred type has an index of zero. To enumerate all the types, make
  896. //  successive calls while incrementing the type index until the method returns
  897. //  DMO_E_NO_MORE_ITEMS.
  898. //
  899. //  If the method succeeds, call MoFreeMediaType to free the format block.
  900. //
  901. //  To set the media type, call the SetInputType method. Setting the media type
  902. //  on one stream can change another stream's preferred types. In fact, a
  903. //  stream might not have a preferred type until the type is set on another
  904. //  stream. For example, a decoder might not have a preferred output type until
  905. //  the input type is set. However, the DMO is not required to update its
  906. //  preferred types dynamically in this fashion. Thus, the types returned by
  907. //  this method are not guaranteed to be valid; they might fail when used in the
  908. //  SetInputType method. Conversely, the DMO is not guaranteed to enumerate every
  909. //  media type that it supports. To test whether a particular media type is
  910. //  acceptable, call SetInputType with the DMO_SET_TYPEF_TEST_ONLY flag.
  911. //
  912. HRESULT $$CLASS_NAME$$::InternalGetInputType(DWORD dwInputStreamIndex, DWORD dwTypeIndex, DMO_MEDIA_TYPE *pmt)
  913. {
  914.     // This function resembles InternalGetOutputType() since the input and output types must
  915.     // be consistent for DirectSound
  916.  
  917.     HRESULT hr = S_OK;
  918.  
  919. $$IF(PROCESS_MEDIATYPE_16BIT_PCM || PROCESS_MEDIATYPE_8BIT_PCM)
  920. $$IF(PROCESS_MEDIATYPE_FLOAT)
  921.     if (dwTypeIndex > 1)
  922. $$ELSE
  923.     if (dwTypeIndex > 0)
  924. $$ENDIF
  925. $$ELSE
  926.     if (dwTypeIndex > 0)
  927. $$ENDIF
  928.     {
  929.         return DMO_E_NO_MORE_ITEMS;
  930.     }
  931.  
  932.     // If pmt is NULL, and the type index is in range, we return S_OK
  933.     if (pmt == NULL)
  934.     {
  935.         return S_OK;
  936.     }
  937.  
  938.     // If the output type is set, we prefer to use that one
  939.     if (OutputTypeSet(0))
  940.     {
  941.         return MoCopyMediaType(pmt, OutputType(0));
  942.     }
  943.  
  944.     hr = MoInitMediaType(pmt, sizeof(WAVEFORMATEX));
  945.  
  946.     if (SUCCEEDED(hr))
  947.     {
  948. $$IF(PROCESS_MEDIATYPE_16BIT_PCM || PROCESS_MEDIATYPE_8BIT_PCM)
  949. $$IF(PROCESS_MEDIATYPE_FLOAT)
  950.         if (0 == dwTypeIndex)
  951.         {
  952.             pmt->majortype  = MEDIATYPE_Audio;
  953.             pmt->subtype    = MEDIASUBTYPE_PCM;            // We take PCM format!
  954.             pmt->formattype = FORMAT_None;
  955.         }
  956.         else if (1 == dwTypeIndex)
  957.         {
  958.             pmt->majortype  = MEDIATYPE_Audio;
  959.             pmt->subtype    = MEDIASUBTYPE_IEEE_FLOAT;    // We take FLOAT format also!
  960.             pmt->formattype = FORMAT_None;
  961.         }
  962. $$ELSE
  963.         pmt->majortype  = MEDIATYPE_Audio;
  964.         pmt->subtype    = MEDIASUBTYPE_PCM;            // We take PCM format!
  965.         pmt->formattype = FORMAT_None;
  966. $$ENDIF
  967. $$ELSE
  968.         pmt->majortype  = MEDIATYPE_Audio;
  969.         pmt->subtype    = MEDIASUBTYPE_IEEE_FLOAT;    // We take FLOAT format!
  970.         pmt->formattype = FORMAT_None;
  971. $$ENDIF
  972.     }
  973.  
  974.     return hr;
  975. }
  976.  
  977.  
  978. ///////////////////////////////////
  979. //
  980. //  IMediaObjectImpl::InternalGetOutputType
  981. //
  982. //  *** Called by GetOutputType, description below ***
  983. //
  984. //  The GetOutputType method retrieves a preferred media type for a specified
  985. //  output stream.
  986. //
  987. //  Parameters
  988. //
  989. //      dwOutputStreamIndex
  990. //          Zero-based index of an output stream on the DMO.
  991. //
  992. //      dwTypeIndex
  993. //          Zero-based index on the set of acceptable media types.
  994. //
  995. //      pmt
  996. //          [out] Pointer to a DMO_MEDIA_TYPE structure allocated by the
  997. //          caller. The method fills the structure with the media type. The
  998. //          format block might be NULL, in which case the format type GUID is GUID_NULL.
  999. //
  1000. //  Return Value
  1001. //      S_OK Success
  1002. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  1003. //      DMO_E_NO_MORE_ITEMS Type index is out of range
  1004. //      E_OUTOFMEMORY Insufficient memory
  1005. //      E_POINTER NULL pointer argument
  1006. //
  1007. //  Call this method to enumerate an output stream's preferred media types. The
  1008. //  DMO assigns each media type an index value, in order of preference. The
  1009. //  most preferred type has an index of zero. To enumerate all the types, make
  1010. //  successive calls while incrementing the type index, until the method returns
  1011. //  DMO_E_NO_MORE_ITEMS.
  1012. //
  1013. //  If the method succeeds, call MoFreeMediaType to free the format block.
  1014. //
  1015. //  To set the media type, call the SetOutputType method. Setting the media type
  1016. //  on one stream can change another stream's preferred types. In fact, a stream
  1017. //  might not have a preferred type until the type is set on another stream. For
  1018. //  example, a decoder might not have a preferred output type until the input
  1019. //  type is set. However, the DMO is not required to update its preferred types
  1020. //  dynamically in this fashion. Thus, the types returned by this method are not
  1021. //  guaranteed to be valid; they might fail when used in the SetOutputType method.
  1022. //  Conversely, the DMO is not guaranteed to enumerate every media type that it
  1023. //  supports. To test whether a particular media type is acceptable, call
  1024. //  SetOutputType with the DMO_SET_TYPEF_TEST_ONLY flag.
  1025. //
  1026. //
  1027. HRESULT $$CLASS_NAME$$::InternalGetOutputType(DWORD dwOutputStreamIndex, DWORD dwTypeIndex, DMO_MEDIA_TYPE *pmt)
  1028. {
  1029.     // This function resembles InternalGetInputType() since the input and output types must
  1030.     // be consistent for DirectSound
  1031.  
  1032.     HRESULT hr = S_OK;
  1033.  
  1034. $$IF(PROCESS_MEDIATYPE_16BIT_PCM || PROCESS_MEDIATYPE_8BIT_PCM)
  1035. $$IF(PROCESS_MEDIATYPE_FLOAT)
  1036.     if (dwTypeIndex > 1)
  1037. $$ELSE
  1038.     if (dwTypeIndex > 0)
  1039. $$ENDIF
  1040. $$ELSE
  1041.     if (dwTypeIndex > 0)
  1042. $$ENDIF
  1043.     {
  1044.         return DMO_E_NO_MORE_ITEMS;
  1045.     }
  1046.  
  1047.     // If pmt is NULL, and the type index is in range, we return S_OK
  1048.     if (pmt == NULL)
  1049.     {
  1050.         return S_OK;
  1051.     }
  1052.  
  1053.     // If the input type is set, we prefer to use that one
  1054.     if (InputTypeSet(0))
  1055.     {
  1056.         return MoCopyMediaType(pmt, InputType(0));
  1057.     }
  1058.  
  1059.     hr = MoInitMediaType(pmt, sizeof(WAVEFORMATEX));
  1060.  
  1061.     if (SUCCEEDED(hr))
  1062.     {
  1063. $$IF(PROCESS_MEDIATYPE_16BIT_PCM || PROCESS_MEDIATYPE_8BIT_PCM)
  1064. $$IF(PROCESS_MEDIATYPE_FLOAT)
  1065.         if (0 == dwTypeIndex)
  1066.         {
  1067.             pmt->majortype  = MEDIATYPE_Audio;
  1068.             pmt->subtype    = MEDIASUBTYPE_PCM;            // We take PCM format!
  1069.             pmt->formattype = FORMAT_None;
  1070.         }
  1071.         else if (1 == dwTypeIndex)
  1072.         {
  1073.             pmt->majortype  = MEDIATYPE_Audio;
  1074.             pmt->subtype    = MEDIASUBTYPE_IEEE_FLOAT;    // We take FLOAT format also!
  1075.             pmt->formattype = FORMAT_None;
  1076.         }
  1077. $$ELSE
  1078.         pmt->majortype  = MEDIATYPE_Audio;
  1079.         pmt->subtype    = MEDIASUBTYPE_PCM;            // We take PCM format!
  1080.         pmt->formattype = FORMAT_None;
  1081. $$ENDIF
  1082. $$ELSE
  1083.         pmt->majortype  = MEDIATYPE_Audio;
  1084.         pmt->subtype    = MEDIASUBTYPE_IEEE_FLOAT;    // We take FLOAT format!
  1085.         pmt->formattype = FORMAT_None;
  1086. $$ENDIF
  1087.     }
  1088.  
  1089.     return hr;
  1090. }
  1091.  
  1092.  
  1093. ///////////////////////////////////////
  1094. //
  1095. //  IMediaObjectImpl::InternalProcessInput
  1096. //
  1097. //  *** Called by ProcessInput, description below ***
  1098. //
  1099. //  The ProcessInput method delivers a buffer to the specified input stream.
  1100. //
  1101. //  Parameters
  1102. //      dwInputStreamIndex
  1103. //          Zero-based index of an input stream on the DMO.
  1104. //
  1105. //      pBuffer
  1106. //          Pointer to the buffer's IMediaBuffer interface.
  1107. //
  1108. //      dwFlags
  1109. //          Bitwise combination of zero or more flags from the
  1110. //          DMO_INPUT_DATA_BUFFER_FLAGS enumeration.
  1111. //
  1112. //      rtTimestamp
  1113. //          Time stamp that specifies the start time of the data in the buffer.
  1114. //          If the buffer has a valid time stamp, set the
  1115. //          DMO_INPUT_DATA_BUFFERF_TIME flag in the dwFlags parameter.
  1116. //          Otherwise, the DMO ignores this value.
  1117. //
  1118. //      rtTimelength
  1119. //          Reference time specifying the duration of the data in the buffer.
  1120. //          If this value is valid, set the DMO_INPUT_DATA_BUFFERF_TIMELENGTH
  1121. //          flag in the dwFlags parameter. Otherwise, the DMO ignores this value.
  1122. //
  1123. //  Return Value
  1124. //      S_FALSE No output to process
  1125. //      S_OK Success
  1126. //      DMO_E_INVALIDSTREAMINDEX Invalid stream index
  1127. //      DMO_E_NOTACCEPTING Data cannot be accepted
  1128. //
  1129. //  If the DMO does not process all the data in the buffer, it keeps a
  1130. //  reference count on the buffer. It releases the buffer once it has
  1131. //  generated all the output, unless it needs to perform lookahead on the data.
  1132. //  (To determine whether a DMO performs lookahead, call the GetInputStreamInfo
  1133. //  method.)
  1134. //
  1135. //  If this method returns DMO_E_NOTACCEPTING, call the ProcessOutput method
  1136. //  until the input stream can accept more data. To determine whether the stream
  1137. //  can accept more data, call the GetInputStatus method.
  1138. //
  1139. //  If the method returns S_FALSE, no output was generated from this input and the
  1140. //  application does not need to call ProcessOutput. However, a DMO is not required
  1141. //  to return S_FALSE in this situation; it might return S_OK.
  1142. //
  1143. //  Note:
  1144. //
  1145. //  Before this method calls InternalProcessInput, it calls
  1146. //  AllocateStreamingResources and InternalAcceptingInput. Therefore, the
  1147. //  implementation of InternalProcessInput can assume the following:
  1148. //
  1149. //  * All resources have been allocated.
  1150. //  * The input stream can accept data.
  1151. //
  1152. HRESULT $$CLASS_NAME$$::InternalProcessInput(DWORD dwInputStreamIndex, IMediaBuffer *pBuffer, DWORD dwFlags, REFERENCE_TIME rtTimestamp, REFERENCE_TIME rtTimelength)
  1153. {
  1154.  
  1155. // TODO: Complete or modify implementation of InternalProcessInput() if necessary
  1156.  
  1157.     HRESULT hr = S_OK;
  1158.  
  1159.     if (!pBuffer)
  1160.     {
  1161.         return E_POINTER;
  1162.     }
  1163.  
  1164.     // Get the size of the input buffer
  1165.     hr = pBuffer->GetBufferAndLength(&m_pbInputData, &m_cbInputLength);
  1166.  
  1167.     if (SUCCEEDED(hr))
  1168.     {
  1169.         m_pBuffer = pBuffer;
  1170.  
  1171.         if (dwFlags & DMO_INPUT_DATA_BUFFERF_TIME)
  1172.         {
  1173.             m_bValidTime = true;
  1174.             m_rtTimestamp = rtTimestamp;
  1175.         }
  1176.         else
  1177.         {
  1178.             m_bValidTime = false;
  1179.         }
  1180.     }
  1181.  
  1182.     return hr;
  1183. }
  1184.  
  1185.  
  1186. ///////////////////////////////////
  1187. //
  1188. //  IMediaObjectImpl::InternalProcessOutput
  1189. //
  1190. //  *** Called by ProcessOutput, description below ***
  1191. //
  1192. //  The ProcessOutput method generates output from the current input data.
  1193. //
  1194. //  Parameters
  1195. //
  1196. //      dwFlags
  1197. //          Bitwise combination of zero or more flags from the
  1198. //          DMO_PROCESS_OUTPUT_FLAGS enumeration.
  1199. //
  1200. //      cOutputBufferCount
  1201. //          Number of output buffers.
  1202. //
  1203. //      pOutputBuffers
  1204. //          [in, out] Pointer to an array of DMO_OUTPUT_DATA_BUFFER structures
  1205. //          containing the output buffers. Specify the size of the array in the
  1206. //          cOutputBufferCount parameter.
  1207. //
  1208. //      pdwStatus
  1209. //          [out] Pointer to a variable that receives a reserved value (zero).
  1210. //          The application should ignore this value.
  1211. //
  1212. //  Return Value
  1213. //      S_FALSE No output was generated
  1214. //      S_OK Success
  1215. //      E_FAIL Failure
  1216. //      E_INVALIDARG Invalid argument
  1217. //      E_POINTER NULL pointer argument
  1218. //
  1219. //  The pOutputBuffers parameter points to an array of DMO_OUTPUT_DATA_BUFFER
  1220. //  structures. The application must allocate one structure for each output
  1221. //  stream. To determine the number of output streams, call the GetStreamCount
  1222. //  method. Set the cOutputBufferCount parameter to this number.
  1223. //
  1224. //  Each DMO_OUTPUT_DATA_BUFFER structure contains a pointer to a buffer's
  1225. //  IMediaBuffer interface. The application allocates these buffers. The other
  1226. //  members of the structure are status fields. The DMO sets these fields if
  1227. //  the method succeeds. If the method fails, their values are undefined.
  1228. //
  1229. //  When the application calls ProcessOutput, the DMO processes as much input
  1230. //  data as possible. It writes the output data to the output buffers, starting
  1231. //  from the end of the data in each buffer. (To find the end of the data, call
  1232. //  the IMediaBuffer::GetBufferAndLength method.) The DMO never holds a
  1233. //  reference count on an output buffer.
  1234. //
  1235. //  If the DMO fills an entire output buffer and still has input data to
  1236. //  process, the DMO returns the DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE flag in the
  1237. //  DMO_OUTPUT_DATA_BUFFER structure. The application should check for this
  1238. //  flag by testing the dwStatus member of each structure.
  1239. //
  1240. //  If the method returns S_FALSE, no output was generated. However, a DMO is
  1241. //  not required to return S_FALSE in this situation; it might return S_OK.
  1242. //
  1243. //  Discarding data:
  1244. //
  1245. //  You can discard data from a stream by setting the
  1246. //  DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER flag in the dwFlags parameter.
  1247. //  For each stream that you want to discard, set the pBuffer member of the
  1248. //  DMO_OUTPUT_DATA_BUFFER structure to NULL.
  1249. //
  1250. //  For each stream in which pBuffer is NULL:
  1251. //
  1252. //  If the DMO_PROCESS_OUTPUT_DISCARD_WHEN_NO_BUFFER flag is set, and the
  1253. //  stream is discardable or optional, the DMO discards the data.
  1254. //
  1255. //  If the flag is set but the stream is neither discardable nor optional, the
  1256. //  DMO discards the data if possible. It is not guaranteed to discard the
  1257. //  data.
  1258. //
  1259. //  If the flag is not set, the DMO does not produce output data for that
  1260. //  stream, but does not discard the data.
  1261. //
  1262. //  To check whether a stream is discardable or optional, call the
  1263. //  GetOutputStreamInfo method.
  1264. //
  1265. //  Note:
  1266. //
  1267. //  Before this method calls InternalProcessOutput, it calls
  1268. //  AllocateStreamingResources. Therefore, the implementation of
  1269. //  InternalProcessOutput can assume that all resources have been allocated.
  1270. //
  1271. HRESULT $$CLASS_NAME$$::InternalProcessOutput(DWORD dwFlags, DWORD cOutputBufferCount, DMO_OUTPUT_DATA_BUFFER *pOutputBuffers, DWORD *pdwStatus)
  1272. {
  1273.  
  1274. // TODO: Complete or modify implementation of InternalProcessOutput() if necessary
  1275.  
  1276.     HRESULT         hr = S_OK;
  1277.     BYTE            *pbData = NULL;
  1278.     DWORD           cbData = 0;
  1279.     DWORD           cbOutputLength = 0;
  1280.     DWORD           cbBytesProcessed = 0;
  1281.     bool            bComplete = false;
  1282.     const DWORD     UNITS = 10000000;  // 1 sec = 100 * UNITS ns
  1283.  
  1284.     CComPtr<IMediaBuffer> pOutputBuffer = pOutputBuffers[0].pBuffer;
  1285.  
  1286.     if (!m_pBuffer || !pOutputBuffer)
  1287.     {
  1288.         return S_FALSE;  // Did not produce output
  1289.     }
  1290.  
  1291.     // Get the size of the output buffer
  1292.     hr = pOutputBuffer->GetBufferAndLength(&pbData, &cbData);
  1293.  
  1294.     if (SUCCEEDED(hr))
  1295.     {
  1296.         hr = pOutputBuffer->GetMaxLength(&cbOutputLength);
  1297.     }
  1298.  
  1299.     if (SUCCEEDED(hr))
  1300.     {
  1301.         // Skip past any valid data in the output buffer
  1302.         pbData += cbData;
  1303.         cbOutputLength -= cbData;
  1304.  
  1305.         // Calculate how many quanta we can process
  1306.         if (m_cbInputLength > cbOutputLength)
  1307.         {
  1308.             cbBytesProcessed = cbOutputLength;
  1309.         }
  1310.         else
  1311.         {
  1312.             cbBytesProcessed = m_cbInputLength;
  1313.             bComplete = true;
  1314.         }
  1315.  
  1316.         // Process the data
  1317.         hr = DoProcess(pbData, m_pbInputData, cbBytesProcessed / WaveFormat()->nBlockAlign);
  1318.     }
  1319.  
  1320.     if (SUCCEEDED(hr))
  1321.     {
  1322.         hr = pOutputBuffer->SetLength(cbBytesProcessed + cbData);
  1323.     }
  1324.  
  1325.     if (SUCCEEDED(hr))
  1326.     {
  1327.         if (m_bValidTime)
  1328.         {
  1329.             pOutputBuffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIME;
  1330.             pOutputBuffers[0].rtTimestamp = m_rtTimestamp;
  1331.  
  1332.             // Estimate how far along we are
  1333.             pOutputBuffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_TIMELENGTH;
  1334.             double dTime = (double)(cbBytesProcessed) / WaveFormat()->nAvgBytesPerSec;
  1335.             pOutputBuffers[0].rtTimelength = (REFERENCE_TIME)(dTime * UNITS);
  1336.         }
  1337.  
  1338.         if (bComplete)
  1339.         {
  1340.             m_pBuffer = NULL;   // Release input buffer
  1341.         }
  1342.         else
  1343.         {
  1344.             pOutputBuffers[0].dwStatus |= DMO_OUTPUT_DATA_BUFFERF_INCOMPLETE;
  1345.             m_cbInputLength -= cbBytesProcessed;
  1346.             m_pbInputData += cbBytesProcessed;
  1347.             m_rtTimestamp += pOutputBuffers[0].rtTimelength;
  1348.         }
  1349.     }
  1350.     return hr;
  1351. }
  1352.  
  1353.  
  1354. ///////////////////////////////////
  1355. //
  1356. //  DoProcess
  1357. //
  1358. //  *** Called by Process and ProcessOutput ***
  1359. //
  1360. //  The DoProcess method processes the sound data.
  1361. //
  1362. //  Parameters
  1363. //
  1364. //      pbData
  1365. //          Pointer to the output buffer
  1366. //
  1367. //      pbInputData
  1368. //          Pointer to the input buffer
  1369. //
  1370. //      dwQuanta
  1371. //          Number of quanta to process
  1372. //
  1373. //  Return Value
  1374. //      S_OK Success
  1375. //
  1376. HRESULT $$CLASS_NAME$$::DoProcess(BYTE *pbData, const BYTE *pbInputData, DWORD dwQuanta)
  1377. {
  1378.  
  1379. $$IF(EMPTY_DSDMO)
  1380. /////////////////////////////////////////////////////////////////////////////
  1381. // TODO: Implement the sound processing code in this method
  1382.  
  1383. $$IF(PROCESS_CHANNELS_MONO)
  1384.     if (1 == m_nChannels)
  1385.     {
  1386. $$IF(PROCESS_MEDIATYPE_8BIT_PCM)
  1387.         if (8 == m_wBitsPerSample)
  1388.         {
  1389.         // TODO: Process 8-Bit Mono PCM samples
  1390.  
  1391.         }
  1392. $$ENDIF
  1393. $$IF(PROCESS_MEDIATYPE_16BIT_PCM)
  1394. $$IF(PROCESS_MEDIATYPE_8BIT_PCM)
  1395.         else if (16 == m_wBitsPerSample)
  1396. $$ELSE
  1397.         if (16 == m_wBitsPerSample)
  1398. $$ENDIF
  1399.         {
  1400.         // TODO: Process 16-Bit Mono PCM samples
  1401.  
  1402.         }
  1403. $$ENDIF
  1404. $$IF(PROCESS_MEDIATYPE_FLOAT)
  1405. $$IF(PROCESS_MEDIATYPE_16BIT_PCM || PROCESS_MEDIATYPE_8BIT_PCM)
  1406.         else if (32 == m_wBitsPerSample)
  1407. $$ELSE
  1408.         if (32 == m_wBitsPerSample)
  1409. $$ENDIF
  1410.         {
  1411.         // TODO: Process 32-Bit Mono Float samples
  1412.  
  1413.         }
  1414. $$ENDIF
  1415.     }
  1416. $$ENDIF
  1417. $$IF(PROCESS_CHANNELS_STEREO)
  1418. $$IF(PROCESS_CHANNELS_MONO)
  1419.     else if (2 == m_nChannels)
  1420. $$ELSE
  1421.     if (2 == m_nChannels)
  1422. $$ENDIF
  1423.     {
  1424. $$IF(PROCESS_MEDIATYPE_8BIT_PCM)
  1425.         if (8 == m_wBitsPerSample)
  1426.         {
  1427.         // TODO: Process 8-Bit Stereo PCM samples
  1428.  
  1429.         }
  1430. $$ENDIF
  1431. $$IF(PROCESS_MEDIATYPE_16BIT_PCM)
  1432. $$IF(PROCESS_MEDIATYPE_8BIT_PCM)
  1433.         else if (16 == m_wBitsPerSample)
  1434. $$ELSE
  1435.         if (16 == m_wBitsPerSample)
  1436. $$ENDIF
  1437.         {
  1438.         // TODO: Process 16-Bit Stereo PCM samples
  1439.  
  1440.         }
  1441. $$ENDIF
  1442. $$IF(PROCESS_MEDIATYPE_FLOAT)
  1443. $$IF(PROCESS_MEDIATYPE_16BIT_PCM || PROCESS_MEDIATYPE_8BIT_PCM)
  1444.         else if (32 == m_wBitsPerSample)
  1445. $$ELSE
  1446.         if (32 == m_wBitsPerSample)
  1447. $$ENDIF
  1448.         {
  1449.         // TODO: Process 32-Bit Stereo Float samples
  1450.  
  1451.         }
  1452. $$ENDIF
  1453.     }
  1454. $$ENDIF
  1455. $$ELSE // ELSE for IF(PROCESS_CHANNELS_MONO) (a page up), below is for Sample DMO
  1456. //
  1457. // Start of Panner sample code
  1458. //
  1459.         DWORD dwSample = 0;
  1460.  
  1461.         // Process each sample at a time
  1462.  
  1463.         if (1 == m_nChannels)
  1464.         {
  1465.             if (8 == m_wBitsPerSample)
  1466.             {
  1467.                 for (dwSample = 0; dwSample < dwQuanta; ++dwSample)
  1468.                 {
  1469.                     // 8-bit sound is 0 to 255 with 128 equal to silence
  1470.                     // Normalize sample to -128 to 127
  1471.                     int i = ((unsigned char*)pbInputData)[dwSample] - 128;
  1472.                     int j = i;
  1473.  
  1474.                     i *= 256;
  1475.                     j *= 256;
  1476.  
  1477.                     DoOneSample(&i, &j);
  1478.  
  1479.                     i /= 256;
  1480.                     j /= 256;
  1481.  
  1482.                     ((unsigned char*)pbData)[dwSample] = (unsigned char)(i + 128);
  1483.                 }
  1484.             }
  1485.             else if (16 == m_wBitsPerSample)
  1486.             {
  1487.                 for (dwSample = 0; dwSample < dwQuanta; ++dwSample)
  1488.                 {
  1489.                     int i = ((short*)pbInputData)[dwSample];
  1490.                     int j = i;
  1491.  
  1492.                     DoOneSample(&i, &j);
  1493.  
  1494.                     ((short*)pbData)[dwSample] = (short)i;
  1495.                 }
  1496.             }
  1497.             else if (32 == m_wBitsPerSample)
  1498.             {
  1499.                 for (dwSample = 0; dwSample < dwQuanta; ++dwSample)
  1500.                 {
  1501.                     float i = ((float*)pbInputData)[dwSample];
  1502.                     float j = i;
  1503.  
  1504.                     DoOneSample(&i, &j);
  1505.  
  1506.                     ((float*)pbData)[dwSample] = (float)i;
  1507.                 }
  1508.             }
  1509.         }
  1510.         else if (2 == m_nChannels)
  1511.         {
  1512.             if (8 == m_wBitsPerSample)
  1513.             {
  1514.                 for (dwSample = 0; dwSample < dwQuanta; ++dwSample)
  1515.                 {
  1516.                     // 8-bit sound is 0 to 255 with 128 equal to silence
  1517.                     // Normalize sample to -128 to 127
  1518.                     int i = ((unsigned char*)pbInputData)[dwSample * 2] - 128;
  1519.                     int j = ((unsigned char*)pbInputData)[dwSample * 2 + 1] - 128;
  1520.  
  1521.                     i *= 256;
  1522.                     j *= 256;
  1523.  
  1524.                     DoOneSample(&i, &j);
  1525.  
  1526.                     i /= 256;
  1527.                     j /= 256;
  1528.  
  1529.                     ((unsigned char*)pbData)[dwSample * 2] = (unsigned char)(i + 128);
  1530.                     ((unsigned char*)pbData)[dwSample * 2 + 1] = (unsigned char)(j + 128);
  1531.                 }
  1532.             }
  1533.             else if (16 == m_wBitsPerSample)
  1534.             {
  1535.                 for (dwSample = 0; dwSample < dwQuanta; ++dwSample)
  1536.                 {
  1537.                     int i = ((short*)pbInputData)[dwSample * 2];
  1538.                     int j = ((short*)pbInputData)[dwSample * 2 + 1];
  1539.  
  1540.                     DoOneSample(&i, &j);
  1541.  
  1542.                     ((short*)pbData)[dwSample * 2] = (short)i;
  1543.                     ((short*)pbData)[dwSample * 2 + 1] = (short)j;
  1544.                 }
  1545.             }
  1546.             else if (32 == m_wBitsPerSample)
  1547.             {
  1548.                 for (dwSample = 0; dwSample < dwQuanta; ++dwSample)
  1549.                 {
  1550.                     float i = ((float*)pbInputData)[dwSample * 2];
  1551.                     float j = ((float*)pbInputData)[dwSample * 2 + 1];
  1552.  
  1553.                     DoOneSample(&i, &j);
  1554.  
  1555.                     ((float*)pbData)[dwSample * 2] = (float)i;
  1556.                     ((float*)pbData)[dwSample * 2 + 1] = (float)j;
  1557.                 }
  1558.             }
  1559.         }
  1560. //
  1561. // End of Panner sample code
  1562. //
  1563. $$ENDIF
  1564.     return S_OK;
  1565. }
  1566.  
  1567.  
  1568. $$IF(!EMPTY_DSDMO)
  1569. // Sample Panner DMO
  1570. template<class SampleType> __forceinline void CPanner::DoOneSample(SampleType *l, SampleType *r)
  1571. {
  1572.  
  1573. // TODO: Add, change, remove as needed to implement your audio processing code
  1574.  
  1575.     // Increment current phase
  1576.     ++m_ulPhase;
  1577.  
  1578.     // Ignore the negative half cycle since we only interested in postive values
  1579.     if ( m_ulPhase > m_ulPeriod / 2 )
  1580.     {
  1581.         m_ulPhase = 0;
  1582.     }
  1583.  
  1584.     ULONG ulQuarterPhase = m_ulPhase;
  1585.     ULONG ulQuarterPeriod = m_ulPeriod / 4;
  1586.  
  1587.     // Wrap around at 1/4 of a cycle since the sine table contains only samples of a 1/4 cycle
  1588.     if( ulQuarterPhase > ulQuarterPeriod )
  1589.     {
  1590.         ulQuarterPhase = m_ulPeriod / 2 - ulQuarterPhase;
  1591.  
  1592.         // Eliminate duplicate samples at the wrap point
  1593.         if( ulQuarterPhase == ulQuarterPeriod )
  1594.         {
  1595.             ulQuarterPhase--;
  1596.         }
  1597.     }
  1598.  
  1599.     // Modulation rate for the left channel
  1600.     float fScaleLeft = SINE[(UINT)(ulQuarterPhase / m_fSineTablePeriod)];
  1601.  
  1602.     // Modulate amplitude of the left channel by fScaleLeft
  1603.     *l = (SampleType)( (*l) - (*l) * m_fWidth * fScaleLeft );
  1604.  
  1605.     // Modulate amplitude of the right channel by (1 - fScaleLeft)
  1606.     *r = (SampleType)( (*r) - (*r) * m_fWidth * (1 - fScaleLeft) );
  1607. }
  1608. $$ENDIF
  1609.  
  1610.  
  1611. ////////////////////////////////////////
  1612. //
  1613. //  IMediaObjectImpl::InternalAcceptingInput
  1614. //
  1615. //  Queries whether an input stream can accept more input. The derived class
  1616. //  must declare and implement this method.
  1617. //
  1618. //  Parameters
  1619. //
  1620. //      dwInputStreamIndex
  1621. //          Index of an input stream.
  1622. //
  1623. //  Return Value
  1624. //
  1625. //      Returns S_OK if the input stream can accept input, or S_FALSE otherwise.
  1626. //
  1627. //  Note:
  1628. //
  1629. //  Called by IMediaObject::GetInputStatus
  1630. //
  1631. HRESULT $$CLASS_NAME$$::InternalAcceptingInput(DWORD dwInputStreamIndex)
  1632. {
  1633.  
  1634. // TODO: Change implementation if necessary
  1635.  
  1636.     // Do not accept input if there is already input data to process
  1637.     return (m_pBuffer ? S_FALSE : S_OK);
  1638. }
  1639.  
  1640.  
  1641. ////////////////////////////////////
  1642. //
  1643. // IMediaObjectImpl::InternalCheckInputType
  1644. //
  1645. // Queries whether an input stream can accept a given media type.
  1646. // The derived class must declare and implement this method.
  1647. //
  1648. //  Parameters
  1649. //
  1650. //      dwInputStreamIndex
  1651. //          Index of an input stream.
  1652. //
  1653. //      pmt
  1654. //          Pointer to a DMO_MEDIA_TYPE structure that describes the media type.
  1655. //
  1656. //  Return Value
  1657. //
  1658. //       Returns S_OK if the media type is valid, or DMO_E_INVALIDTYPE otherwise.
  1659. //
  1660. //  Note:
  1661. //
  1662. //  Called by IMediaObject::SetInputType
  1663. //
  1664. HRESULT $$CLASS_NAME$$::InternalCheckInputType(DWORD dwInputStreamIndex, const DMO_MEDIA_TYPE *pmt)
  1665. {
  1666.     WAVEFORMATEX* pWave = (WAVEFORMATEX*)pmt->pbFormat;
  1667.  
  1668.     HRESULT hr = S_OK;
  1669.  
  1670.     // Check that we're PCM or float
  1671.     if ((NULL                       == pmt) ||
  1672.         (MEDIATYPE_Audio            != pmt->majortype) ||
  1673. $$IF(PROCESS_MEDIATYPE_8BIT_PCM || PROCESS_MEDIATYPE_16BIT_PCM)
  1674. $$IF(!PROCESS_MEDIATYPE_FLOAT)
  1675.         (MEDIASUBTYPE_PCM           != pmt->subtype) ||
  1676. $$ELSE
  1677.         (MEDIASUBTYPE_PCM           != pmt->subtype  &&
  1678.          MEDIASUBTYPE_IEEE_FLOAT    != pmt->subtype) ||
  1679. $$ENDIF
  1680. $$ELIF(PROCESS_MEDIATYPE_FLOAT)
  1681.         (MEDIASUBTYPE_IEEE_FLOAT    != pmt->subtype) ||
  1682. $$ENDIF
  1683.         (FORMAT_WaveFormatEx        != pmt->formattype &&
  1684.          FORMAT_None                != pmt->formattype) ||
  1685.         (pmt->cbFormat                <  sizeof(WAVEFORMATEX)) ||
  1686.         (NULL                       == pmt->pbFormat))
  1687.     {
  1688.         hr = DMO_E_INVALIDTYPE;
  1689.     }
  1690.  
  1691.     // If other type set, accept only if identical to that.  Otherwise accept
  1692.     // any standard PCM/float audio.
  1693.     if (SUCCEEDED(hr))
  1694.     {
  1695.         if (OutputTypeSet(0))
  1696.         {
  1697.             const DMO_MEDIA_TYPE* pmtOutput;
  1698.             pmtOutput = OutputType(0);
  1699.             if (memcmp(pmt->pbFormat, pmtOutput->pbFormat, sizeof(WAVEFORMATEX)))
  1700.             {
  1701.                 hr = DMO_E_INVALIDTYPE;
  1702.             }
  1703.         }
  1704.         else
  1705.         {
  1706.             WAVEFORMATEX* pWave = (WAVEFORMATEX*)pmt->pbFormat;
  1707. $$IF(PROCESS_MEDIATYPE_8BIT_PCM || PROCESS_MEDIATYPE_16BIT_PCM)    // Process PCM and maybe float
  1708. $$IF(!PROCESS_MEDIATYPE_FLOAT)                                    // Process PCM only
  1709.             if ((WAVE_FORMAT_PCM != pWave->wFormatTag) ||
  1710. $$ELSE                                                            // Process PCM and float
  1711.             if ((WAVE_FORMAT_PCM != pWave->wFormatTag &&
  1712.                  WAVE_FORMAT_IEEE_FLOAT != pWave->wFormatTag) ||
  1713. $$ENDIF
  1714. $$ELIF(PROCESS_MEDIATYPE_FLOAT)                                    // Process float only
  1715.             if ((WAVE_FORMAT_IEEE_FLOAT != pWave->wFormatTag) ||
  1716. $$ENDIF
  1717. $$IF(PROCESS_MEDIATYPE_8BIT_PCM || PROCESS_MEDIATYPE_16BIT_PCM)    // Process 8-bit or 16-bit and maybe 32-bit
  1718. $$IF(!PROCESS_MEDIATYPE_FLOAT)                                    // Process 8-bit or 16-bit only
  1719. $$IF(!PROCESS_MEDIATYPE_16BIT_PCM)                                // Process 8-bit only
  1720.                 (8 != pWave->wBitsPerSample) ||
  1721. $$ELIF(!PROCESS_MEDIATYPE_8BIT_PCM)                                // Process 16-bit only
  1722.                 (16 != pWave->wBitsPerSample) ||
  1723. $$ELSE                                                            // Process 8-bit and 16-bit only
  1724.                 ((8 != pWave->wBitsPerSample) && (16 != pWave->wBitsPerSample)) ||
  1725. $$ENDIF
  1726. $$ELSE                                                            // Process 8-bit or 16-bit and 32-bit
  1727. $$IF(!PROCESS_MEDIATYPE_16BIT_PCM)                                // Process 8-bit and 32-bit only
  1728.                 ((32 != pWave->wBitsPerSample) && (8 != pWave->wBitsPerSample)) ||
  1729. $$ELIF(!PROCESS_MEDIATYPE_8BIT_PCM)                                // Process 16-bit and 32-bit only
  1730.                 ((32 != pWave->wBitsPerSample) && (16 != pWave->wBitsPerSample)) ||
  1731. $$ELSE                                                            // Process 8-bit, 16-bit and 32-bit
  1732.                 ((32 != pWave->wBitsPerSample) && (16 != pWave->wBitsPerSample) && (8 != pWave->wBitsPerSample)) ||
  1733. $$ENDIF
  1734. $$ENDIF
  1735. $$ELSE                                                            // Process maybe only 32-bit
  1736. $$IF(PROCESS_MEDIATYPE_FLOAT)                                    // Process only 32-bit
  1737.                 (32 != pWave->wBitsPerSample) ||
  1738. $$ENDIF
  1739. $$ENDIF
  1740. $$IF(PROCESS_CHANNELS_STEREO)                                    // Process stereo and maybe mono as well
  1741. $$IF(PROCESS_CHANNELS_MONO)                                        // Process both stereo and mono
  1742.                 ((1 != pWave->nChannels) && (2 != pWave->nChannels)) ||
  1743. $$ELSE                                                            // Process stereo only
  1744.                 (2 != pWave->nChannels) ||
  1745. $$ENDIF
  1746. $$ELSE                                                            // Process mono only
  1747.                 (1 != pWave->nChannels) ||
  1748. $$ENDIF
  1749.                 ( // Supported sample rates:
  1750. $$IF(PROCESS_SAMPLE_RATES_96000)
  1751.                  (96000 != pWave->nSamplesPerSec) &&
  1752. $$ENDIF
  1753. $$IF(PROCESS_SAMPLE_RATES_48000)
  1754.                  (48000 != pWave->nSamplesPerSec) &&
  1755. $$ENDIF
  1756. $$IF(PROCESS_SAMPLE_RATES_44100)
  1757.                  (44100 != pWave->nSamplesPerSec) &&
  1758. $$ENDIF
  1759. $$IF(PROCESS_SAMPLE_RATES_32000)
  1760.                  (32000 != pWave->nSamplesPerSec) &&
  1761. $$ENDIF
  1762. $$IF(PROCESS_SAMPLE_RATES_22050)
  1763.                  (22050 != pWave->nSamplesPerSec) &&
  1764. $$ENDIF
  1765. $$IF(PROCESS_SAMPLE_RATES_16000)
  1766.                  (16000 != pWave->nSamplesPerSec) &&
  1767. $$ENDIF
  1768. $$IF(PROCESS_SAMPLE_RATES_11025)
  1769.                  (11025 != pWave->nSamplesPerSec) &&
  1770. $$ENDIF
  1771. $$IF(PROCESS_SAMPLE_RATES_8000)
  1772.                  (8000 != pWave->nSamplesPerSec) &&
  1773. $$ENDIF
  1774.                  TRUE    // You may delete && TRUE
  1775.                 ) ||
  1776.                 (pWave->nBlockAlign != pWave->nChannels * pWave->wBitsPerSample / 8) ||
  1777.                 (pWave->nAvgBytesPerSec != pWave->nSamplesPerSec * pWave->nBlockAlign))
  1778.             {
  1779.                 hr = DMO_E_INVALIDTYPE;
  1780.             }
  1781.         }
  1782.     }
  1783.  
  1784.     if (SUCCEEDED(hr))
  1785.     {
  1786.         // We will remember the number of channels, bps, and sample rate of the input type
  1787.         m_nChannels = pWave->nChannels;
  1788.         m_wBitsPerSample = pWave->wBitsPerSample;
  1789.         m_nSamplesPerSec = pWave->nSamplesPerSec;
  1790.     }
  1791.  
  1792.     return hr;
  1793. }
  1794.  
  1795.  
  1796. ////////////////////////////////////////////
  1797. //
  1798. //  IMediaObjectImpl::InternalCheckOutputType
  1799. //
  1800. //  Queries whether an output stream can accept a given media type. The derived
  1801. //  class must declare and implement this method.
  1802. //
  1803. //  Parameters
  1804. //
  1805. //      dwOutputStreamIndex
  1806. //          Index of an output stream.
  1807. //
  1808. //      pmt
  1809. //          Pointer to a DMO_MEDIA_TYPE structure that describes the media type.
  1810. //
  1811. //  Return Value
  1812. //
  1813. //      Returns S_OK if the media type is valid, or DMO_E_INVALIDTYPE otherwise.
  1814. //
  1815. //  Note:
  1816. //
  1817. //  Called by IMediaObject::SetOutputType
  1818. //
  1819. HRESULT $$CLASS_NAME$$::InternalCheckOutputType(DWORD dwOutputStreamIndex,const DMO_MEDIA_TYPE *pmt)
  1820. {
  1821.     // Check that we're PCM or float
  1822.     HRESULT hr = S_OK;
  1823.  
  1824.     if ((NULL                       == pmt) ||
  1825.         (MEDIATYPE_Audio            != pmt->majortype) ||
  1826. $$IF(PROCESS_MEDIATYPE_8BIT_PCM || PROCESS_MEDIATYPE_16BIT_PCM)
  1827. $$IF(!PROCESS_MEDIATYPE_FLOAT)
  1828.         (MEDIASUBTYPE_PCM            != pmt->subtype) ||
  1829. $$ELSE
  1830.         (MEDIASUBTYPE_PCM            != pmt->subtype &&
  1831.          MEDIASUBTYPE_IEEE_FLOAT    != pmt->subtype) ||
  1832. $$ENDIF
  1833. $$ELIF(PROCESS_MEDIATYPE_FLOAT)
  1834.         (MEDIASUBTYPE_IEEE_FLOAT    != pmt->subtype) ||
  1835. $$ENDIF
  1836.         (FORMAT_WaveFormatEx        != pmt->formattype &&
  1837.          FORMAT_None                != pmt->formattype) ||
  1838.         (pmt->cbFormat                <  sizeof(WAVEFORMATEX)) ||
  1839.         (NULL                       == pmt->pbFormat))
  1840.     {
  1841.         hr = DMO_E_INVALIDTYPE;
  1842.     }
  1843.  
  1844.     // If other type set, accept only if identical to that.  Otherwise accept
  1845.     // any standard PCM/float audio.
  1846.     if (SUCCEEDED(hr))
  1847.     {
  1848.         if (InputTypeSet(0))
  1849.         {
  1850.             const DMO_MEDIA_TYPE* pmtInput;
  1851.             pmtInput = InputType(0);
  1852.             if (memcmp(pmt->pbFormat, pmtInput->pbFormat, sizeof(WAVEFORMATEX)))
  1853.             {
  1854.                 hr = DMO_E_INVALIDTYPE;
  1855.             }
  1856.         }
  1857.         else
  1858.         {
  1859.             WAVEFORMATEX* pWave = (WAVEFORMATEX*)pmt->pbFormat;
  1860. $$IF(PROCESS_MEDIATYPE_8BIT_PCM || PROCESS_MEDIATYPE_16BIT_PCM)    // Process PCM and maybe float
  1861. $$IF(!PROCESS_MEDIATYPE_FLOAT)                                    // Process PCM only
  1862.             if ((WAVE_FORMAT_PCM != pWave->wFormatTag) ||
  1863. $$ELSE                                                            // Process PCM and float
  1864.             if ((WAVE_FORMAT_PCM != pWave->wFormatTag &&
  1865.                  WAVE_FORMAT_IEEE_FLOAT != pWave->wFormatTag) ||
  1866. $$ENDIF
  1867. $$ELIF(PROCESS_MEDIATYPE_FLOAT)                                    // Process float only
  1868.             if ((WAVE_FORMAT_IEEE_FLOAT != pWave->wFormatTag) ||
  1869. $$ENDIF
  1870. $$IF(PROCESS_MEDIATYPE_8BIT_PCM || PROCESS_MEDIATYPE_16BIT_PCM)    // Process 8-bit or 16-bit and maybe 32-bit
  1871. $$IF(!PROCESS_MEDIATYPE_FLOAT)                                    // Process 8-bit or 16-bit only
  1872. $$IF(!PROCESS_MEDIATYPE_16BIT_PCM)                                // Process 8-bit only
  1873.                 (8 != pWave->wBitsPerSample) ||
  1874. $$ELIF(!PROCESS_MEDIATYPE_8BIT_PCM)                                // Process 16-bit only
  1875.                 (16 != pWave->wBitsPerSample) ||
  1876. $$ELSE                                                            // Process 8-bit and 16-bit only
  1877.                 ((8 != pWave->wBitsPerSample) && (16 != pWave->wBitsPerSample)) ||
  1878. $$ENDIF
  1879. $$ELSE                                                            // Process 8-bit or 16-bit and 32-bit
  1880. $$IF(!PROCESS_MEDIATYPE_16BIT_PCM)                                // Process 8-bit and 32-bit only
  1881.                 ((32 != pWave->wBitsPerSample) && (8 != pWave->wBitsPerSample)) ||
  1882. $$ELIF(!PROCESS_MEDIATYPE_8BIT_PCM)                                // Process 16-bit and 32-bit only
  1883.                 ((32 != pWave->wBitsPerSample) && (16 != pWave->wBitsPerSample)) ||
  1884. $$ELSE                                                            // Process 8-bit, 16-bit and 32-bit
  1885.                 ((32 != pWave->wBitsPerSample) && (16 != pWave->wBitsPerSample) && (8 != pWave->wBitsPerSample)) ||
  1886. $$ENDIF
  1887. $$ENDIF
  1888. $$ELSE                                                            // Process maybe only 32-bit
  1889. $$IF(PROCESS_MEDIATYPE_FLOAT)                                    // Process only 32-bit
  1890.                 (32 != pWave->wBitsPerSample) ||
  1891. $$ENDIF
  1892. $$ENDIF
  1893. $$IF(PROCESS_CHANNELS_STEREO)                                    // Process stereo and maybe mono as well
  1894. $$IF(PROCESS_CHANNELS_MONO)                                        // Process both stereo and mono
  1895.                 ((1 != pWave->nChannels) && (2 != pWave->nChannels)) ||
  1896. $$ELSE                                                            // Process stereo only
  1897.                 (2 != pWave->nChannels) ||
  1898. $$ENDIF
  1899. $$ELSE                                                            // Process mono only
  1900.                 (1 != pWave->nChannels) ||
  1901. $$ENDIF
  1902.                 ( // Supported sample rates:
  1903. $$IF(PROCESS_SAMPLE_RATES_96000)
  1904.                  (96000 != pWave->nSamplesPerSec) &&
  1905. $$ENDIF
  1906. $$IF(PROCESS_SAMPLE_RATES_48000)
  1907.                  (48000 != pWave->nSamplesPerSec) &&
  1908. $$ENDIF
  1909. $$IF(PROCESS_SAMPLE_RATES_44100)
  1910.                  (44100 != pWave->nSamplesPerSec) &&
  1911. $$ENDIF
  1912. $$IF(PROCESS_SAMPLE_RATES_32000)
  1913.                  (32000 != pWave->nSamplesPerSec) &&
  1914. $$ENDIF
  1915. $$IF(PROCESS_SAMPLE_RATES_22050)
  1916.                  (22050 != pWave->nSamplesPerSec) &&
  1917. $$ENDIF
  1918. $$IF(PROCESS_SAMPLE_RATES_16000)
  1919.                  (16000 != pWave->nSamplesPerSec) &&
  1920. $$ENDIF
  1921. $$IF(PROCESS_SAMPLE_RATES_11025)
  1922.                  (11025 != pWave->nSamplesPerSec) &&
  1923. $$ENDIF
  1924. $$IF(PROCESS_SAMPLE_RATES_8000)
  1925.                  (8000 != pWave->nSamplesPerSec) &&
  1926. $$ENDIF
  1927.                  TRUE    // You may delete && TRUE
  1928.                 ) ||
  1929.                 (pWave->nBlockAlign != pWave->nChannels * pWave->wBitsPerSample / 8) ||
  1930.                 (pWave->nAvgBytesPerSec != pWave->nSamplesPerSec * pWave->nBlockAlign))
  1931.             {
  1932.                 hr = DMO_E_INVALIDTYPE;
  1933.             }
  1934.         }
  1935.     }
  1936.  
  1937.     return hr;
  1938. }
  1939.  
  1940.  
  1941. ///////////////
  1942. //
  1943. //  IMediaObjectImpl::Lock
  1944. //
  1945. // Locks the object. The derived class must declare and implement this method.
  1946. //
  1947. // If you implement your derived class using the Active Template Library (ATL),
  1948. // you can use ATL's default implementation of this method.
  1949. //
  1950. void $$CLASS_NAME$$::Lock(void)
  1951. {
  1952.     CComObjectRootEx<CComMultiThreadModel>::Lock();
  1953. }
  1954.  
  1955.  
  1956. ///////////////
  1957. //
  1958. // IMediaObjectImpl::Unlock
  1959. //
  1960. // Unlocks the object. The derived class must declare and implement this method.
  1961. //
  1962. // If you implement your derived class using the Active Template Library (ATL),
  1963. // you can use ATL's default implementation of this method.
  1964. //
  1965. void $$CLASS_NAME$$::Unlock(void)
  1966. {
  1967.     CComObjectRootEx<CComMultiThreadModel>::Unlock();
  1968. }
  1969.  
  1970.  
  1971. $$IF(SUPPORT_DS_IMEDPARAM || SUPPORT_DS_DMP)
  1972. //////////////////////////////////////////////////////////////////////////////
  1973. //
  1974. // $$CLASS_NAME$$::SetParamInternal
  1975. //
  1976. HRESULT $$CLASS_NAME$$::SetParamInternal(DWORD dwParamIndex, MP_DATA value, bool fSkipPasssingToParamManager)
  1977. {
  1978.     switch (dwParamIndex)
  1979.     {
  1980. $$IF(EMPTY_DSDMO)
  1981.     case $$DSDMO_DEFINE$$_PARAM1:
  1982.         m_dwParam1 = (DWORD)value;
  1983.         break;
  1984.     // TODO: Add cases for each of your parameters
  1985. $$ELSE    // Sample DMO
  1986.     case PANNER_FREQ:
  1987.         m_fFreq = (float)value;
  1988.         UpdateStatesInternal();                    // To update m_ulPeriod
  1989.         break;
  1990.     case PANNER_WIDTH:
  1991.         m_fWidth = (float)value;
  1992.         break;
  1993. $$ENDIF
  1994.     default:
  1995.         return E_INVALIDARG;
  1996.     }
  1997.  
  1998.     // Let base class set this so it can handle all the rest of the param calls.
  1999.     // Skip the base class if fSkipPasssingToParamManager.  This indicates that we're calling the function
  2000.     //    internally using values that came from the base class -- thus there's no need to tell it values it
  2001.     //    already knows.
  2002.     return fSkipPasssingToParamManager ? S_OK : CParamsManager::SetParam(dwParamIndex, value);
  2003. }
  2004.  
  2005. //////////////////
  2006. //  Macros used by GetAllParameters() and SetAllParameters()
  2007. //
  2008. // GET_PARAM_DWORD()
  2009. #define GET_PARAM_DWORD(x, y) \
  2010.     if (SUCCEEDED(hr)) \
  2011.     { \
  2012.         hr = GetParam(x, &var); \
  2013.         if (SUCCEEDED(hr)) \
  2014.         { \
  2015.             y = (DWORD)var; \
  2016.         } \
  2017.     }
  2018.  
  2019. // GET_PARAM_FLOAT()
  2020. #define GET_PARAM_FLOAT(x, y) \
  2021.     if (SUCCEEDED(hr)) \
  2022.     { \
  2023.         hr = GetParam(x, &var); \
  2024.         if (SUCCEEDED(hr)) \
  2025.         { \
  2026.             y = (float)var; \
  2027.         } \
  2028.     }
  2029.  
  2030. // SET_PARAM()
  2031. #define SET_PARAM(x, y) \
  2032.     if (SUCCEEDED(hr)) \
  2033.     { \
  2034.         hr = SetParam(x, static_cast<MP_DATA>(y)); \
  2035.     }
  2036.  
  2037. ///////////////
  2038. //
  2039. // $$INTERFACE_NAME$$::SetAllParameters
  2040. //
  2041. STDMETHODIMP $$CLASS_NAME$$::SetAllParameters(THIS_ LPC$$DSDMOID_NAME$$Params pParm)
  2042. {
  2043.     HRESULT hr = S_OK;
  2044.  
  2045.     // Check that the pointer is not NULL
  2046.     if (NULL == pParm)
  2047.     {
  2048.         hr = E_POINTER;
  2049.     }
  2050.  
  2051.     // Set the parameters
  2052.     if (SUCCEEDED(hr))
  2053.     {
  2054. $$IF(EMPTY_DSDMO)
  2055.     // TODO: Set all parameters with values stored in pParm. Example:
  2056.         SET_PARAM($$DSDMO_DEFINE$$_PARAM1, pParm->dwParam1);
  2057.     // End of Example
  2058. $$ELSE    // Sample DMO
  2059.         SET_PARAM(PANNER_FREQ,  pParm->fFreq);
  2060.         SET_PARAM(PANNER_WIDTH, pParm->fWidth);
  2061. $$ENDIF
  2062.     }
  2063.  
  2064.     m_fDirty = TRUE;
  2065.     return hr;
  2066. }
  2067.  
  2068.  
  2069. ///////////////
  2070. //
  2071. // $$INTERFACE_NAME$$::GetAllParameters
  2072. //
  2073. STDMETHODIMP $$CLASS_NAME$$::GetAllParameters(THIS_ LP$$DSDMOID_NAME$$Params pParm)
  2074. {
  2075.     HRESULT hr    = S_OK;
  2076.     MP_DATA var;
  2077.  
  2078.     if (NULL == pParm)
  2079.     {
  2080.         return E_POINTER;
  2081.     }
  2082.  
  2083. $$IF(EMPTY_DSDMO)
  2084. // TODO: Get all parameter values into pParm.
  2085.     // Example:
  2086.     GET_PARAM_DWORD($$DSDMO_DEFINE$$_PARAM1, pParm->dwParam1);
  2087.     // End of Example
  2088. $$ELSE    // Sample DMO
  2089.      GET_PARAM_FLOAT(PANNER_FREQ, pParm->fFreq);
  2090.     GET_PARAM_FLOAT(PANNER_WIDTH, pParm->fWidth);
  2091. $$ENDIF
  2092.  
  2093.     return hr;
  2094. }
  2095.  
  2096.  
  2097. ////////////////
  2098. //
  2099. // IPersist::GetClassID
  2100. //
  2101. // Get the class ID for this class
  2102. //
  2103. HRESULT $$CLASS_NAME$$::GetClassID(CLSID *pClsid)
  2104. {
  2105.     // Check for valid pointer
  2106.     if( NULL == pClsid )
  2107.     {
  2108.         return E_POINTER;
  2109.     }
  2110.  
  2111.     *pClsid = CLSID_$$DSDMO_DEFINE$$;
  2112.     return S_OK;
  2113.  
  2114. } // GetClassID
  2115.  
  2116.  
  2117. ////////////////
  2118. //
  2119. // IPersistStream::IsDirty
  2120. //
  2121. // Checks the object for changes since it was last saved
  2122. //
  2123. HRESULT $$CLASS_NAME$$::IsDirty()
  2124. {
  2125.     return m_fDirty ? S_OK : S_FALSE;
  2126. }
  2127.  
  2128. ////////////////
  2129. //
  2130. // IPersistStream::Load
  2131. //
  2132. // Initializes an object from the stream where it was previously saved
  2133. //
  2134. HRESULT $$CLASS_NAME$$::Load(IStream *pStm)
  2135. {
  2136.     ULONG ulSizeRead = 0;
  2137.     HRESULT hr = S_OK;
  2138.  
  2139.     if (NULL == pStm)
  2140.     {
  2141.         return E_POINTER;
  2142.     }
  2143.  
  2144.     $$DSDMOID_NAME$$Params params;
  2145.     hr = pStm->Read((void *)¶ms, sizeof(params), &ulSizeRead);
  2146.     if (hr != S_OK || ulSizeRead < sizeof(params))
  2147.     {
  2148.         return E_FAIL;
  2149.     }
  2150.  
  2151.     hr = SetAllParameters(¶ms);
  2152.  
  2153.     m_fDirty = FALSE;
  2154.  
  2155.     return hr;
  2156. }
  2157.  
  2158.  
  2159. ////////////////
  2160. //
  2161. // IPersistStream::Save
  2162. //
  2163. // This method saves an object to the specified stream
  2164. //
  2165. HRESULT $$CLASS_NAME$$::Save(IStream *pStm, BOOL fClearDirty)
  2166. {
  2167.     HRESULT hr = S_OK;
  2168.  
  2169.     if (NULL == pStm)
  2170.     {
  2171.         return E_POINTER;
  2172.     }
  2173.  
  2174.     $$DSDMOID_NAME$$Params params;
  2175.     hr = GetAllParameters(¶ms);
  2176.     if (FAILED(hr))
  2177.     {
  2178.         return hr;
  2179.     }
  2180.  
  2181.     ULONG ulSizeWritten = 0;
  2182.     hr = pStm->Write((void *)¶ms, sizeof(params), &ulSizeWritten);
  2183.     if (hr != S_OK || ulSizeWritten < sizeof(params))
  2184.     {
  2185.         return E_FAIL;
  2186.     }
  2187.  
  2188.     if (fClearDirty)
  2189.     {
  2190.         m_fDirty = FALSE;
  2191.     }
  2192.  
  2193.     return S_OK;
  2194. }
  2195.  
  2196.  
  2197. ////////////////
  2198. //
  2199. // IPersistStream::GetSizeMax
  2200. //
  2201. // This method returns the size in bytes of the stream needed to save the object
  2202. //
  2203. HRESULT $$CLASS_NAME$$::GetSizeMax(ULARGE_INTEGER *pcbSize)
  2204. {
  2205.     if ( NULL == pcbSize )
  2206.         return E_POINTER;
  2207.  
  2208.     pcbSize->QuadPart = sizeof($$DSDMOID_NAME$$Params);
  2209.     return S_OK;
  2210. }
  2211.  
  2212. // ENDIF for IF(SUPPORT_DS_IMEDPARAM || SUPPORT_DS_DMP)  (a few pages up)
  2213. $$ENDIF
  2214.  
  2215.  
  2216. $$IF(SUPPORT_DS_DMP)
  2217. ////////////////
  2218. //
  2219. // _DERIVED_::GetPages
  2220. //
  2221. // Get the property pages GUIDs
  2222. //
  2223. HRESULT $$CLASS_NAME$$::GetPages(CAUUID *pPages)
  2224. {
  2225.     // Only one property page is required for DMO
  2226.     pPages->cElems = 1;
  2227.     pPages->pElems = static_cast<GUID *>(CoTaskMemAlloc(sizeof(GUID)));
  2228.  
  2229.     // Make sure memory is allocated for pPages->pElems
  2230.     if (NULL == pPages->pElems)
  2231.     {
  2232.         return E_OUTOFMEMORY;
  2233.     }
  2234.  
  2235.     // Return the property page's class ID
  2236.     *(pPages->pElems) = CLSID_$$DSDMO_DEFINE$$PROP;
  2237.     return S_OK;
  2238. }
  2239.  
  2240. $$ENDIF
  2241.