source: trunk/Utilities/GeneratePcmWavFile/Application.cpp

Last change on this file was 824, checked in by roman, 4 years ago

VS2017 upgrade, 32-bit PCM support (limited)

File size: 22.2 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2018
3// Created by Roman Ryltsov roman@alax.info
4
5#include "stdafx.h"
6#include "rodshow.h"
7
8////////////////////////////////////////////////////////////
9// CModule
10
11class CModule : 
12        public CAtlExeModuleT<CModule>
13{
14        typedef CThreadT<CModule> CThread;
15
16public:
17
18        ////////////////////////////////////////////////////////
19        // CSourceFilter
20
21        class ATL_NO_VTABLE CSourceFilter :
22                public CComObjectRootEx<CComMultiThreadModelNoCS>,
23                public CComCoClass<CSourceFilter>,
24                public CPushSourceFilterT<CSourceFilter>,
25                public CBasePersistT<CSourceFilter>,
26                public CAmFilterMiscFlagsT<CSourceFilter, AM_FILTER_MISC_FLAGS_IS_SOURCE>
27        {
28        public:
29
30        DECLARE_NO_REGISTRY()
31
32        DECLARE_PROTECT_FINAL_CONSTRUCT()
33
34        //DECLARE_QI_TRACE(CSourceFilter)
35
36        BEGIN_COM_MAP(CSourceFilter)
37                COM_INTERFACE_ENTRY(IBaseFilter)
38                COM_INTERFACE_ENTRY(IMediaFilter)
39                COM_INTERFACE_ENTRY_IID(__uuidof(IPersist), IBaseFilter)
40                COM_INTERFACE_ENTRY(IAMFilterMiscFlags)
41        END_COM_MAP()
42
43        public:
44
45                ////////////////////////////////////////////////////////
46                // CThreadContext
47
48                class COutputPin;
49
50                class CThreadContext :
51                        public CPushSourceFilterT<CSourceFilter>::CThreadContext
52                {
53                public:
54                        CEvent m_MediaSampleTimeEvent;
55                        REFERENCE_TIME m_nMediaSampleTime;
56                        SIZE_T m_nCurrentSampleIndex;
57
58                public:
59                // CThreadContext
60                        CThreadContext(CEvent& TerminationEvent) :
61                                CPushSourceFilter::CThreadContext(TerminationEvent),
62                                m_nMediaSampleTime(0),
63                                m_nCurrentSampleIndex(0)
64                        {
65                        }
66                };
67
68                ////////////////////////////////////////////////////////
69                // COutputPin
70
71                class ATL_NO_VTABLE COutputPin :
72                        public CComObjectRootEx<CComMultiThreadModelNoCS>,
73                        public CPushSourceFilterT<CSourceFilter>::COutputPinT<COutputPin, CSourceFilter, CThreadContext>,
74                        public CAmPushSourceT<COutputPin, 0>
75                {
76                public:
77
78                //DECLARE_QI_TRACE(CSourceFilter::COutputPin)
79
80                BEGIN_COM_MAP(COutputPin)
81                        COM_INTERFACE_ENTRY(IPin)
82                        COM_INTERFACE_ENTRY(IAMPushSource)
83                        COM_INTERFACE_ENTRY(IAMLatency)
84                END_COM_MAP()
85
86                public:
87                        CMediaType m_pDataMediaType;
88                        REFERENCE_TIME m_nDataLength;
89                        DOUBLE m_fSignalPeriod;
90                        DOUBLE m_fSignalAmplitude;
91                        DOUBLE m_fNoiseAmplitude;
92
93                public:
94                // COutputPin
95                        COutputPin() :
96                                m_nDataLength(0),
97                                m_fSignalPeriod(0),
98                                m_fSignalAmplitude(0),
99                                m_fNoiseAmplitude(0)
100                        {
101                                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
102                        }
103                        ~COutputPin()
104                        {
105                                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
106                        }
107                        VOID EnumerateMediaTypes(CAtlList<CMediaType>& MediaTypeList)
108                        {
109                                CRoCriticalSectionLock DataLock(GetDataCriticalSection());
110                                _W(MediaTypeList.AddTail(m_pDataMediaType));
111                        }
112                        BOOL CheckMediaType(const CMediaType& pMediaType) const
113                        {
114                                _A(pMediaType);
115                                //if(pMediaType->majortype != MEDIATYPE_Audio || pMediaType->subtype != MEDIASUBTYPE_PCM)
116                                //      return FALSE;
117                                //const CWaveFormatEx* pWaveFormatEx = pMediaType.GetWaveFormatEx();
118                                //if(!pWaveFormatEx)
119                                //      return FALSE;
120                                return m_pDataMediaType.Compare(pMediaType);
121                        }
122                        BOOL DecideMemAllocatorProperties(IMemAllocator* pMemAllocator, ALLOCATOR_PROPERTIES Properties)
123                        {
124                                CRoCriticalSectionLock DataLock(GetDataCriticalSection());
125                                const CMediaType& pMediaType = GetMediaTypeReference();
126                                const CWaveFormatEx* pWaveFormatEx = pMediaType.GetWaveFormatEx();
127                                if(!pWaveFormatEx)
128                                        return FALSE;
129                                if(!__super::DecideMemAllocatorProperties(pMemAllocator, Properties))
130                                        return FALSE;
131                                static const ULONG g_nDefaultBufferLength = 500; // 500 ms
132                                const SIZE_T nDefaultBufferBlockCount = (pWaveFormatEx->nAvgBytesPerSec * g_nDefaultBufferLength / 1000 + pWaveFormatEx->nBlockAlign - 1) / pWaveFormatEx->nBlockAlign;
133                                const SIZE_T nDefaultBufferSize = nDefaultBufferBlockCount * pWaveFormatEx->nBlockAlign;
134                                if(Properties.cbBuffer < (LONG) nDefaultBufferSize)
135                                        Properties.cbBuffer = (LONG) nDefaultBufferSize;
136                                if(Properties.cbAlign < pWaveFormatEx->nBlockAlign)
137                                        Properties.cbAlign = pWaveFormatEx->nBlockAlign;
138                                if(!SetMemAllocatorBufferSize(pMemAllocator, Properties))
139                                        return FALSE;
140                                const SIZE_T nSampleCount = Properties.cbBuffer / pWaveFormatEx->nBlockAlign;
141                                const SIZE_T nEffectiveBufferSize = nSampleCount * pWaveFormatEx->nBlockAlign;
142                                const REFERENCE_TIME nBufferTime = (REFERENCE_TIME) (1000 * 10000) * nEffectiveBufferSize / pWaveFormatEx->nAvgBytesPerSec;
143                                SetLatency(nBufferTime);
144                                return TRUE;
145                        }
146                        VOID InitializeThread(CThreadContext& ThreadContext)
147                        {
148                                CRoCriticalSectionLock DataLock(GetDataCriticalSection());
149                                __super::InitializeThread(ThreadContext);
150                                if(m_fSignalPeriod > 0)
151                                {
152                                        const WORD wBitsPerSample = m_pDataMediaType.GetWaveFormatEx()->wBitsPerSample;
153                                        __D(wBitsPerSample == 16 || wBitsPerSample == 24 || wBitsPerSample == 32, E_NOTIMPL);
154                                        ThreadContext.m_nCurrentSampleIndex = 0;
155                                }
156                        }
157                        BOOL ComposeMediaSample(CThreadContext& ThreadContext, IMediaSample* pMediaSample)
158                        {
159                                CMediaSampleProperties Properties(pMediaSample);
160                                _A(!Properties.pMediaType);
161                                if(ThreadContext.m_nMediaSampleTime >= m_nDataLength)
162                                        return FALSE; // Finished
163                                CRoCriticalSectionLock DataLock(GetDataCriticalSection());
164                                const CWaveFormatEx* pWaveFormatEx = GetMediaTypeReference().GetWaveFormatEx();
165                                _A(pWaveFormatEx);
166                                const SIZE_T nRemainedDataSize = (SIZE_T) ((m_nDataLength - ThreadContext.m_nMediaSampleTime) * pWaveFormatEx->nAvgBytesPerSec / (1000 * 10000i64));
167                                SIZE_T nDataSize = Properties.cbBuffer;
168                                if(nDataSize > nRemainedDataSize)
169                                        nDataSize = nRemainedDataSize;
170                                nDataSize = (nDataSize / pWaveFormatEx->nBlockAlign) * pWaveFormatEx->nBlockAlign;
171                                if(pWaveFormatEx->wBitsPerSample == 8)
172                                {
173                                        FillMemory(Properties.pbBuffer, nDataSize, 0x80);
174                                } else
175                                {
176                                        _A(pWaveFormatEx->wBitsPerSample == 16 || pWaveFormatEx->wBitsPerSample == 32);
177                                        ZeroMemory(Properties.pbBuffer, nDataSize);
178                                        #pragma region Sine Wave Data
179                                        if(m_fSignalPeriod > 0)
180                                        {
181                                                SIZE_T nSampleIndex = 0;
182                                                switch(pWaveFormatEx->wBitsPerSample)
183                                                {
184                                                case 16:
185                                                        {
186                                                                for(SIZE_T nIndex = 0; nIndex < nDataSize; nIndex += pWaveFormatEx->nBlockAlign, nSampleIndex++)
187                                                                {
188                                                                        #pragma region Per-channel Frequencies and Amplitudes
189                                                                        if(FALSE)
190                                                                        {
191                                                                                const DOUBLE pfSignalFrequencies[6] = { 1000, 1000, 1000, 1000, 1000, 1000, };
192                                                                                const DOUBLE pfSignalAmplitudes[6] = { m_fSignalAmplitude, m_fSignalAmplitude, m_fSignalAmplitude, 0, 0, 0,  };
193                                                                                //const DOUBLE pfSignalFrequencies[2] = { 1000, 1000, };
194                                                                                //const DOUBLE pfSignalAmplitudes[2] = { m_fSignalAmplitude, m_fSignalAmplitude, };
195                                                                                SHORT* pnSampleData = (SHORT*) (Properties.pbBuffer + nIndex);
196                                                                                _A(DIM(pfSignalFrequencies) == DIM(pfSignalAmplitudes));
197                                                                                _A(pWaveFormatEx->nChannels <= DIM(pfSignalFrequencies));
198                                                                                for(WORD nChannelIndex = 0; nChannelIndex < pWaveFormatEx->nChannels; nChannelIndex++)
199                                                                                {
200                                                                                        const DOUBLE fSignalPeriod = (DOUBLE) pWaveFormatEx->nSamplesPerSec / pfSignalFrequencies[nChannelIndex];
201                                                                                        const DOUBLE fSignalAmplitude = pfSignalAmplitudes[nChannelIndex];
202                                                                                        const SHORT nValue = (SHORT) (fSignalAmplitude * sin(2 * M_PI * (ThreadContext.m_nCurrentSampleIndex + nSampleIndex) / fSignalPeriod));
203                                                                                        pnSampleData[nChannelIndex] = nValue;
204                                                                                }
205                                                                                continue;
206                                                                        }
207                                                                        #pragma endregion
208                                                                        #pragma region Stream Time Coefficients
209                                                                        #if TRUE && FALSE
210                                                                        {
211                                                                                COMPILER_MESSAGE("Every 170 seconds: 50 seconds 1.0, 70 seconds 0.0, 50 seconds 1.0");
212                                                                                #pragma region Factor
213                                                                                REFERENCE_TIME nTime = ThreadContext.m_nMediaSampleTime + nIndex * (1000 * 10000i64) / pWaveFormatEx->nAvgBytesPerSec;
214                                                                                nTime /= 1000 * 10000i64;
215                                                                                // NOTE: Every 170 seconds: 50 seconds 1.0, 70 seconds 0.0, 50 seconds 1.0
216                                                                                nTime %= 170;
217                                                                                const DOUBLE fTimeFactor = (nTime < 50 || nTime >= 120) ? 1.0 : (1.0 / 256);
218                                                                                #pragma endregion
219                                                                                const SHORT nValue = (SHORT) (m_fSignalAmplitude * sin(2 * M_PI * (ThreadContext.m_nCurrentSampleIndex + nSampleIndex) / m_fSignalPeriod));
220                                                                                SHORT* pnSampleData = (SHORT*) (Properties.pbBuffer + nIndex);
221                                                                                for(WORD nChannelIndex = 0; nChannelIndex < pWaveFormatEx->nChannels; nChannelIndex++)
222                                                                                        pnSampleData[nChannelIndex] = (SHORT) (fTimeFactor * nValue);
223                                                                                continue;
224                                                                        }
225                                                                        #endif // TRUE
226                                                                        #pragma endregion
227                                                                        // NOTE: Phase shift might be added here, e.g. "... + nSampleIndex + 0.25)..."
228                                                                        const INT16 nValue = (INT16) (m_fSignalAmplitude * sin(2 * M_PI * (ThreadContext.m_nCurrentSampleIndex + nSampleIndex) / m_fSignalPeriod));
229                                                                        INT16* pnSampleData = (INT16*) (Properties.pbBuffer + nIndex);
230                                                                        for(WORD nChannelIndex = 0; nChannelIndex < pWaveFormatEx->nChannels; nChannelIndex++)
231                                                                                pnSampleData[nChannelIndex] = nValue;
232                                                                }
233                                                        }
234                                                        break;
235                                                case 32:
236                                                        {
237                                                                for(SIZE_T nIndex = 0; nIndex < nDataSize; nIndex += pWaveFormatEx->nBlockAlign, nSampleIndex++)
238                                                                {
239                                                                        // NOTE: Phase shift might be added here, e.g. "... + nSampleIndex + 0.25)..."
240                                                                        const INT32 nValue = (INT32) (m_fSignalAmplitude * sin(2 * M_PI * (ThreadContext.m_nCurrentSampleIndex + nSampleIndex) / m_fSignalPeriod));
241                                                                        INT32* pnSampleData = (INT32*) (Properties.pbBuffer + nIndex);
242                                                                        for(WORD nChannelIndex = 0; nChannelIndex < pWaveFormatEx->nChannels; nChannelIndex++)
243                                                                                pnSampleData[nChannelIndex] = nValue;
244                                                                }
245                                                        }
246                                                        break;
247                                                default:
248                                                        _A(FALSE);
249                                                }
250                                        }
251                                        #pragma endregion
252                                        #pragma region Noise Wave Data
253                                        if(m_fNoiseAmplitude > 0)
254                                        {
255                                                _A(pWaveFormatEx->wBitsPerSample == 16);
256                                                for(SIZE_T nIndex = 0; nIndex < nDataSize; nIndex += pWaveFormatEx->nBlockAlign)
257                                                {
258                                                        SHORT* pnSampleData = (SHORT*) (Properties.pbBuffer + nIndex);
259                                                        for(WORD nChannelIndex = 0; nChannelIndex < pWaveFormatEx->nChannels; nChannelIndex++)
260                                                                pnSampleData[nChannelIndex] += (SHORT) (m_fNoiseAmplitude * (DOUBLE) (rand() - RAND_MAX / 2) / (RAND_MAX / 2));
261                                                }
262                                        }
263                                        #pragma endregion
264                                }
265                                ThreadContext.m_nMediaSampleTime += nDataSize * (1000 * 10000i64) / pWaveFormatEx->nAvgBytesPerSec;
266                                ThreadContext.m_nCurrentSampleIndex += nDataSize / pWaveFormatEx->nBlockAlign;
267                                Properties.lActual = (LONG) nDataSize;
268                                Properties.Set();
269                                return TRUE;
270                        }
271                        VOID InitializeData(const CWaveFormatEx* pWaveFormatEx, REFERENCE_TIME nLength)
272                        {
273                                _A(pWaveFormatEx);
274                                _A(nLength > 0);
275                                __D(!m_pDataMediaType, E_UNNAMED);
276                                m_pDataMediaType.AllocateWaveFormatEx(pWaveFormatEx);
277                                m_nDataLength = nLength;
278                        }
279                        VOID InitializeSignal(DOUBLE fSignalPeriod, DOUBLE fSignalAmplitude, DOUBLE fNoiseAmplitude)
280                        {
281                                __D(fSignalPeriod >= 0 && fSignalAmplitude >= 0 && fNoiseAmplitude >= 0, E_INVALIDARG);
282                                m_fSignalPeriod = fSignalPeriod;
283                                m_fSignalAmplitude = fSignalAmplitude;
284                                m_fNoiseAmplitude = fNoiseAmplitude;
285                        }
286                };
287
288        private:
289                CObjectPtr<COutputPin> m_pOutputPin;
290
291        public:
292        // CSourceFilter
293                CSourceFilter() :
294                        CBasePersistT<CSourceFilter>(GetDataCriticalSection())
295                {
296                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
297                }
298                ~CSourceFilter()
299                {
300                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
301                }
302                HRESULT FinalConstruct()
303                {
304                        _ATLTRY
305                        {
306                                m_pOutputPin.Construct()->Initialize(this, L"Output");
307                                AddPin(m_pOutputPin);
308                        }
309                        _ATLCATCH(Exception)
310                        {
311                                _C(Exception);
312                        }
313                        return S_OK;
314                }
315                VOID FinalRelease()
316                {
317                        m_pOutputPin = NULL;
318                }
319                VOID DeliverBeginFlush(IPin*)
320                {
321                        m_pOutputPin->DeliverBeginFlush();
322                }
323                VOID DeliverEndFlush(IPin*)
324                {
325                        m_pOutputPin->DeliverEndFlush();
326                }
327                VOID DeliverNewSegment(IPin*, REFERENCE_TIME nStartTime, REFERENCE_TIME nStopTime, DOUBLE fRate)
328                {
329                        m_pOutputPin->DeliverNewSegment(nStartTime, nStopTime, fRate);
330                }
331                static BOOL CanCue()
332                {
333                        return FALSE;
334                }
335                VOID CueFilter()
336                {
337                        m_pOutputPin->CuePin();
338                }
339                VOID RunFilter(REFERENCE_TIME nStartTime)
340                {
341                        m_pOutputPin->RunPin(nStartTime);
342                }
343                VOID PauseFilter()
344                {
345                        m_pOutputPin->PausePin();
346                }
347                VOID StopFilter()
348                {
349                        m_pOutputPin->StopPin();
350                }
351                const CObjectPtr<COutputPin>& GetOutputPin() const
352                {
353                        return m_pOutputPin;
354                }
355                VOID Initialize(const CWaveFormatEx* pWaveFormatEx, REFERENCE_TIME nLength)
356                {
357                        m_pOutputPin->InitializeData(pWaveFormatEx, nLength);
358                }
359                VOID InitializeSignal(DOUBLE fSignalAmplitude, DOUBLE fSignalPeriod, DOUBLE fNoiseAmplitude)
360                {
361                        m_pOutputPin->InitializeSignal(fSignalAmplitude, fSignalPeriod, fNoiseAmplitude);
362                }
363        };
364
365private:
366        CWaveFormatEx m_WaveFormatEx;
367        REFERENCE_TIME m_nLength;
368        UINT m_nSignalFrequency;
369        UINT m_nSignalLoudness;
370        UINT m_nNoiseLoudness;
371        CPath m_sPath;
372
373public:
374// CModule
375        CModule()
376        {
377                AtlTraceSetDefaultSettings();
378                _Z4_THIS();
379                ZeroMemory(&m_WaveFormatEx, sizeof m_WaveFormatEx);
380                m_nLength = 0;
381                m_nSignalFrequency = 0;
382                m_nSignalLoudness = 0;
383                m_nNoiseLoudness = 0;
384        }
385        ~CModule()
386        {
387                _Z4_THIS();
388        }
389        VOID SetSampleRate(UINT nSampleRate)
390        {
391                __D(nSampleRate > 0, E_INVALIDARG);
392                m_WaveFormatEx.nSamplesPerSec = (DWORD) nSampleRate;
393        }
394        VOID SetChannelCount(UINT nChannelCount)
395        {
396                __D(nChannelCount > 0, E_INVALIDARG);
397                m_WaveFormatEx.nChannels = (WORD) nChannelCount;
398        }
399        VOID SetSampleBitCount(UINT nSampleBitCount)
400        {
401                __D(nSampleBitCount == 8 || nSampleBitCount == 16 || nSampleBitCount == 24 || nSampleBitCount == 32, E_INVALIDARG);
402                m_WaveFormatEx.wBitsPerSample = (WORD) nSampleBitCount;
403        }
404        VOID SetLength(REFERENCE_TIME nLength)
405        {
406                __D(nLength > 0, E_INVALIDARG);
407                m_nLength = nLength;
408        }
409        VOID SetSignalFrequency(UINT nSignalFrequency)
410        {
411                __D(nSignalFrequency > 0, E_INVALIDARG);
412                m_nSignalFrequency = nSignalFrequency;
413        }
414        VOID SetSignalLoudness(UINT nSignalLoudness)
415        {
416                __D(nSignalLoudness >= 0, E_INVALIDARG);
417                m_nSignalLoudness = nSignalLoudness;
418        }
419        VOID SetNoiseLoudness(UINT nNoiseLoudness)
420        {
421                __D(nNoiseLoudness >= 0, E_INVALIDARG);
422                m_nNoiseLoudness = nNoiseLoudness;
423        }
424        VOID SetPath(LPCTSTR pszPath)
425        {
426                __D(_tcslen(pszPath), E_INVALIDARG);
427                __D(!_tcslen(m_sPath), E_INVALIDARG);
428                m_sPath = pszPath;
429        }
430        HRESULT PreMessageLoop(INT nShowCommand)
431        {
432                __C(__super::PreMessageLoop(nShowCommand));
433                return S_OK;
434        }
435        VOID RunMessageLoop()
436        {
437                #pragma region Input Validation and Syntax
438                if(!m_WaveFormatEx.nSamplesPerSec || !m_WaveFormatEx.nChannels || !m_WaveFormatEx.wBitsPerSample || !m_nLength || !_tcslen(m_sPath))
439                {
440                        _tprintf(_T("Syntax: GeneratePcmWavFile <options> <output-path>\n"));
441                        _tprintf(_T("  /s:N: Sampling Rate N, Hz\n"));
442                        _tprintf(_T("  /c:N: Channel Count N\n"));
443                        _tprintf(_T("  /b:N: Sample Bit Count N, 8 or 16\n"));
444                        _tprintf(_T("  /t:N: Length N, seconds\n"));
445                        _tprintf(_T("  /f:N: Sine Signal Frequency N, Hz\n"));
446                        _tprintf(_T("  /l:N: Sine Signal Loudness N, dB below full scale\n"));
447                        _tprintf(_T("  /n:N: Noise Signal Loudness N, dB below full scale\n"));
448                        AtlThrow(S_FALSE);
449                }
450                #pragma endregion
451                #pragma region Complete Audio Format
452                m_WaveFormatEx.wFormatTag = WAVE_FORMAT_PCM;
453                m_WaveFormatEx.nBlockAlign = m_WaveFormatEx.nChannels * ((m_WaveFormatEx.wBitsPerSample + 7) >> 3);
454                m_WaveFormatEx.nAvgBytesPerSec = m_WaveFormatEx.nSamplesPerSec * m_WaveFormatEx.nBlockAlign;
455                CWaveFormatEx* pWaveFormatEx = &m_WaveFormatEx;
456                // SUGG: Replace with WAVEFORMATEXTENSIBLE where appropriate
457                #pragma endregion
458                #pragma region Filter Graph
459                CGenericFilterGraph GenericFilterGraph(TRUE);
460                GenericFilterGraph.CoCreateInstance();
461                CObjectPtr<CSourceFilter> pSourceFilter;
462                pSourceFilter.Construct()->Initialize(pWaveFormatEx, m_nLength);
463                if(m_nSignalFrequency && m_nSignalLoudness >= 0 || m_nNoiseLoudness)
464                {
465                        __D(m_WaveFormatEx.wBitsPerSample == 16 || m_WaveFormatEx.wBitsPerSample == 24 || m_WaveFormatEx.wBitsPerSample == 32, E_NOTIMPL);
466                        DOUBLE fSignalPeriod = 0, fSignalAmplitude = 0;
467                        if(m_nSignalFrequency && m_nSignalLoudness >= 0)
468                        {
469                                fSignalPeriod = (DOUBLE) pWaveFormatEx->nSamplesPerSec / m_nSignalFrequency;
470                                fSignalAmplitude = (((UINT64) 1 << (m_WaveFormatEx.wBitsPerSample - 1)) - 1) / pow(10.0, m_nSignalLoudness / 20.0);
471                        }
472                        DOUBLE fNoiseAmplitude = 0;
473                        if(m_nNoiseLoudness)
474                        {
475                                fNoiseAmplitude = (((UINT64) 1 << (m_WaveFormatEx.wBitsPerSample - 1)) - 1) / pow(10.0, m_nNoiseLoudness / 20.0);
476                        }
477                        pSourceFilter->InitializeSignal(fSignalPeriod, fSignalAmplitude, fNoiseAmplitude);
478                }
479                __C(GenericFilterGraph->AddFilter(pSourceFilter, CT2CW(_T("Source"))));
480                CComPtr<IPin> pCurrentOutputPin = pSourceFilter->GetOutputPin();
481                #pragma region WAV Dest
482                CComPtr<IBaseFilter> pWavDestBaseFilter;
483                _ATLTRY
484                {
485                        __C(pWavDestBaseFilter.CoCreateInstance(_PersistHelper::ClassIdentifierFromString(CT2CW(_T("{3C78B8E2-6C4D-11D1-ADE2-0000F8754B99}")))));
486                        __C(GenericFilterGraph->AddFilter(pWavDestBaseFilter, CT2CW(_T(".WAV Multiplexer"))));
487                        __C(GenericFilterGraph->Connect(pCurrentOutputPin, _FilterGraphHelper::GetFilterPin(pWavDestBaseFilter, PINDIR_INPUT)));
488                        pCurrentOutputPin = _FilterGraphHelper::GetFilterPin(pWavDestBaseFilter, PINDIR_OUTPUT);
489                }
490                _ATLCATCH(Exception)
491                {
492                        _tprintf(_T("There was an error trying to instantiate WAV Dest filter, Exception 0x%08X\n"), (HRESULT) Exception);
493                        _ATLRETHROW;
494                }
495                #pragma endregion
496                #pragma region File Writer
497                CComPtr<IBaseFilter> pFileWriterBaseFilter;
498                __C(pFileWriterBaseFilter.CoCreateInstance(CLSID_FileWriter));
499                CComQIPtr<IFileSinkFilter2> pFileSinkFilter2 = pFileWriterBaseFilter;
500                __D(pFileSinkFilter2, E_NOINTERFACE);
501                _tprintf(_T("Writing into \"%s\"...\n"), m_sPath);
502                __C(pFileSinkFilter2->SetFileName(CT2CW(m_sPath), NULL));
503                __C(pFileSinkFilter2->SetMode(AM_FILE_OVERWRITE));
504                __C(GenericFilterGraph->AddFilter(pFileWriterBaseFilter, CT2CW(_T("File Writer"))));
505                __C(GenericFilterGraph->Connect(pCurrentOutputPin, _FilterGraphHelper::GetFilterPin(pFileWriterBaseFilter, PINDIR_INPUT)));
506                pCurrentOutputPin.Release();
507                #pragma endregion
508                _A(!pCurrentOutputPin);
509                _A(GenericFilterGraph.m_pMediaFilter);
510                __C(GenericFilterGraph.m_pMediaFilter->SetSyncSource(NULL));
511                #pragma endregion
512                _tprintf(_T("Running...\n"));
513                _A(GenericFilterGraph.m_pMediaControl);
514                __C(GenericFilterGraph.m_pMediaControl->Run());
515                GenericFilterGraph.SetShowDestructorMessageBox(FALSE);
516                _A(GenericFilterGraph.m_pMediaEventEx);
517                LONG nEventCode;
518                __C(GenericFilterGraph.m_pMediaEventEx->WaitForCompletion(INFINITE, &nEventCode));
519                _tprintf(_T("Complete, nEventCode 0x%02X\n"), nEventCode);
520                __C(GenericFilterGraph.m_pMediaControl->Stop());
521        }
522};
523
524////////////////////////////////////////////////////////////
525// Main
526
527int _tmain(int argc, _TCHAR* argv[])
528{
529        _ATLTRY
530        {
531                CModule Module;
532                #pragma region Parse Command Line
533                for(INT nIndex = 1; nIndex < argc; nIndex++)
534                {
535                        CString sArgument = argv[nIndex];
536                        _A(!sArgument.IsEmpty());
537                        #pragma region Switches
538                        if(_tcschr(_T("-/"), sArgument[0]))
539                        {
540                                sArgument.Delete(0);
541                                #pragma region Switch Value/Specification
542                                CString sArgumentValue;
543                                if(sArgument.GetLength() > 1)
544                                {
545                                        SIZE_T nIndex = 1;
546                                        if(sArgument[1] == _T(':'))
547                                                nIndex++;
548                                        sArgumentValue = (LPCTSTR) sArgument + nIndex;
549                                }
550                                INT nIntegerArgumentValue = 0;
551                                const BOOL bIntegerArgumentValueValid = !sArgumentValue.IsEmpty() ? AtlStringToInteger(sArgumentValue, nIntegerArgumentValue) : FALSE;
552                                #pragma endregion
553                                if(_tcschr(_T("Ss"), sArgument[0])) // Sample Rate
554                                {
555                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
556                                        //_tprintf(_T("Option: Sample Rate, %d\n"), nIntegerArgumentValue);
557                                        Module.SetSampleRate(nIntegerArgumentValue);
558                                } else
559                                if(_tcschr(_T("Cc"), sArgument[0])) // Channel Count
560                                {
561                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
562                                        //_tprintf(_T("Option: Channel Count, %d\n"), nIntegerArgumentValue);
563                                        Module.SetChannelCount(nIntegerArgumentValue);
564                                } else
565                                if(_tcschr(_T("Bb"), sArgument[0])) // Sample Bit Count
566                                {
567                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
568                                        //_tprintf(_T("Option: Sample Bit Count, %d\n"), nIntegerArgumentValue);
569                                        Module.SetSampleBitCount(nIntegerArgumentValue);
570                                } else
571                                if(_tcschr(_T("Tt"), sArgument[0])) // Length, seconds
572                                {
573                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
574                                        //_tprintf(_T("Option: Length, %d\n"), nIntegerArgumentValue);
575                                        Module.SetLength(nIntegerArgumentValue * 1000 * 10000i64);
576                                } else
577                                if(_tcschr(_T("Ff"), sArgument[0])) // Sine Signal Frequency, Hz
578                                {
579                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
580                                        //_tprintf(_T("Option: Sine Signal Frequency, %d\n"), nIntegerArgumentValue);
581                                        Module.SetSignalFrequency(nIntegerArgumentValue);
582                                } else
583                                if(_tcschr(_T("Ll"), sArgument[0])) // Sine Signal Loudness, dB below FS
584                                {
585                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
586                                        //_tprintf(_T("Option: Sine Signal Loudness, %d\n"), nIntegerArgumentValue);
587                                        Module.SetSignalLoudness(nIntegerArgumentValue);
588                                } else
589                                if(_tcschr(_T("Nn"), sArgument[0])) // Noise Signal Loudness, dB below FS
590                                {
591                                        __D(bIntegerArgumentValueValid, E_INVALIDARG);
592                                        //_tprintf(_T("Option: Noise Signal Loudness, %d\n"), nIntegerArgumentValue);
593                                        Module.SetNoiseLoudness(nIntegerArgumentValue);
594                                }
595                                continue;
596                        }
597                        #pragma endregion
598                        if(sArgument.GetLength() >= 2 && sArgument[0] == _T('"') && sArgument[sArgument.GetLength() - 1] == _T('"'))
599                                sArgument = sArgument.Mid(1, sArgument.GetLength() - 2);
600                        Module.SetPath(sArgument);
601                }
602                #pragma endregion
603                Module.WinMain(SW_SHOWNORMAL);
604        }
605        _ATLCATCH(Exception)
606        {
607                if(FAILED((HRESULT) Exception))
608                        _tprintf(_T("Error 0x%08x: %s\n"), (HRESULT) Exception, AtlFormatSystemMessage(Exception).TrimRight(_T("\t\n\r .")));
609                return (INT) (HRESULT) Exception;
610        }
611        _ATLCATCHALL()
612        {
613                _tprintf(_T("Fatal Error\n"));
614                return (INT) E_FAIL;
615        }
616        return 0;
617}
Note: See TracBrowser for help on using the repository browser.