├── .editorconfig
├── .gitignore
├── .gitmodules
├── IGuidedReclock.h
├── LICENSE
├── README.md
├── TODO.txt
├── changelog.txt
├── dll
├── base.props
├── platform.props
├── sanear-dll.sln
├── sanear-platform.props
├── sanear.props
├── skel
│ ├── register.bat
│ └── unregister.bat
└── src
│ ├── baseclasses.vcxproj
│ ├── baseclasses
│ ├── amextra.cpp
│ ├── amextra.h
│ ├── amfilter.cpp
│ ├── amfilter.h
│ ├── amvideo.cpp
│ ├── arithutil.cpp
│ ├── cache.h
│ ├── checkbmi.h
│ ├── combase.cpp
│ ├── combase.h
│ ├── cprop.cpp
│ ├── cprop.h
│ ├── ctlutil.cpp
│ ├── ctlutil.h
│ ├── ddmm.cpp
│ ├── ddmm.h
│ ├── dllentry.cpp
│ ├── dllsetup.cpp
│ ├── dllsetup.h
│ ├── dxmperf.h
│ ├── fourcc.h
│ ├── measure.h
│ ├── msgthrd.h
│ ├── mtype.cpp
│ ├── mtype.h
│ ├── outputq.cpp
│ ├── outputq.h
│ ├── perflog.cpp
│ ├── perflog.h
│ ├── perfstruct.h
│ ├── pstream.cpp
│ ├── pstream.h
│ ├── pullpin.cpp
│ ├── pullpin.h
│ ├── refclock.cpp
│ ├── refclock.h
│ ├── reftime.h
│ ├── renbase.cpp
│ ├── renbase.h
│ ├── schedule.cpp
│ ├── schedule.h
│ ├── seekpt.cpp
│ ├── seekpt.h
│ ├── source.cpp
│ ├── source.h
│ ├── streams.cpp
│ ├── streams.h
│ ├── strmctl.cpp
│ ├── strmctl.h
│ ├── sysclock.cpp
│ ├── sysclock.h
│ ├── transfrm.cpp
│ ├── transfrm.h
│ ├── transip.cpp
│ ├── transip.h
│ ├── videoctl.cpp
│ ├── videoctl.h
│ ├── vtrans.cpp
│ ├── vtrans.h
│ ├── winctrl.cpp
│ ├── winctrl.h
│ ├── winutil.cpp
│ ├── winutil.h
│ ├── wxdebug.cpp
│ ├── wxdebug.h
│ ├── wxlist.cpp
│ ├── wxlist.h
│ ├── wxutil.cpp
│ └── wxutil.h
│ ├── bs2b.vcxproj
│ ├── fftw-config
│ └── config.h
│ ├── fftw.vcxproj
│ ├── fftw.vcxproj.filters
│ ├── rubberband.vcxproj
│ ├── rubberband.vcxproj.filters
│ ├── sanear-dll.vcxproj
│ ├── sanear-dll.vcxproj.filters
│ ├── sanear-dll
│ ├── Entry.cpp
│ ├── OuterFilter.cpp
│ ├── OuterFilter.h
│ ├── RegistryKey.cpp
│ ├── RegistryKey.h
│ ├── TrayWindow.cpp
│ ├── TrayWindow.h
│ ├── pch.cpp
│ ├── pch.h
│ ├── resource.h
│ ├── sanear.def
│ ├── sanear.ico
│ ├── sanear.rc
│ └── sanear.svg
│ ├── snprintf.h
│ ├── soundtouch.vcxproj
│ ├── soxr-config.h
│ └── soxr.vcxproj
├── sanear.vcxproj
├── sanear.vcxproj.filters
└── src
├── AudioDevice.h
├── AudioDeviceEvent.cpp
├── AudioDeviceEvent.h
├── AudioDeviceManager.cpp
├── AudioDeviceManager.h
├── AudioDevicePush.cpp
├── AudioDevicePush.h
├── AudioRenderer.cpp
├── AudioRenderer.h
├── DspBalance.cpp
├── DspBalance.h
├── DspBase.h
├── DspChunk.cpp
├── DspChunk.h
├── DspCrossfeed.cpp
├── DspCrossfeed.h
├── DspDither.cpp
├── DspDither.h
├── DspFormat.h
├── DspLimiter.cpp
├── DspLimiter.h
├── DspMatrix.cpp
├── DspMatrix.h
├── DspRate.cpp
├── DspRate.h
├── DspTempo.cpp
├── DspTempo.h
├── DspTempo2.cpp
├── DspTempo2.h
├── DspVolume.cpp
├── DspVolume.h
├── Factory.cpp
├── Factory.h
├── Interfaces.h
├── MyBasicAudio.cpp
├── MyBasicAudio.h
├── MyClock.cpp
├── MyClock.h
├── MyFilter.cpp
├── MyFilter.h
├── MyPin.cpp
├── MyPin.h
├── MyPropertyPage.cpp
├── MyPropertyPage.h
├── MyTestClock.cpp
├── MyTestClock.h
├── SampleCorrection.cpp
├── SampleCorrection.h
├── Settings.cpp
├── Settings.h
├── Utils.h
├── pch.cpp
└── pch.h
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*.{cpp,h}]
4 | end_of_line = crlf
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 4
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /dll/bin
2 | /dll/ipch
3 | *.sdf
4 | *.opensdf
5 | *.suo
6 | *.vcxproj.user
7 | *.aps
8 | *.vspx
9 | *.opendb
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libbs2b"]
2 | path = dll/src/libbs2b
3 | url = git://github.com/alexmarsev/libbs2b.git
4 | [submodule "soxr"]
5 | path = dll/src/soxr
6 | url = git://github.com/alexmarsev/soxr.git
7 | [submodule "soundtouch"]
8 | path = dll/src/soundtouch
9 | url = git://github.com/alexmarsev/soundtouch.git
10 | [submodule "rubberband"]
11 | path = dll/src/rubberband
12 | url = git://github.com/breakfastquay/rubberband.git
13 | [submodule "fftw"]
14 | path = dll/src/fftw
15 | url = git://github.com/alexmarsev/fftw3.git
16 | branch = codelets-3.3.4
17 |
--------------------------------------------------------------------------------
/IGuidedReclock.h:
--------------------------------------------------------------------------------
1 | // This file is released under CC0 1.0 license
2 | // License text can be found at http://creativecommons.org/publicdomain/zero/1.0/
3 |
4 | // Originally designed as part of sanear project
5 |
6 | #pragma once
7 |
8 | struct __declspec(uuid("243F1282-94C3-46A1-B3F6-72B400786FEC"))
9 | IGuidedReclock : IUnknown
10 | {
11 | STDMETHOD(SlaveClock)(DOUBLE multiplier) = 0;
12 | STDMETHOD(UnslaveClock)() = 0;
13 |
14 | STDMETHOD(OffsetClock)(LONGLONG offset) = 0;
15 |
16 | STDMETHOD(GetImmediateTime)(LONGLONG* pTime) = 0;
17 | };
18 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Sanear
2 |
3 | ### What is it?
4 | Open-source DirectShow audio renderer. With WASAPI support and more.
5 |
6 | ### Binary releases
7 | Can be found here https://github.com/alexmarsev/sanear/releases
8 |
9 | ### Compilation instructions
10 | If you want to partake in the development or simply feeling adventurous:
11 |
12 | 1. Have recent `Visual Studio` installed (free versions like `Visual Studio Community 2013 Update 5` or `Visual Studio Community 2015 Update 1` work just fine)
13 | 2. Check out `master` branch of sanear
14 | 3. Ensure that all submodules are up-to-date by running `git submodule update --init --recursive` from inside the tree
15 | 4. Open `sanear-dll.sln` solution file and build
16 |
--------------------------------------------------------------------------------
/TODO.txt:
--------------------------------------------------------------------------------
1 | - design and implement "guided reclock" interface
2 | - don't recreate the device when media type changes during playback and the old one can be used
3 | - override advise portion of IReferenceClock interface
4 | - add "excessive precision processing" option
5 | - play silence during pause in exclusive mode (for ati hdmi)
6 |
--------------------------------------------------------------------------------
/changelog.txt:
--------------------------------------------------------------------------------
1 | Sanear, a robust DirectShow audio renderer
2 | ==========================================
3 |
4 | v0.3 - 2015/08/08
5 | * Bugfixing release
6 | * Improves status page compatibility with certain players
7 |
8 | v0.2 - 2015/08/02
9 | * Bugfixing release
10 | * Fixes audible noise in dithering
11 |
12 | v0.1 - 2015/07/22
13 | * Initial release
14 | * Outputs sound through WASAPI (shared or exclusive)
15 | * Employs automatic channel downmixing (as per standard)
16 | * Provides stereo crossfeed processing option (for headphones)
17 | * Tries to preserve signal pitch when playing at custom rate (time stretching)
18 | * Uses audio device clock as clock source
19 | * Comes in 32-bit and 64-bit versions
20 | * Supports bitstreaming
21 |
--------------------------------------------------------------------------------
/dll/base.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\obj\
5 | $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\
6 | $(SolutionDir)bin\$(Configuration)$(PlatformArchitecture)\obj\$(ProjectName)\
7 |
8 |
9 |
10 | true
11 |
12 |
13 |
14 |
15 | MultiThreadedDebug
16 |
17 |
18 |
19 |
20 | MultiThreaded
21 | NDEBUG;%(PreprocessorDefinitions)
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/dll/platform.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | v140
5 |
6 |
7 | v120
8 |
9 |
10 |
--------------------------------------------------------------------------------
/dll/sanear-platform.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/dll/sanear.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | SANEAR_GPL_PHASE_VOCODER;%(PreprocessorDefinitions)
7 | $(SolutionDir)src\baseclasses;$(SolutionDir)src\soxr\src;$(SolutionDir)src\libbs2b\src;$(SolutionDir)src\soundtouch\include;$(SolutionDir)src\zita-resampler\libs;$(SolutionDir)src\rubberband\rubberband;%(AdditionalIncludeDirectories)
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/dll/skel/register.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd /d "%~dp0"
3 |
4 | regsvr32.exe sanear.ax /s
5 | if %ERRORLEVEL% neq 0 goto fail
6 |
7 | if "%PROCESSOR_ARCHITECTURE%" == "x86" goto ok
8 | regsvr32.exe sanear64.ax /s
9 | if %ERRORLEVEL% neq 0 goto fail
10 |
11 | :ok
12 | echo.
13 | echo Registration succeeded
14 | echo.
15 | goto done
16 |
17 | :fail
18 | echo.
19 | echo Registration failed!
20 | echo.
21 | echo Try to right-click on %~nx0 and select "Run as administrator"
22 | echo.
23 |
24 | :done
25 | pause >nul
26 |
--------------------------------------------------------------------------------
/dll/skel/unregister.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | cd /d "%~dp0"
3 |
4 | regsvr32.exe /u sanear.ax /s
5 | if %ERRORLEVEL% neq 0 goto fail
6 |
7 | if "%PROCESSOR_ARCHITECTURE%" == "x86" goto ok
8 | regsvr32.exe /u sanear64.ax /s
9 | if %ERRORLEVEL% neq 0 goto fail
10 |
11 | :ok
12 | echo.
13 | echo Unregistration succeeded
14 | echo.
15 | goto done
16 |
17 | :fail
18 | echo.
19 | echo Unregistration failed!
20 | echo.
21 | echo Try to right-click on %~nx0 and select "Run as administrator"
22 | echo.
23 |
24 | :done
25 | pause >nul
26 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/amextra.cpp:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: AMExtra.cpp
3 | //
4 | // Desc: DirectShow base classes - implements CRenderedInputPin class.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #include // DirectShow base class definitions
11 | #include // Needed for definition of timeGetTime
12 | #include // Standard data type limit definitions
13 | #include // Used for time critical log functions
14 |
15 | #include "amextra.h"
16 |
17 | #pragma warning(disable:4355)
18 |
19 | // Implements CRenderedInputPin class
20 |
21 | CRenderedInputPin::CRenderedInputPin(__in_opt LPCTSTR pObjectName,
22 | __in CBaseFilter *pFilter,
23 | __in CCritSec *pLock,
24 | __inout HRESULT *phr,
25 | __in_opt LPCWSTR pName) :
26 | CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
27 | m_bAtEndOfStream(FALSE),
28 | m_bCompleteNotified(FALSE)
29 | {
30 | }
31 | #ifdef UNICODE
32 | CRenderedInputPin::CRenderedInputPin(__in_opt LPCSTR pObjectName,
33 | __in CBaseFilter *pFilter,
34 | __in CCritSec *pLock,
35 | __inout HRESULT *phr,
36 | __in_opt LPCWSTR pName) :
37 | CBaseInputPin(pObjectName, pFilter, pLock, phr, pName),
38 | m_bAtEndOfStream(FALSE),
39 | m_bCompleteNotified(FALSE)
40 | {
41 | }
42 | #endif
43 |
44 | // Flush end of stream condition - caller should do any
45 | // necessary stream level locking before calling this
46 |
47 | STDMETHODIMP CRenderedInputPin::EndOfStream()
48 | {
49 | HRESULT hr = CheckStreaming();
50 |
51 | // Do EC_COMPLETE handling for rendered pins
52 | if (S_OK == hr && !m_bAtEndOfStream) {
53 | m_bAtEndOfStream = TRUE;
54 | FILTER_STATE fs;
55 | EXECUTE_ASSERT(SUCCEEDED(m_pFilter->GetState(0, &fs)));
56 | if (fs == State_Running) {
57 | DoCompleteHandling();
58 | }
59 | }
60 | return hr;
61 | }
62 |
63 |
64 | // Called to complete the flush
65 |
66 | STDMETHODIMP CRenderedInputPin::EndFlush()
67 | {
68 | CAutoLock lck(m_pLock);
69 |
70 | // Clean up renderer state
71 | m_bAtEndOfStream = FALSE;
72 | m_bCompleteNotified = FALSE;
73 |
74 | return CBaseInputPin::EndFlush();
75 | }
76 |
77 |
78 | // Notify of Run() from filter
79 |
80 | HRESULT CRenderedInputPin::Run(REFERENCE_TIME tStart)
81 | {
82 | UNREFERENCED_PARAMETER(tStart);
83 | m_bCompleteNotified = FALSE;
84 | if (m_bAtEndOfStream) {
85 | DoCompleteHandling();
86 | }
87 | return S_OK;
88 | }
89 |
90 |
91 | // Clear status on going into paused state
92 |
93 | HRESULT CRenderedInputPin::Active()
94 | {
95 | m_bAtEndOfStream = FALSE;
96 | m_bCompleteNotified = FALSE;
97 | return CBaseInputPin::Active();
98 | }
99 |
100 |
101 | // Do stuff to deliver end of stream
102 |
103 | void CRenderedInputPin::DoCompleteHandling()
104 | {
105 | ASSERT(m_bAtEndOfStream);
106 | if (!m_bCompleteNotified) {
107 | m_bCompleteNotified = TRUE;
108 | m_pFilter->NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)m_pFilter);
109 | }
110 | }
111 |
112 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/amextra.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: AMExtra.h
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #ifndef __AMEXTRA__
11 | #define __AMEXTRA__
12 |
13 | // Simple rendered input pin
14 | //
15 | // NOTE if your filter queues stuff before rendering then it may not be
16 | // appropriate to use this class
17 | //
18 | // In that case queue the end of stream condition until the last sample
19 | // is actually rendered and flush the condition appropriately
20 |
21 | class CRenderedInputPin : public CBaseInputPin
22 | {
23 | public:
24 |
25 | CRenderedInputPin(__in_opt LPCTSTR pObjectName,
26 | __in CBaseFilter *pFilter,
27 | __in CCritSec *pLock,
28 | __inout HRESULT *phr,
29 | __in_opt LPCWSTR pName);
30 | #ifdef UNICODE
31 | CRenderedInputPin(__in_opt LPCSTR pObjectName,
32 | __in CBaseFilter *pFilter,
33 | __in CCritSec *pLock,
34 | __inout HRESULT *phr,
35 | __in_opt LPCWSTR pName);
36 | #endif
37 |
38 | // Override methods to track end of stream state
39 | STDMETHODIMP EndOfStream();
40 | STDMETHODIMP EndFlush();
41 |
42 | HRESULT Active();
43 | HRESULT Run(REFERENCE_TIME tStart);
44 |
45 | protected:
46 |
47 | // Member variables to track state
48 | BOOL m_bAtEndOfStream; // Set by EndOfStream
49 | BOOL m_bCompleteNotified; // Set when we notify for EC_COMPLETE
50 |
51 | private:
52 | void DoCompleteHandling();
53 | };
54 |
55 | #endif // __AMEXTRA__
56 |
57 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/cache.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: Cache.h
3 | //
4 | // Desc: DirectShow base classes - efines a non-MFC generic cache class.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | /* This class implements a simple cache. A cache object is instantiated
11 | with the number of items it is to hold. An item is a pointer to an
12 | object derived from CBaseObject (helps reduce memory leaks). The cache
13 | can then have objects added to it and removed from it. The cache size
14 | is fixed at construction time and may therefore run out or be flooded.
15 | If it runs out it returns a NULL pointer, if it fills up it also returns
16 | a NULL pointer instead of a pointer to the object just inserted */
17 |
18 | /* Making these classes inherit from CBaseObject does nothing for their
19 | functionality but it allows us to check there are no memory leaks */
20 |
21 | /* WARNING Be very careful when using this class, what it lets you do is
22 | store and retrieve objects so that you can minimise object creation
23 | which in turns improves efficiency. However the object you store is
24 | exactly the same as the object you get back which means that it short
25 | circuits the constructor initialisation phase. This means any class
26 | variables the object has (eg pointers) are highly likely to be invalid.
27 | Therefore ensure you reinitialise the object before using it again */
28 |
29 |
30 | #ifndef __CACHE__
31 | #define __CACHE__
32 |
33 |
34 | class CCache : CBaseObject {
35 |
36 | /* Make copy constructor and assignment operator inaccessible */
37 |
38 | CCache(const CCache &refCache);
39 | CCache &operator=(const CCache &refCache);
40 |
41 | private:
42 |
43 | /* These are initialised in the constructor. The first variable points to
44 | an array of pointers, each of which points to a CBaseObject derived
45 | object. The m_iCacheSize is the static fixed size for the cache and the
46 | m_iUsed defines the number of places filled with objects at any time.
47 | We fill the array of pointers from the start (ie m_ppObjects[0] first)
48 | and then only add and remove objects from the end position, so in this
49 | respect the array of object pointers should be treated as a stack */
50 |
51 | CBaseObject **m_ppObjects;
52 | const INT m_iCacheSize;
53 | INT m_iUsed;
54 |
55 | public:
56 |
57 | CCache(__in_opt LPCTSTR pName,INT iItems);
58 | virtual ~CCache();
59 |
60 | /* Add an item to the cache */
61 | CBaseObject *AddToCache(__in CBaseObject *pObject);
62 |
63 | /* Remove an item from the cache */
64 | CBaseObject *RemoveFromCache();
65 |
66 | /* Delete all the objects held in the cache */
67 | void RemoveAll(void);
68 |
69 | /* Return the cache size which is set during construction */
70 | INT GetCacheSize(void) const {return m_iCacheSize;};
71 | };
72 |
73 | #endif /* __CACHE__ */
74 |
75 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/checkbmi.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 1992 - 1997 Microsoft Corporation. All Rights Reserved.
2 |
3 | #ifndef _CHECKBMI_H_
4 | #define _CHECKBMI_H_
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | // Helper
11 | __inline BOOL MultiplyCheckOverflow(DWORD a, DWORD b, __deref_out_range(==, a * b) DWORD *pab) {
12 | *pab = a * b;
13 | if ((a == 0) || (((*pab) / a) == b)) {
14 | return TRUE;
15 | }
16 | return FALSE;
17 | }
18 |
19 |
20 | // Checks if the fields in a BITMAPINFOHEADER won't generate
21 | // overlows and buffer overruns
22 | // This is not a complete check and does not guarantee code using this structure will be secure
23 | // from attack
24 | // Bugs this is guarding against:
25 | // 1. Total structure size calculation overflowing
26 | // 2. biClrUsed > 256 for 8-bit palettized content
27 | // 3. Total bitmap size in bytes overflowing
28 | // 4. biSize < size of the base structure leading to accessessing random memory
29 | // 5. Total structure size exceeding know size of data
30 | //
31 |
32 | __success(return != 0) __inline BOOL ValidateBitmapInfoHeader(
33 | const BITMAPINFOHEADER *pbmi, // pointer to structure to check
34 | __out_range(>=, sizeof(BITMAPINFOHEADER)) DWORD cbSize // size of memory block containing structure
35 | )
36 | {
37 | DWORD dwWidthInBytes;
38 | DWORD dwBpp;
39 | DWORD dwWidthInBits;
40 | DWORD dwHeight;
41 | DWORD dwSizeImage;
42 | DWORD dwClrUsed;
43 |
44 | // Reject bad parameters - do the size check first to avoid reading bad memory
45 | if (cbSize < sizeof(BITMAPINFOHEADER) ||
46 | pbmi->biSize < sizeof(BITMAPINFOHEADER) ||
47 | pbmi->biSize > 4096) {
48 | return FALSE;
49 | }
50 |
51 | // Reject 0 size
52 | if (pbmi->biWidth == 0 || pbmi->biHeight == 0) {
53 | return FALSE;
54 | }
55 |
56 | // Use bpp of 200 for validating against further overflows if not set for compressed format
57 | dwBpp = 200;
58 |
59 | if (pbmi->biBitCount > dwBpp) {
60 | return FALSE;
61 | }
62 |
63 | // Strictly speaking abs can overflow so cast explicitly to DWORD
64 | dwHeight = (DWORD)abs(pbmi->biHeight);
65 |
66 | if (!MultiplyCheckOverflow(dwBpp, (DWORD)pbmi->biWidth, &dwWidthInBits)) {
67 | return FALSE;
68 | }
69 |
70 | // Compute correct width in bytes - rounding up to 4 bytes
71 | dwWidthInBytes = (dwWidthInBits / 8 + 3) & ~3;
72 |
73 | if (!MultiplyCheckOverflow(dwWidthInBytes, dwHeight, &dwSizeImage)) {
74 | return FALSE;
75 | }
76 |
77 | // Fail if total size is 0 - this catches indivual quantities being 0
78 | // Also don't allow huge values > 1GB which might cause arithmetic
79 | // errors for users
80 | if (dwSizeImage > 0x40000000 ||
81 | pbmi->biSizeImage > 0x40000000) {
82 | return FALSE;
83 | }
84 |
85 | // Fail if biClrUsed looks bad
86 | if (pbmi->biClrUsed > 256) {
87 | return FALSE;
88 | }
89 |
90 | if (pbmi->biClrUsed == 0 && pbmi->biBitCount <= 8 && pbmi->biBitCount > 0) {
91 | dwClrUsed = (1 << pbmi->biBitCount);
92 | } else {
93 | dwClrUsed = pbmi->biClrUsed;
94 | }
95 |
96 | // Check total size
97 | if (cbSize < pbmi->biSize + dwClrUsed * sizeof(RGBQUAD) +
98 | (pbmi->biCompression == BI_BITFIELDS ? 3 * sizeof(DWORD) : 0)) {
99 | return FALSE;
100 | }
101 |
102 | // If it is RGB validate biSizeImage - lots of code assumes the size is correct
103 | if (pbmi->biCompression == BI_RGB || pbmi->biCompression == BI_BITFIELDS) {
104 | if (pbmi->biSizeImage != 0) {
105 | DWORD dwBits = (DWORD)pbmi->biWidth * (DWORD)pbmi->biBitCount;
106 | DWORD dwWidthInBytes = ((DWORD)((dwBits+31) & (~31)) / 8);
107 | DWORD dwTotalSize = (DWORD)abs(pbmi->biHeight) * dwWidthInBytes;
108 | if (dwTotalSize > pbmi->biSizeImage) {
109 | return FALSE;
110 | }
111 | }
112 | }
113 | return TRUE;
114 | }
115 |
116 | #ifdef __cplusplus
117 | }
118 | #endif
119 |
120 | #endif // _CHECKBMI_H_
121 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/cprop.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: CProp.h
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #ifndef __CPROP__
11 | #define __CPROP__
12 |
13 | // Base property page class. Filters typically expose custom properties by
14 | // implementing special control interfaces, examples are IDirectDrawVideo
15 | // and IQualProp on renderers. This allows property pages to be built that
16 | // use the given interface. Applications such as the ActiveMovie OCX query
17 | // filters for the property pages they support and expose them to the user
18 | //
19 | // This class provides all the framework for a property page. A property
20 | // page is a COM object that supports IPropertyPage. We should be created
21 | // with a resource ID for the dialog which we will load when required. We
22 | // should also be given in the constructor a resource ID for a title string
23 | // we will load from the DLLs STRINGTABLE. The property page titles must be
24 | // stored in resource files so that they can be easily internationalised
25 | //
26 | // We have a number of virtual methods (not PURE) that may be overriden in
27 | // derived classes to query for interfaces and so on. These functions have
28 | // simple implementations here that just return NOERROR. Derived classes
29 | // will almost definately have to override the message handler method called
30 | // OnReceiveMessage. We have a static dialog procedure that calls the method
31 | // so that derived classes don't have to fiddle around with the this pointer
32 |
33 | class AM_NOVTABLE CBasePropertyPage : public IPropertyPage, public CUnknown
34 | {
35 | protected:
36 |
37 | LPPROPERTYPAGESITE m_pPageSite; // Details for our property site
38 | HWND m_hwnd; // Window handle for the page
39 | HWND m_Dlg; // Actual dialog window handle
40 | BOOL m_bDirty; // Has anything been changed
41 | int m_TitleId; // Resource identifier for title
42 | int m_DialogId; // Dialog resource identifier
43 |
44 | static INT_PTR CALLBACK DialogProc(HWND hwnd,
45 | UINT uMsg,
46 | WPARAM wParam,
47 | LPARAM lParam);
48 |
49 | private:
50 | BOOL m_bObjectSet ; // SetObject has been called or not.
51 | public:
52 |
53 | CBasePropertyPage(__in_opt LPCTSTR pName, // Debug only name
54 | __inout_opt LPUNKNOWN pUnk, // COM Delegator
55 | int DialogId, // Resource ID
56 | int TitleId); // To get tital
57 |
58 | #ifdef UNICODE
59 | CBasePropertyPage(__in_opt LPCSTR pName,
60 | __inout_opt LPUNKNOWN pUnk,
61 | int DialogId,
62 | int TitleId);
63 | #endif
64 | virtual ~CBasePropertyPage() { };
65 | DECLARE_IUNKNOWN
66 |
67 | // Override these virtual methods
68 |
69 | virtual HRESULT OnConnect(IUnknown *pUnknown) { return NOERROR; };
70 | virtual HRESULT OnDisconnect() { return NOERROR; };
71 | virtual HRESULT OnActivate() { return NOERROR; };
72 | virtual HRESULT OnDeactivate() { return NOERROR; };
73 | virtual HRESULT OnApplyChanges() { return NOERROR; };
74 | virtual INT_PTR OnReceiveMessage(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
75 |
76 | // These implement an IPropertyPage interface
77 |
78 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv);
79 | STDMETHODIMP_(ULONG) NonDelegatingRelease();
80 | STDMETHODIMP_(ULONG) NonDelegatingAddRef();
81 | STDMETHODIMP SetPageSite(__in_opt LPPROPERTYPAGESITE pPageSite);
82 | STDMETHODIMP Activate(HWND hwndParent, LPCRECT prect,BOOL fModal);
83 | STDMETHODIMP Deactivate(void);
84 | STDMETHODIMP GetPageInfo(__out LPPROPPAGEINFO pPageInfo);
85 | STDMETHODIMP SetObjects(ULONG cObjects, __in_ecount_opt(cObjects) LPUNKNOWN *ppUnk);
86 | STDMETHODIMP Show(UINT nCmdShow);
87 | STDMETHODIMP Move(LPCRECT prect);
88 | STDMETHODIMP IsPageDirty(void) { return m_bDirty ? S_OK : S_FALSE; }
89 | STDMETHODIMP Apply(void);
90 | STDMETHODIMP Help(LPCWSTR lpszHelpDir) { return E_NOTIMPL; }
91 | STDMETHODIMP TranslateAccelerator(__inout LPMSG lpMsg) { return E_NOTIMPL; }
92 | };
93 |
94 | #endif // __CPROP__
95 |
96 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/ddmm.cpp:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: DDMM.cpp
3 | //
4 | // Desc: DirectShow base classes - implements routines for using DirectDraw
5 | // on a multimonitor system.
6 | //
7 | // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | #include
12 | #include
13 | #include "ddmm.h"
14 |
15 | /*
16 | * FindDeviceCallback
17 | */
18 | typedef struct {
19 | LPSTR szDevice;
20 | GUID* lpGUID;
21 | GUID GUID;
22 | BOOL fFound;
23 | } FindDeviceData;
24 |
25 | BOOL CALLBACK FindDeviceCallback(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam)
26 | {
27 | FindDeviceData *p = (FindDeviceData*)lParam;
28 |
29 | if (lstrcmpiA(p->szDevice, szDevice) == 0) {
30 | if (lpGUID) {
31 | p->GUID = *lpGUID;
32 | p->lpGUID = &p->GUID;
33 | } else {
34 | p->lpGUID = NULL;
35 | }
36 | p->fFound = TRUE;
37 | return FALSE;
38 | }
39 | return TRUE;
40 | }
41 |
42 |
43 | BOOL CALLBACK FindDeviceCallbackEx(__in_opt GUID* lpGUID, __in LPSTR szName, __in LPSTR szDevice, __in LPVOID lParam, HMONITOR hMonitor)
44 | {
45 | FindDeviceData *p = (FindDeviceData*)lParam;
46 |
47 | if (lstrcmpiA(p->szDevice, szDevice) == 0) {
48 | if (lpGUID) {
49 | p->GUID = *lpGUID;
50 | p->lpGUID = &p->GUID;
51 | } else {
52 | p->lpGUID = NULL;
53 | }
54 | p->fFound = TRUE;
55 | return FALSE;
56 | }
57 | return TRUE;
58 | }
59 |
60 |
61 | /*
62 | * DirectDrawCreateFromDevice
63 | *
64 | * create a DirectDraw object for a particular device
65 | */
66 | IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, PDRAWENUM DirectDrawEnumerateP)
67 | {
68 | IDirectDraw* pdd = NULL;
69 | FindDeviceData find;
70 |
71 | if (szDevice == NULL) {
72 | DirectDrawCreateP(NULL, &pdd, NULL);
73 | return pdd;
74 | }
75 |
76 | find.szDevice = szDevice;
77 | find.fFound = FALSE;
78 | DirectDrawEnumerateP(FindDeviceCallback, (LPVOID)&find);
79 |
80 | if (find.fFound)
81 | {
82 | //
83 | // In 4bpp mode the following DDraw call causes a message box to be popped
84 | // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
85 | // make sure it doesn't happen.
86 | //
87 | UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
88 | DirectDrawCreateP(find.lpGUID, &pdd, NULL);
89 | SetErrorMode(ErrorMode);
90 | }
91 |
92 | return pdd;
93 | }
94 |
95 |
96 | /*
97 | * DirectDrawCreateFromDeviceEx
98 | *
99 | * create a DirectDraw object for a particular device
100 | */
101 | IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR szDevice, PDRAWCREATE DirectDrawCreateP, LPDIRECTDRAWENUMERATEEXA DirectDrawEnumerateExP)
102 | {
103 | IDirectDraw* pdd = NULL;
104 | FindDeviceData find;
105 |
106 | if (szDevice == NULL) {
107 | DirectDrawCreateP(NULL, &pdd, NULL);
108 | return pdd;
109 | }
110 |
111 | find.szDevice = szDevice;
112 | find.fFound = FALSE;
113 | DirectDrawEnumerateExP(FindDeviceCallbackEx, (LPVOID)&find,
114 | DDENUM_ATTACHEDSECONDARYDEVICES);
115 |
116 | if (find.fFound)
117 | {
118 | //
119 | // In 4bpp mode the following DDraw call causes a message box to be popped
120 | // up by DDraw (!?!). It's DDraw's fault, but we don't like it. So we
121 | // make sure it doesn't happen.
122 | //
123 | UINT ErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
124 | DirectDrawCreateP(find.lpGUID, &pdd, NULL);
125 | SetErrorMode(ErrorMode);
126 | }
127 |
128 | return pdd;
129 | }
130 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/ddmm.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: DDMM.h
3 | //
4 | // Desc: DirectShow base classes - efines routines for using DirectDraw
5 | // on a multimonitor system.
6 | //
7 | // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | #ifdef __cplusplus
12 | extern "C" { /* Assume C declarations for C++ */
13 | #endif /* __cplusplus */
14 |
15 | // DDRAW.H might not include these
16 | #ifndef DDENUM_ATTACHEDSECONDARYDEVICES
17 | #define DDENUM_ATTACHEDSECONDARYDEVICES 0x00000001L
18 | #endif
19 |
20 | typedef HRESULT (*PDRAWCREATE)(IID *,LPDIRECTDRAW *,LPUNKNOWN);
21 | typedef HRESULT (*PDRAWENUM)(LPDDENUMCALLBACKA, LPVOID);
22 |
23 | IDirectDraw * DirectDrawCreateFromDevice(__in_opt LPSTR, PDRAWCREATE, PDRAWENUM);
24 | IDirectDraw * DirectDrawCreateFromDeviceEx(__in_opt LPSTR, PDRAWCREATE, LPDIRECTDRAWENUMERATEEXA);
25 |
26 | #ifdef __cplusplus
27 | }
28 | #endif /* __cplusplus */
29 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/dllsetup.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: DllSetup.h
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | // To be self registering, OLE servers must
11 | // export functions named DllRegisterServer
12 | // and DllUnregisterServer. To allow use of
13 | // custom and default implementations the
14 | // defaults are named AMovieDllRegisterServer
15 | // and AMovieDllUnregisterServer.
16 | //
17 | // To the use the default implementation you
18 | // must provide stub functions.
19 | //
20 | // i.e. STDAPI DllRegisterServer()
21 | // {
22 | // return AMovieDllRegisterServer();
23 | // }
24 | //
25 | // STDAPI DllUnregisterServer()
26 | // {
27 | // return AMovieDllUnregisterServer();
28 | // }
29 | //
30 | //
31 | // AMovieDllRegisterServer calls IAMovieSetup.Register(), and
32 | // AMovieDllUnregisterServer calls IAMovieSetup.Unregister().
33 |
34 | STDAPI AMovieDllRegisterServer2( BOOL );
35 | STDAPI AMovieDllRegisterServer();
36 | STDAPI AMovieDllUnregisterServer();
37 |
38 | // helper functions
39 | STDAPI EliminateSubKey( HKEY, LPCTSTR );
40 |
41 |
42 | STDAPI
43 | AMovieSetupRegisterFilter2( const AMOVIESETUP_FILTER * const psetupdata
44 | , IFilterMapper2 * pIFM2
45 | , BOOL bRegister );
46 |
47 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/fourcc.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: FourCC.h
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | // FOURCCMap
11 | //
12 | // provides a mapping between old-style multimedia format DWORDs
13 | // and new-style GUIDs.
14 | //
15 | // A range of 4 billion GUIDs has been allocated to ensure that this
16 | // mapping can be done straightforwardly one-to-one in both directions.
17 | //
18 | // January 95
19 |
20 |
21 | #ifndef __FOURCC__
22 | #define __FOURCC__
23 |
24 |
25 | // Multimedia format types are marked with DWORDs built from four 8-bit
26 | // chars and known as FOURCCs. New multimedia AM_MEDIA_TYPE definitions include
27 | // a subtype GUID. In order to simplify the mapping, GUIDs in the range:
28 | // XXXXXXXX-0000-0010-8000-00AA00389B71
29 | // are reserved for FOURCCs.
30 |
31 | class FOURCCMap : public GUID
32 | {
33 |
34 | public:
35 | FOURCCMap();
36 | FOURCCMap(DWORD Fourcc);
37 | FOURCCMap(const GUID *);
38 |
39 |
40 | DWORD GetFOURCC(void);
41 | void SetFOURCC(DWORD fourcc);
42 | void SetFOURCC(const GUID *);
43 |
44 | private:
45 | void InitGUID();
46 | };
47 |
48 | #define GUID_Data2 0
49 | #define GUID_Data3 0x10
50 | #define GUID_Data4_1 0xaa000080
51 | #define GUID_Data4_2 0x719b3800
52 |
53 | inline void
54 | FOURCCMap::InitGUID() {
55 | Data2 = GUID_Data2;
56 | Data3 = GUID_Data3;
57 | ((DWORD *)Data4)[0] = GUID_Data4_1;
58 | ((DWORD *)Data4)[1] = GUID_Data4_2;
59 | }
60 |
61 | inline
62 | FOURCCMap::FOURCCMap() {
63 | InitGUID();
64 | SetFOURCC( DWORD(0));
65 | }
66 |
67 | inline
68 | FOURCCMap::FOURCCMap(DWORD fourcc)
69 | {
70 | InitGUID();
71 | SetFOURCC(fourcc);
72 | }
73 |
74 | inline
75 | FOURCCMap::FOURCCMap(const GUID * pGuid)
76 | {
77 | InitGUID();
78 | SetFOURCC(pGuid);
79 | }
80 |
81 | inline void
82 | FOURCCMap::SetFOURCC(const GUID * pGuid)
83 | {
84 | FOURCCMap * p = (FOURCCMap*) pGuid;
85 | SetFOURCC(p->GetFOURCC());
86 | }
87 |
88 | inline void
89 | FOURCCMap::SetFOURCC(DWORD fourcc)
90 | {
91 | Data1 = fourcc;
92 | }
93 |
94 | inline DWORD
95 | FOURCCMap::GetFOURCC(void)
96 | {
97 | return Data1;
98 | }
99 |
100 | #endif /* __FOURCC__ */
101 |
102 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/msgthrd.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: MsgThrd.h
3 | //
4 | // Desc: DirectShow base classes - provides support for a worker thread
5 | // class to which one can asynchronously post messages.
6 | //
7 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | // Message class - really just a structure.
12 | //
13 | class CMsg {
14 | public:
15 | UINT uMsg;
16 | DWORD dwFlags;
17 | LPVOID lpParam;
18 | CAMEvent *pEvent;
19 |
20 | CMsg(UINT u, DWORD dw, __inout_opt LPVOID lp, __in_opt CAMEvent *pEvnt)
21 | : uMsg(u), dwFlags(dw), lpParam(lp), pEvent(pEvnt) {}
22 |
23 | CMsg()
24 | : uMsg(0), dwFlags(0L), lpParam(NULL), pEvent(NULL) {}
25 | };
26 |
27 | // This is the actual thread class. It exports all the usual thread control
28 | // functions. The created thread is different from a normal WIN32 thread in
29 | // that it is prompted to perform particaular tasks by responding to messages
30 | // posted to its message queue.
31 | //
32 | class AM_NOVTABLE CMsgThread {
33 | private:
34 | static DWORD WINAPI DefaultThreadProc(__inout LPVOID lpParam);
35 | DWORD m_ThreadId;
36 | HANDLE m_hThread;
37 |
38 | protected:
39 |
40 | // if you want to override GetThreadMsg to block on other things
41 | // as well as this queue, you need access to this
42 | CGenericList m_ThreadQueue;
43 | CCritSec m_Lock;
44 | HANDLE m_hSem;
45 | LONG m_lWaiting;
46 |
47 | public:
48 | CMsgThread()
49 | : m_ThreadId(0),
50 | m_hThread(NULL),
51 | m_lWaiting(0),
52 | m_hSem(NULL),
53 | // make a list with a cache of 5 items
54 | m_ThreadQueue(NAME("MsgThread list"), 5)
55 | {
56 | }
57 |
58 | ~CMsgThread();
59 | // override this if you want to block on other things as well
60 | // as the message loop
61 | void virtual GetThreadMsg(__out CMsg *msg);
62 |
63 | // override this if you want to do something on thread startup
64 | virtual void OnThreadInit() {
65 | };
66 |
67 | BOOL CreateThread();
68 |
69 | BOOL WaitForThreadExit(__out LPDWORD lpdwExitCode) {
70 | if (m_hThread != NULL) {
71 | WaitForSingleObject(m_hThread, INFINITE);
72 | return GetExitCodeThread(m_hThread, lpdwExitCode);
73 | }
74 | return FALSE;
75 | }
76 |
77 | DWORD ResumeThread() {
78 | return ::ResumeThread(m_hThread);
79 | }
80 |
81 | DWORD SuspendThread() {
82 | return ::SuspendThread(m_hThread);
83 | }
84 |
85 | int GetThreadPriority() {
86 | return ::GetThreadPriority(m_hThread);
87 | }
88 |
89 | BOOL SetThreadPriority(int nPriority) {
90 | return ::SetThreadPriority(m_hThread, nPriority);
91 | }
92 |
93 | HANDLE GetThreadHandle() {
94 | return m_hThread;
95 | }
96 |
97 | DWORD GetThreadId() {
98 | return m_ThreadId;
99 | }
100 |
101 |
102 | void PutThreadMsg(UINT uMsg, DWORD dwMsgFlags,
103 | __in_opt LPVOID lpMsgParam, __in_opt CAMEvent *pEvent = NULL) {
104 | CAutoLock lck(&m_Lock);
105 | CMsg* pMsg = new CMsg(uMsg, dwMsgFlags, lpMsgParam, pEvent);
106 | m_ThreadQueue.AddTail(pMsg);
107 | if (m_lWaiting != 0) {
108 | ReleaseSemaphore(m_hSem, m_lWaiting, 0);
109 | m_lWaiting = 0;
110 | }
111 | }
112 |
113 | // This is the function prototype of the function that the client
114 | // supplies. It is always called on the created thread, never on
115 | // the creator thread.
116 | //
117 | virtual LRESULT ThreadMessageProc(
118 | UINT uMsg, DWORD dwFlags, __inout_opt LPVOID lpParam, __in_opt CAMEvent *pEvent) = 0;
119 | };
120 |
121 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/mtype.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: MtType.h
3 | //
4 | // Desc: DirectShow base classes - defines a class that holds and manages
5 | // media type information.
6 | //
7 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | #ifndef __MTYPE__
12 | #define __MTYPE__
13 |
14 | /* Helper class that derived pin objects can use to compare media
15 | types etc. Has same data members as the struct AM_MEDIA_TYPE defined
16 | in the streams IDL file, but also has (non-virtual) functions */
17 |
18 | class CMediaType : public _AMMediaType {
19 |
20 | public:
21 |
22 | ~CMediaType();
23 | CMediaType();
24 | CMediaType(const GUID * majortype);
25 | CMediaType(const AM_MEDIA_TYPE&, __out_opt HRESULT* phr = NULL);
26 | CMediaType(const CMediaType&, __out_opt HRESULT* phr = NULL);
27 |
28 | CMediaType& operator=(const CMediaType&);
29 | CMediaType& operator=(const AM_MEDIA_TYPE&);
30 |
31 | BOOL operator == (const CMediaType&) const;
32 | BOOL operator != (const CMediaType&) const;
33 |
34 | HRESULT Set(const CMediaType& rt);
35 | HRESULT Set(const AM_MEDIA_TYPE& rt);
36 |
37 | BOOL IsValid() const;
38 |
39 | const GUID *Type() const { return &majortype;} ;
40 | void SetType(const GUID *);
41 | const GUID *Subtype() const { return &subtype;} ;
42 | void SetSubtype(const GUID *);
43 |
44 | BOOL IsFixedSize() const {return bFixedSizeSamples; };
45 | BOOL IsTemporalCompressed() const {return bTemporalCompression; };
46 | ULONG GetSampleSize() const;
47 |
48 | void SetSampleSize(ULONG sz);
49 | void SetVariableSize();
50 | void SetTemporalCompression(BOOL bCompressed);
51 |
52 | // read/write pointer to format - can't change length without
53 | // calling SetFormat, AllocFormatBuffer or ReallocFormatBuffer
54 |
55 | BYTE* Format() const {return pbFormat; };
56 | ULONG FormatLength() const { return cbFormat; };
57 |
58 | void SetFormatType(const GUID *);
59 | const GUID *FormatType() const {return &formattype; };
60 | BOOL SetFormat(__in_bcount(length) BYTE *pFormat, ULONG length);
61 | void ResetFormatBuffer();
62 | BYTE* AllocFormatBuffer(ULONG length);
63 | BYTE* ReallocFormatBuffer(ULONG length);
64 |
65 | void InitMediaType();
66 |
67 | BOOL MatchesPartial(const CMediaType* ppartial) const;
68 | BOOL IsPartiallySpecified(void) const;
69 | };
70 |
71 |
72 | /* General purpose functions to copy and delete a task allocated AM_MEDIA_TYPE
73 | structure which is useful when using the IEnumMediaFormats interface as
74 | the implementation allocates the structures which you must later delete */
75 |
76 | void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt);
77 | AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc);
78 | HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource);
79 | void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt);
80 |
81 | // Initialize a media type from a WAVEFORMATEX
82 |
83 | STDAPI CreateAudioMediaType(
84 | const WAVEFORMATEX *pwfx,
85 | __out AM_MEDIA_TYPE *pmt,
86 | BOOL bSetFormat);
87 |
88 | #endif /* __MTYPE__ */
89 |
90 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/outputq.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: OutputQ.h
3 | //
4 | // Desc: DirectShow base classes - defines the COutputQueue class, which
5 | // makes a queue of samples and sends them to an output pin. The
6 | // class will optionally send the samples to the pin directly.
7 | //
8 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
9 | //------------------------------------------------------------------------------
10 |
11 |
12 | typedef CGenericList CSampleList;
13 |
14 | class COutputQueue : public CCritSec
15 | {
16 | public:
17 | // Constructor
18 | COutputQueue(IPin *pInputPin, // Pin to send stuff to
19 | __inout HRESULT *phr, // 'Return code'
20 | BOOL bAuto = TRUE, // Ask pin if blocks
21 | BOOL bQueue = TRUE, // Send through queue (ignored if
22 | // bAuto set)
23 | LONG lBatchSize = 1, // Batch
24 | BOOL bBatchExact = FALSE,// Batch exactly to BatchSize
25 | LONG lListSize = // Likely number in the list
26 | DEFAULTCACHE,
27 | DWORD dwPriority = // Priority of thread to create
28 | THREAD_PRIORITY_NORMAL,
29 | bool bFlushingOpt = false // flushing optimization
30 | );
31 | ~COutputQueue();
32 |
33 | // enter flush state - discard all data
34 | void BeginFlush(); // Begin flushing samples
35 |
36 | // re-enable receives (pass this downstream)
37 | void EndFlush(); // Complete flush of samples - downstream
38 | // pin guaranteed not to block at this stage
39 |
40 | void EOS(); // Call this on End of stream
41 |
42 | void SendAnyway(); // Send batched samples anyway (if bBatchExact set)
43 |
44 | void NewSegment(
45 | REFERENCE_TIME tStart,
46 | REFERENCE_TIME tStop,
47 | double dRate);
48 |
49 | HRESULT Receive(IMediaSample *pSample);
50 |
51 | // do something with these media samples
52 | HRESULT ReceiveMultiple (
53 | __in_ecount(nSamples) IMediaSample **pSamples,
54 | long nSamples,
55 | __out long *nSamplesProcessed);
56 |
57 | void Reset(); // Reset m_hr ready for more data
58 |
59 | // See if its idle or not
60 | BOOL IsIdle();
61 |
62 | // give the class an event to fire after everything removed from the queue
63 | void SetPopEvent(HANDLE hEvent);
64 |
65 | protected:
66 | static DWORD WINAPI InitialThreadProc(__in LPVOID pv);
67 | DWORD ThreadProc();
68 | BOOL IsQueued()
69 | {
70 | return m_List != NULL;
71 | };
72 |
73 | // The critical section MUST be held when this is called
74 | void QueueSample(IMediaSample *pSample);
75 |
76 | BOOL IsSpecialSample(IMediaSample *pSample)
77 | {
78 | return (DWORD_PTR)pSample > (DWORD_PTR)(LONG_PTR)(-16);
79 | };
80 |
81 | // Remove and Release() batched and queued samples
82 | void FreeSamples();
83 |
84 | // Notify the thread there is something to do
85 | void NotifyThread();
86 |
87 |
88 | protected:
89 | // Queue 'messages'
90 | #define SEND_PACKET ((IMediaSample *)(LONG_PTR)(-2)) // Send batch
91 | #define EOS_PACKET ((IMediaSample *)(LONG_PTR)(-3)) // End of stream
92 | #define RESET_PACKET ((IMediaSample *)(LONG_PTR)(-4)) // Reset m_hr
93 | #define NEW_SEGMENT ((IMediaSample *)(LONG_PTR)(-5)) // send NewSegment
94 |
95 | // new segment packet is always followed by one of these
96 | struct NewSegmentPacket {
97 | REFERENCE_TIME tStart;
98 | REFERENCE_TIME tStop;
99 | double dRate;
100 | };
101 |
102 | // Remember input stuff
103 | IPin * const m_pPin;
104 | IMemInputPin * m_pInputPin;
105 | BOOL const m_bBatchExact;
106 | LONG const m_lBatchSize;
107 |
108 | CSampleList * m_List;
109 | HANDLE m_hSem;
110 | CAMEvent m_evFlushComplete;
111 | HANDLE m_hThread;
112 | __field_ecount_opt(m_lBatchSize) IMediaSample ** m_ppSamples;
113 | __range(0, m_lBatchSize) LONG m_nBatched;
114 |
115 | // Wait optimization
116 | LONG m_lWaiting;
117 | // Flush synchronization
118 | BOOL m_bFlushing;
119 |
120 | // flushing optimization. some downstream filters have trouble
121 | // with the queue's flushing optimization. other rely on it
122 | BOOL m_bFlushed;
123 | bool m_bFlushingOpt;
124 |
125 | // Terminate now
126 | BOOL m_bTerminate;
127 |
128 | // Send anyway flag for batching
129 | BOOL m_bSendAnyway;
130 |
131 | // Deferred 'return code'
132 | HRESULT volatile m_hr;
133 |
134 | // an event that can be fired after every deliver
135 | HANDLE m_hEventPop;
136 | };
137 |
138 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/perflog.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: perflog.h
3 | //
4 | // Desc: Performance logging framework.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 | typedef struct _PERFLOG_LOGGING_PARAMS {
10 | GUID ControlGuid;
11 | void (*OnStateChanged)(void);
12 | ULONG NumberOfTraceGuids;
13 | TRACE_GUID_REGISTRATION TraceGuids[ANYSIZE_ARRAY];
14 | } PERFLOG_LOGGING_PARAMS, *PPERFLOG_LOGGING_PARAMS;
15 |
16 | BOOL
17 | PerflogInitIfEnabled(
18 | IN HINSTANCE hInstance,
19 | __in PPERFLOG_LOGGING_PARAMS LogParams
20 | );
21 |
22 | BOOL
23 | PerflogInitialize (
24 | __in PPERFLOG_LOGGING_PARAMS LogParams
25 | );
26 |
27 | VOID
28 | PerflogShutdown (
29 | VOID
30 | );
31 |
32 | VOID
33 | PerflogTraceEvent (
34 | __in PEVENT_TRACE_HEADER Event
35 | );
36 |
37 | extern ULONG PerflogEnableFlags;
38 | extern UCHAR PerflogEnableLevel;
39 | extern ULONG PerflogModuleLevel;
40 | extern TRACEHANDLE PerflogTraceHandle;
41 | extern TRACEHANDLE PerflogRegHandle;
42 |
43 | #define PerflogTracingEnabled() (PerflogTraceHandle != 0)
44 |
45 | #define PerflogEvent( _x_ ) PerflogTraceEventLevel _x_
46 |
47 | VOID
48 | PerflogTraceEventLevel(
49 | ULONG Level,
50 | __in PEVENT_TRACE_HEADER Event
51 | );
52 |
53 | VOID
54 | PerflogTraceEvent (
55 | __in PEVENT_TRACE_HEADER Event
56 | );
57 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/pstream.cpp:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: PStream.cpp
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #include
11 | #include
12 |
13 | #ifdef PERF
14 | #include
15 | #endif
16 | // #include "pstream.h" in streams.h
17 |
18 | //
19 | // Constructor
20 | //
21 | CPersistStream::CPersistStream(IUnknown *punk, __inout HRESULT *phr)
22 | : mPS_fDirty(FALSE)
23 | {
24 | mPS_dwFileVersion = GetSoftwareVersion();
25 | }
26 |
27 |
28 | //
29 | // Destructor
30 | //
31 | CPersistStream::~CPersistStream() {
32 | // Nothing to do
33 | }
34 |
35 | #if 0
36 | SAMPLE CODE TO COPY - not active at the moment
37 |
38 | //
39 | // NonDelegatingQueryInterface
40 | //
41 | // This object supports IPersist & IPersistStream
42 | STDMETHODIMP CPersistStream::NonDelegatingQueryInterface(REFIID riid, __deref_out void **ppv)
43 | {
44 | if (riid == IID_IPersist) {
45 | return GetInterface((IPersist *) this, ppv); // ???
46 | }
47 | else if (riid == IID_IPersistStream) {
48 | return GetInterface((IPersistStream *) this, ppv);
49 | }
50 | else {
51 | return CUnknown::NonDelegatingQueryInterface(riid, ppv);
52 | }
53 | }
54 | #endif
55 |
56 |
57 | //
58 | // WriteToStream
59 | //
60 | // Writes to the stream (default action is to write nothing)
61 | HRESULT CPersistStream::WriteToStream(IStream *pStream)
62 | {
63 | // You can override this to do things like
64 | // hr = pStream->Write(MyStructure, sizeof(MyStructure), NULL);
65 |
66 | return NOERROR;
67 | }
68 |
69 |
70 |
71 | HRESULT CPersistStream::ReadFromStream(IStream * pStream)
72 | {
73 | // You can override this to do things like
74 | // hr = pStream->Read(MyStructure, sizeof(MyStructure), NULL);
75 |
76 | return NOERROR;
77 | }
78 |
79 |
80 | //
81 | // Load
82 | //
83 | // Load all the data from the given stream
84 | STDMETHODIMP CPersistStream::Load(LPSTREAM pStm)
85 | {
86 | HRESULT hr;
87 | // Load the version number then the data
88 | mPS_dwFileVersion = ReadInt(pStm, hr);
89 | if (FAILED(hr)) {
90 | return hr;
91 | }
92 |
93 | return ReadFromStream(pStm);
94 | } // Load
95 |
96 |
97 |
98 | //
99 | // Save
100 | //
101 | // Save the contents of this Stream.
102 | STDMETHODIMP CPersistStream::Save(LPSTREAM pStm, BOOL fClearDirty)
103 | {
104 |
105 | HRESULT hr = WriteInt(pStm, GetSoftwareVersion());
106 | if (FAILED(hr)) {
107 | return hr;
108 | }
109 |
110 | hr = WriteToStream(pStm);
111 | if (FAILED(hr)) {
112 | return hr;
113 | }
114 |
115 | mPS_fDirty = !fClearDirty;
116 |
117 | return hr;
118 | } // Save
119 |
120 |
121 | // WriteInt
122 | //
123 | // Writes an integer to an IStream as 11 UNICODE characters followed by one space.
124 | // You could use this for shorts or unsigneds or anything (up to 32 bits)
125 | // where the value isn't actually truncated by squeezing it into 32 bits.
126 | // Values such as (unsigned) 0x80000000 would come out as -2147483648
127 | // but would then load as 0x80000000 through ReadInt. Cast as you please.
128 |
129 | STDAPI WriteInt(IStream *pIStream, int n)
130 | {
131 | WCHAR Buff[13]; // Allows for trailing null that we don't write
132 | (void)StringCchPrintfW(Buff, NUMELMS(Buff),L"%011d ",n);
133 | return pIStream->Write(&(Buff[0]), 12*sizeof(WCHAR), NULL);
134 | } // WriteInt
135 |
136 |
137 | // ReadInt
138 | //
139 | // Reads an integer from an IStream.
140 | // Read as 4 bytes. You could use this for shorts or unsigneds or anything
141 | // where the value isn't actually truncated by squeezing it into 32 bits
142 | // Striped down subset of what sscanf can do (without dragging in the C runtime)
143 |
144 | STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr)
145 | {
146 |
147 | int Sign = 1;
148 | unsigned int n = 0; // result wil be n*Sign
149 | WCHAR wch;
150 |
151 | hr = pIStream->Read( &wch, sizeof(wch), NULL);
152 | if (FAILED(hr)) {
153 | return 0;
154 | }
155 |
156 | if (wch==L'-'){
157 | Sign = -1;
158 | hr = pIStream->Read( &wch, sizeof(wch), NULL);
159 | if (FAILED(hr)) {
160 | return 0;
161 | }
162 | }
163 |
164 | for( ; ; ) {
165 | if (wch>=L'0' && wch<=L'9') {
166 | n = 10*n+(int)(wch-L'0');
167 | } else if ( wch == L' '
168 | || wch == L'\t'
169 | || wch == L'\r'
170 | || wch == L'\n'
171 | || wch == L'\0'
172 | ) {
173 | break;
174 | } else {
175 | hr = VFW_E_INVALID_FILE_FORMAT;
176 | return 0;
177 | }
178 |
179 | hr = pIStream->Read( &wch, sizeof(wch), NULL);
180 | if (FAILED(hr)) {
181 | return 0;
182 | }
183 | }
184 |
185 | if (n==0x80000000 && Sign==-1) {
186 | // This is the negative number that has no positive version!
187 | return (int)n;
188 | }
189 | else return (int)n * Sign;
190 | } // ReadInt
191 |
192 |
193 | // The microsoft C/C++ compile generates level 4 warnings to the effect that
194 | // a particular inline function (from some base class) was not needed.
195 | // This line gets rid of hundreds of such unwanted messages and makes
196 | // -W4 compilation feasible:
197 | #pragma warning(disable: 4514)
198 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/pstream.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: PStream.h
3 | //
4 | // Desc: DirectShow base classes - defines a class for persistent properties
5 | // of filters.
6 | //
7 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | #ifndef __PSTREAM__
12 | #define __PSTREAM__
13 |
14 | // Base class for persistent properties of filters
15 | // (i.e. filter properties in saved graphs)
16 |
17 | // The simplest way to use this is:
18 | // 1. Arrange for your filter to inherit this class
19 | // 2. Implement in your class WriteToStream and ReadFromStream
20 | // These will override the "do nothing" functions here.
21 | // 3. Change your NonDelegatingQueryInterface to handle IPersistStream
22 | // 4. Implement SizeMax to return the number of bytes of data you save.
23 | // If you save UNICODE data, don't forget a char is 2 bytes.
24 | // 5. Whenever your data changes, call SetDirty()
25 | //
26 | // At some point you may decide to alter, or extend the format of your data.
27 | // At that point you will wish that you had a version number in all the old
28 | // saved graphs, so that you can tell, when you read them, whether they
29 | // represent the old or new form. To assist you in this, this class
30 | // writes and reads a version number.
31 | // When it writes, it calls GetSoftwareVersion() to enquire what version
32 | // of the software we have at the moment. (In effect this is a version number
33 | // of the data layout in the file). It writes this as the first thing in the data.
34 | // If you want to change the version, implement (override) GetSoftwareVersion().
35 | // It reads this from the file into mPS_dwFileVersion before calling ReadFromStream,
36 | // so in ReadFromStream you can check mPS_dwFileVersion to see if you are reading
37 | // an old version file.
38 | // Normally you should accept files whose version is no newer than the software
39 | // version that's reading them.
40 |
41 |
42 | // CPersistStream
43 | //
44 | // Implements IPersistStream.
45 | // See 'OLE Programmers Reference (Vol 1):Structured Storage Overview' for
46 | // more implementation information.
47 | class CPersistStream : public IPersistStream {
48 | private:
49 |
50 | // Internal state:
51 |
52 | protected:
53 | DWORD mPS_dwFileVersion; // version number of file (being read)
54 | BOOL mPS_fDirty;
55 |
56 | public:
57 |
58 | // IPersistStream methods
59 |
60 | STDMETHODIMP IsDirty()
61 | {return (mPS_fDirty ? S_OK : S_FALSE);} // note FALSE means clean
62 | STDMETHODIMP Load(LPSTREAM pStm);
63 | STDMETHODIMP Save(LPSTREAM pStm, BOOL fClearDirty);
64 | STDMETHODIMP GetSizeMax(__out ULARGE_INTEGER * pcbSize)
65 | // Allow 24 bytes for version.
66 | { pcbSize->QuadPart = 12*sizeof(WCHAR)+SizeMax(); return NOERROR; }
67 |
68 | // implementation
69 |
70 | CPersistStream(IUnknown *punk, __inout HRESULT *phr);
71 | ~CPersistStream();
72 |
73 | HRESULT SetDirty(BOOL fDirty)
74 | { mPS_fDirty = fDirty; return NOERROR;}
75 |
76 |
77 | // override to reveal IPersist & IPersistStream
78 | // STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void **ppv);
79 |
80 | // --- IPersist ---
81 |
82 | // You must override this to provide your own class id
83 | STDMETHODIMP GetClassID(__out CLSID *pClsid) PURE;
84 |
85 | // overrideable if you want
86 | // file version number. Override it if you ever change format
87 | virtual DWORD GetSoftwareVersion(void) { return 0; }
88 |
89 |
90 | //=========================================================================
91 | // OVERRIDE THESE to read and write your data
92 | // OVERRIDE THESE to read and write your data
93 | // OVERRIDE THESE to read and write your data
94 |
95 | virtual int SizeMax() {return 0;}
96 | virtual HRESULT WriteToStream(IStream *pStream);
97 | virtual HRESULT ReadFromStream(IStream *pStream);
98 | //=========================================================================
99 |
100 | private:
101 |
102 | };
103 |
104 |
105 | // --- Useful helpers ---
106 |
107 |
108 | // Writes an int to an IStream as UNICODE.
109 | STDAPI WriteInt(IStream *pIStream, int n);
110 |
111 | // inverse of WriteInt
112 | STDAPI_(int) ReadInt(IStream *pIStream, __out HRESULT &hr);
113 |
114 | #endif // __PSTREAM__
115 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/pullpin.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: PullPin.h
3 | //
4 | // Desc: DirectShow base classes - defines CPullPin class.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #ifndef __PULLPIN_H__
11 | #define __PULLPIN_H__
12 |
13 | //
14 | // CPullPin
15 | //
16 | // object supporting pulling data from an IAsyncReader interface.
17 | // Given a start/stop position, calls a pure Receive method with each
18 | // IMediaSample received.
19 | //
20 | // This is essentially for use in a MemInputPin when it finds itself
21 | // connected to an IAsyncReader pin instead of a pushing pin.
22 | //
23 |
24 | class CPullPin : public CAMThread
25 | {
26 | IAsyncReader* m_pReader;
27 | REFERENCE_TIME m_tStart;
28 | REFERENCE_TIME m_tStop;
29 | REFERENCE_TIME m_tDuration;
30 | BOOL m_bSync;
31 |
32 | enum ThreadMsg {
33 | TM_Pause, // stop pulling and wait for next message
34 | TM_Start, // start pulling
35 | TM_Exit, // stop and exit
36 | };
37 |
38 | ThreadMsg m_State;
39 |
40 | // override pure thread proc from CAMThread
41 | DWORD ThreadProc(void);
42 |
43 | // running pull method (check m_bSync)
44 | void Process(void);
45 |
46 | // clean up any cancelled i/o after a flush
47 | void CleanupCancelled(void);
48 |
49 | // suspend thread from pulling, eg during seek
50 | HRESULT PauseThread();
51 |
52 | // start thread pulling - create thread if necy
53 | HRESULT StartThread();
54 |
55 | // stop and close thread
56 | HRESULT StopThread();
57 |
58 | // called from ProcessAsync to queue and collect requests
59 | HRESULT QueueSample(
60 | __inout REFERENCE_TIME& tCurrent,
61 | REFERENCE_TIME tAlignStop,
62 | BOOL bDiscontinuity);
63 |
64 | HRESULT CollectAndDeliver(
65 | REFERENCE_TIME tStart,
66 | REFERENCE_TIME tStop);
67 |
68 | HRESULT DeliverSample(
69 | IMediaSample* pSample,
70 | REFERENCE_TIME tStart,
71 | REFERENCE_TIME tStop);
72 |
73 | protected:
74 | IMemAllocator * m_pAlloc;
75 |
76 | public:
77 | CPullPin();
78 | virtual ~CPullPin();
79 |
80 | // returns S_OK if successfully connected to an IAsyncReader interface
81 | // from this object
82 | // Optional allocator should be proposed as a preferred allocator if
83 | // necessary
84 | // bSync is TRUE if we are to use sync reads instead of the
85 | // async methods.
86 | HRESULT Connect(IUnknown* pUnk, IMemAllocator* pAlloc, BOOL bSync);
87 |
88 | // disconnect any connection made in Connect
89 | HRESULT Disconnect();
90 |
91 | // agree an allocator using RequestAllocator - optional
92 | // props param specifies your requirements (non-zero fields).
93 | // returns an error code if fail to match requirements.
94 | // optional IMemAllocator interface is offered as a preferred allocator
95 | // but no error occurs if it can't be met.
96 | virtual HRESULT DecideAllocator(
97 | IMemAllocator* pAlloc,
98 | __inout_opt ALLOCATOR_PROPERTIES * pProps);
99 |
100 | // set start and stop position. if active, will start immediately at
101 | // the new position. Default is 0 to duration
102 | HRESULT Seek(REFERENCE_TIME tStart, REFERENCE_TIME tStop);
103 |
104 | // return the total duration
105 | HRESULT Duration(__out REFERENCE_TIME* ptDuration);
106 |
107 | // start pulling data
108 | HRESULT Active(void);
109 |
110 | // stop pulling data
111 | HRESULT Inactive(void);
112 |
113 | // helper functions
114 | LONGLONG AlignDown(LONGLONG ll, LONG lAlign) {
115 | // aligning downwards is just truncation
116 | return ll & ~(lAlign-1);
117 | };
118 |
119 | LONGLONG AlignUp(LONGLONG ll, LONG lAlign) {
120 | // align up: round up to next boundary
121 | return (ll + (lAlign -1)) & ~(lAlign -1);
122 | };
123 |
124 | // GetReader returns the (addrefed) IAsyncReader interface
125 | // for SyncRead etc
126 | IAsyncReader* GetReader() {
127 | m_pReader->AddRef();
128 | return m_pReader;
129 | };
130 |
131 | // -- pure --
132 |
133 | // override this to handle data arrival
134 | // return value other than S_OK will stop data
135 | virtual HRESULT Receive(IMediaSample*) PURE;
136 |
137 | // override this to handle end-of-stream
138 | virtual HRESULT EndOfStream(void) PURE;
139 |
140 | // called on runtime errors that will have caused pulling
141 | // to stop
142 | // these errors are all returned from the upstream filter, who
143 | // will have already reported any errors to the filtergraph.
144 | virtual void OnError(HRESULT hr) PURE;
145 |
146 | // flush this pin and all downstream
147 | virtual HRESULT BeginFlush() PURE;
148 | virtual HRESULT EndFlush() PURE;
149 |
150 | };
151 |
152 | #endif //__PULLPIN_H__
153 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/reftime.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: RefTime.h
3 | //
4 | // Desc: DirectShow base classes - defines CRefTime, a class that manages
5 | // reference times.
6 | //
7 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | //
12 | // CRefTime
13 | //
14 | // Manage reference times.
15 | // Shares same data layout as REFERENCE_TIME, but adds some (nonvirtual)
16 | // functions providing simple comparison, conversion and arithmetic.
17 | //
18 | // A reference time (at the moment) is a unit of seconds represented in
19 | // 100ns units as is used in the Win32 FILETIME structure. BUT the time
20 | // a REFERENCE_TIME represents is NOT the time elapsed since 1/1/1601 it
21 | // will either be stream time or reference time depending upon context
22 | //
23 | // This class provides simple arithmetic operations on reference times
24 | //
25 | // keep non-virtual otherwise the data layout will not be the same as
26 | // REFERENCE_TIME
27 |
28 |
29 | // -----
30 | // note that you are safe to cast a CRefTime* to a REFERENCE_TIME*, but
31 | // you will need to do so explicitly
32 | // -----
33 |
34 |
35 | #ifndef __REFTIME__
36 | #define __REFTIME__
37 |
38 |
39 | const LONGLONG MILLISECONDS = (1000); // 10 ^ 3
40 | const LONGLONG NANOSECONDS = (1000000000); // 10 ^ 9
41 | const LONGLONG UNITS = (NANOSECONDS / 100); // 10 ^ 7
42 |
43 | /* Unfortunately an inline function here generates a call to __allmul
44 | - even for constants!
45 | */
46 | #define MILLISECONDS_TO_100NS_UNITS(lMs) \
47 | Int32x32To64((lMs), (UNITS / MILLISECONDS))
48 |
49 | class CRefTime
50 | {
51 | public:
52 |
53 | // *MUST* be the only data member so that this class is exactly
54 | // equivalent to a REFERENCE_TIME.
55 | // Also, must be *no virtual functions*
56 |
57 | REFERENCE_TIME m_time;
58 |
59 | inline CRefTime()
60 | {
61 | // default to 0 time
62 | m_time = 0;
63 | };
64 |
65 | inline CRefTime(LONG msecs)
66 | {
67 | m_time = MILLISECONDS_TO_100NS_UNITS(msecs);
68 | };
69 |
70 | inline CRefTime(REFERENCE_TIME rt)
71 | {
72 | m_time = rt;
73 | };
74 |
75 | inline operator REFERENCE_TIME() const
76 | {
77 | return m_time;
78 | };
79 |
80 | inline CRefTime& operator=(const CRefTime& rt)
81 | {
82 | m_time = rt.m_time;
83 | return *this;
84 | };
85 |
86 | inline CRefTime& operator=(const LONGLONG ll)
87 | {
88 | m_time = ll;
89 | return *this;
90 | };
91 |
92 | inline CRefTime& operator+=(const CRefTime& rt)
93 | {
94 | return (*this = *this + rt);
95 | };
96 |
97 | inline CRefTime& operator-=(const CRefTime& rt)
98 | {
99 | return (*this = *this - rt);
100 | };
101 |
102 | inline LONG Millisecs(void)
103 | {
104 | return (LONG)(m_time / (UNITS / MILLISECONDS));
105 | };
106 |
107 | inline LONGLONG GetUnits(void)
108 | {
109 | return m_time;
110 | };
111 | };
112 |
113 | const LONGLONG TimeZero = 0;
114 |
115 | #endif /* __REFTIME__ */
116 |
117 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/schedule.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: Schedule.h
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1996-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #ifndef __CAMSchedule__
11 | #define __CAMSchedule__
12 |
13 | class CAMSchedule : private CBaseObject
14 | {
15 | public:
16 | virtual ~CAMSchedule();
17 | // ev is the event we should fire if the advise time needs re-evaluating
18 | CAMSchedule( HANDLE ev );
19 |
20 | DWORD GetAdviseCount();
21 | REFERENCE_TIME GetNextAdviseTime();
22 |
23 | // We need a method for derived classes to add advise packets, we return the cookie
24 | DWORD_PTR AddAdvisePacket( const REFERENCE_TIME & time1, const REFERENCE_TIME & time2, HANDLE h, BOOL periodic );
25 | // And a way to cancel
26 | HRESULT Unadvise(DWORD_PTR dwAdviseCookie);
27 |
28 | // Tell us the time please, and we'll dispatch the expired events. We return the time of the next event.
29 | // NB: The time returned will be "useless" if you start adding extra Advises. But that's the problem of
30 | // whoever is using this helper class (typically a clock).
31 | REFERENCE_TIME Advise( const REFERENCE_TIME & rtTime );
32 |
33 | // Get the event handle which will be set if advise time requires re-evaluation.
34 | HANDLE GetEvent() const { return m_ev; }
35 |
36 | private:
37 | // We define the nodes that will be used in our singly linked list
38 | // of advise packets. The list is ordered by time, with the
39 | // elements that will expire first at the front.
40 | class CAdvisePacket
41 | {
42 | public:
43 | CAdvisePacket()
44 | {}
45 |
46 | CAdvisePacket * m_next;
47 | DWORD_PTR m_dwAdviseCookie;
48 | REFERENCE_TIME m_rtEventTime; // Time at which event should be set
49 | REFERENCE_TIME m_rtPeriod; // Periodic time
50 | HANDLE m_hNotify; // Handle to event or semephore
51 | BOOL m_bPeriodic; // TRUE => Periodic event
52 |
53 | CAdvisePacket( __inout_opt CAdvisePacket * next, LONGLONG time ) : m_next(next), m_rtEventTime(time)
54 | {}
55 |
56 | void InsertAfter( __inout CAdvisePacket * p )
57 | {
58 | p->m_next = m_next;
59 | m_next = p;
60 | }
61 |
62 | int IsZ() const // That is, is it the node that represents the end of the list
63 | { return m_next == 0; }
64 |
65 | CAdvisePacket * RemoveNext()
66 | {
67 | CAdvisePacket *const next = m_next;
68 | CAdvisePacket *const new_next = next->m_next;
69 | m_next = new_next;
70 | return next;
71 | }
72 |
73 | void DeleteNext()
74 | {
75 | delete RemoveNext();
76 | }
77 |
78 | CAdvisePacket * Next() const
79 | {
80 | CAdvisePacket * result = m_next;
81 | if (result->IsZ()) result = 0;
82 | return result;
83 | }
84 |
85 | DWORD_PTR Cookie() const
86 | { return m_dwAdviseCookie; }
87 | };
88 |
89 | // Structure is:
90 | // head -> elmt1 -> elmt2 -> z -> null
91 | // So an empty list is: head -> z -> null
92 | // Having head & z as links makes insertaion,
93 | // deletion and shunting much easier.
94 | CAdvisePacket head, z; // z is both a tail and a sentry
95 |
96 | volatile DWORD_PTR m_dwNextCookie; // Strictly increasing
97 | volatile DWORD m_dwAdviseCount; // Number of elements on list
98 |
99 | CCritSec m_Serialize;
100 |
101 | // AddAdvisePacket: adds the packet, returns the cookie (0 if failed)
102 | DWORD_PTR AddAdvisePacket( __inout CAdvisePacket * pPacket );
103 | // Event that we should set if the packed added above will be the next to fire.
104 | const HANDLE m_ev;
105 |
106 | // A Shunt is where we have changed the first element in the
107 | // list and want it re-evaluating (i.e. repositioned) in
108 | // the list.
109 | void ShuntHead();
110 |
111 | // Rather than delete advise packets, we cache them for future use
112 | CAdvisePacket * m_pAdviseCache;
113 | DWORD m_dwCacheCount;
114 | enum { dwCacheMax = 5 }; // Don't bother caching more than five
115 |
116 | void Delete( __inout CAdvisePacket * pLink );// This "Delete" will cache the Link
117 |
118 | // Attributes and methods for debugging
119 | public:
120 | #ifdef DEBUG
121 | void DumpLinkedList();
122 | #else
123 | void DumpLinkedList() {}
124 | #endif
125 |
126 | };
127 |
128 | #endif // __CAMSchedule__
129 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/seekpt.cpp:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: SeekPT.cpp
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #include
11 | #include "seekpt.h"
12 |
13 | //==================================================================
14 | // CreateInstance
15 | // This goes in the factory template table to create new instances
16 | // If there is already a mapper instance - return that, else make one
17 | // and save it in a static variable so that forever after we can return that.
18 | //==================================================================
19 |
20 | CUnknown * CSeekingPassThru::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr)
21 | {
22 | return new CSeekingPassThru(NAME("Seeking PassThru"),pUnk, phr);
23 | }
24 |
25 |
26 | STDMETHODIMP CSeekingPassThru::NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv)
27 | {
28 | if (riid == IID_ISeekingPassThru) {
29 | return GetInterface((ISeekingPassThru *) this, ppv);
30 | } else {
31 | if (m_pPosPassThru &&
32 | (riid == IID_IMediaSeeking ||
33 | riid == IID_IMediaPosition)) {
34 | return m_pPosPassThru->NonDelegatingQueryInterface(riid,ppv);
35 | } else {
36 | return CUnknown::NonDelegatingQueryInterface(riid, ppv);
37 | }
38 | }
39 | }
40 |
41 |
42 | CSeekingPassThru::CSeekingPassThru( __in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr )
43 | : CUnknown(pName, pUnk, phr),
44 | m_pPosPassThru(NULL)
45 | {
46 | }
47 |
48 |
49 | CSeekingPassThru::~CSeekingPassThru()
50 | {
51 | delete m_pPosPassThru;
52 | }
53 |
54 | STDMETHODIMP CSeekingPassThru::Init(BOOL bRendererSeeking, IPin *pPin)
55 | {
56 | HRESULT hr = NOERROR;
57 | if (m_pPosPassThru) {
58 | hr = E_FAIL;
59 | } else {
60 | m_pPosPassThru =
61 | bRendererSeeking ?
62 | new CRendererPosPassThru(
63 | NAME("Render Seeking COM object"),
64 | (IUnknown *)this,
65 | &hr,
66 | pPin) :
67 | new CPosPassThru(
68 | NAME("Render Seeking COM object"),
69 | (IUnknown *)this,
70 | &hr,
71 | pPin);
72 | if (!m_pPosPassThru) {
73 | hr = E_OUTOFMEMORY;
74 | } else {
75 | if (FAILED(hr)) {
76 | delete m_pPosPassThru;
77 | m_pPosPassThru = NULL;
78 | }
79 | }
80 | }
81 | return hr;
82 | }
83 |
84 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/seekpt.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: SeekPT.h
3 | //
4 | // Desc: DirectShow base classes.
5 | //
6 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
7 | //------------------------------------------------------------------------------
8 |
9 |
10 | #ifndef __seekpt_h__
11 | #define __seekpt_h__
12 |
13 |
14 | class CSeekingPassThru : public ISeekingPassThru, public CUnknown
15 | {
16 | public:
17 | static CUnknown *CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr);
18 | CSeekingPassThru(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr);
19 | ~CSeekingPassThru();
20 |
21 | DECLARE_IUNKNOWN;
22 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv);
23 |
24 | STDMETHODIMP Init(BOOL bSupportRendering, IPin *pPin);
25 |
26 | private:
27 | CPosPassThru *m_pPosPassThru;
28 | };
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/streams.cpp:
--------------------------------------------------------------------------------
1 | #include "streams.h"
2 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/sysclock.cpp:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: SysClock.cpp
3 | //
4 | // Desc: DirectShow base classes - implements a system clock based on
5 | // IReferenceClock.
6 | //
7 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | #include
12 | #include
13 |
14 |
15 | #ifdef FILTER_DLL
16 |
17 | /* List of class IDs and creator functions for the class factory. This
18 | provides the link between the OLE entry point in the DLL and an object
19 | being created. The class factory will call the static CreateInstance
20 | function when it is asked to create a CLSID_SystemClock object */
21 |
22 | CFactoryTemplate g_Templates[1] = {
23 | {&CLSID_SystemClock, CSystemClock::CreateInstance}
24 | };
25 |
26 | int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
27 | #endif
28 |
29 | /* This goes in the factory template table to create new instances */
30 | CUnknown * WINAPI CSystemClock::CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr)
31 | {
32 | return new CSystemClock(NAME("System reference clock"),pUnk, phr);
33 | }
34 |
35 |
36 | CSystemClock::CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr) :
37 | CBaseReferenceClock(pName, pUnk, phr)
38 | {
39 | }
40 |
41 | STDMETHODIMP CSystemClock::NonDelegatingQueryInterface(
42 | REFIID riid,
43 | __deref_out void ** ppv)
44 | {
45 | if (riid == IID_IPersist)
46 | {
47 | return GetInterface(static_cast(this), ppv);
48 | }
49 | else if (riid == IID_IAMClockAdjust)
50 | {
51 | return GetInterface(static_cast(this), ppv);
52 | }
53 | else
54 | {
55 | return CBaseReferenceClock::NonDelegatingQueryInterface(riid, ppv);
56 | }
57 | }
58 |
59 | /* Return the clock's clsid */
60 | STDMETHODIMP
61 | CSystemClock::GetClassID(__out CLSID *pClsID)
62 | {
63 | CheckPointer(pClsID,E_POINTER);
64 | ValidateReadWritePtr(pClsID,sizeof(CLSID));
65 | *pClsID = CLSID_SystemClock;
66 | return NOERROR;
67 | }
68 |
69 |
70 | STDMETHODIMP
71 | CSystemClock::SetClockDelta(REFERENCE_TIME rtDelta)
72 | {
73 | return SetTimeDelta(rtDelta);
74 | }
75 |
--------------------------------------------------------------------------------
/dll/src/baseclasses/sysclock.h:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | // File: SysClock.h
3 | //
4 | // Desc: DirectShow base classes - defines a system clock implementation of
5 | // IReferenceClock.
6 | //
7 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8 | //------------------------------------------------------------------------------
9 |
10 |
11 | #ifndef __SYSTEMCLOCK__
12 | #define __SYSTEMCLOCK__
13 |
14 | //
15 | // Base clock. Uses timeGetTime ONLY
16 | // Uses most of the code in the base reference clock.
17 | // Provides GetTime
18 | //
19 |
20 | class CSystemClock : public CBaseReferenceClock, public IAMClockAdjust, public IPersist
21 | {
22 | public:
23 | // We must be able to create an instance of ourselves
24 | static CUnknown * WINAPI CreateInstance(__inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr);
25 | CSystemClock(__in_opt LPCTSTR pName, __inout_opt LPUNKNOWN pUnk, __inout HRESULT *phr);
26 |
27 | DECLARE_IUNKNOWN
28 |
29 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, __deref_out void ** ppv);
30 |
31 | // Yield up our class id so that we can be persisted
32 | // Implement required Ipersist method
33 | STDMETHODIMP GetClassID(__out CLSID *pClsID);
34 |
35 | // IAMClockAdjust methods
36 | STDMETHODIMP SetClockDelta(REFERENCE_TIME rtDelta);
37 | }; //CSystemClock
38 |
39 | #endif /* __SYSTEMCLOCK__ */
40 |
--------------------------------------------------------------------------------
/dll/src/bs2b.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {C59B751C-F10D-4DE0-B580-73CB03B27B6E}
23 |
24 |
25 |
26 |
27 | Unicode
28 | StaticLibrary
29 |
30 |
31 | true
32 |
33 |
34 | false
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | Level3
47 | true
48 | true
49 |
50 |
51 |
52 |
53 | Disabled
54 | false
55 |
56 |
57 |
58 |
59 | MaxSpeed
60 | true
61 | true
62 |
63 |
64 | true
65 | true
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/dll/src/fftw-config/config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define FFTW_DOUBLE 1
4 | #define HAVE_SSE2 1
5 |
6 | #define DISABLE_FORTRAN 1
7 |
8 | #define HAVE_ABORT 1
9 | #define HAVE_UINTPTR_T 1
10 |
11 | #define HAVE_INTTYPES_H 1
12 | #define HAVE_MALLOC_H 1
13 | #define HAVE_STDINT_H 1
14 | #define HAVE_STRING_H 1
15 | #define HAVE_SYS_TYPES_H 1
16 |
17 | #define FFTW_CC "cl"
18 | #define PACKAGE "fftw"
19 | #define VERSION "3.3.4"
20 | #define PACKAGE_VERSION VERSION
21 |
--------------------------------------------------------------------------------
/dll/src/rubberband.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {863E6128-1F58-4371-A282-0FCC62DFF747}
23 |
24 |
25 |
26 |
27 | Unicode
28 | StaticLibrary
29 |
30 |
31 | true
32 |
33 |
34 | false
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | true
47 | rubberband;rubberband\src;soxr\src;fftw\api
48 | __MSVC__;WIN32;NOMINMAX;_USE_MATH_DEFINES;NO_THREADING;PROCESS_SAMPLE_TYPE=double;HAVE_FFTW3;FFTW_DOUBLE_ONLY;HAVE_LIBSAMPLERATE;%(PreprocessorDefinitions)
49 |
50 |
51 |
52 |
53 | Disabled
54 | false
55 |
56 |
57 |
58 |
59 | MaxSpeed
60 | true
61 | true
62 |
63 |
64 | true
65 | true
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | ..\snprintf.h
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | true
87 |
88 |
89 |
90 |
91 |
92 |
93 | true
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
--------------------------------------------------------------------------------
/dll/src/rubberband.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | src
6 |
7 |
8 | src
9 |
10 |
11 | src
12 |
13 |
14 | src
15 |
16 |
17 | src
18 |
19 |
20 | src
21 |
22 |
23 | src
24 |
25 |
26 | src
27 |
28 |
29 | src
30 |
31 |
32 | src
33 |
34 |
35 | src
36 |
37 |
38 | src
39 |
40 |
41 | src
42 |
43 |
44 | src
45 |
46 |
47 | src
48 |
49 |
50 | src
51 |
52 |
53 | src
54 |
55 |
56 | src
57 |
58 |
59 | src
60 |
61 |
62 | src
63 |
64 |
65 |
66 |
67 |
68 |
69 | {5f1ad43f-a951-4728-878e-cae51eb9e82a}
70 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {E02FD084-ED17-46C7-B5A6-F0BBB7966BBB}
23 |
24 |
25 |
26 |
27 | Unicode
28 | DynamicLibrary
29 |
30 |
31 | true
32 |
33 |
34 | false
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 | $(BinDir)
46 | .ax
47 |
48 |
49 | sanear
50 |
51 |
52 | sanear64
53 |
54 |
55 |
56 | Level3
57 | true
58 | true
59 | Use
60 | pch.h
61 | baseclasses
62 |
63 |
64 | sanear-dll/sanear.def
65 | Comctl32.lib;%(AdditionalDependencies)
66 |
67 |
68 |
69 |
70 | Disabled
71 | false
72 |
73 |
74 |
75 |
76 | MaxSpeed
77 | true
78 | true
79 |
80 |
81 | true
82 | true
83 |
84 |
85 |
86 |
87 | {bb2b61af-734a-4dad-9326-07f4f9ea088f}
88 |
89 |
90 | {b8375339-1932-4cc0-ae5b-257672078e41}
91 |
92 |
93 | {c59b751c-f10d-4de0-b580-73cb03b27b6e}
94 |
95 |
96 | {85a00e9e-c632-497e-8dcb-857487f4d940}
97 |
98 |
99 | {863e6128-1f58-4371-a282-0fcc62dff747}
100 |
101 |
102 | {3c1b816a-645c-4e1f-a006-5c47263e59c5}
103 |
104 |
105 | {2d2a92ff-1fb6-4926-affb-5e00d27939fc}
106 |
107 |
108 |
109 |
110 |
111 |
112 | Create
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Common
7 |
8 |
9 | Filter
10 |
11 |
12 | Filter
13 |
14 |
15 | Filter
16 |
17 |
18 |
19 |
20 | Resources
21 |
22 |
23 | Common
24 |
25 |
26 | Filter
27 |
28 |
29 | Filter
30 |
31 |
32 | Filter
33 |
34 |
35 |
36 |
37 | {c31c72e9-891d-4f49-8964-60ac80d2db08}
38 |
39 |
40 | {57b1ee7d-f0ca-499f-b0fd-57fe76f3012d}
41 |
42 |
43 | {8215adc6-5660-48db-98c3-2627cc6f8b77}
44 |
45 |
46 | {575443ed-3498-4000-aec4-9cfc20cb4a2f}
47 |
48 |
49 |
50 |
51 | Props
52 |
53 |
54 | Props
55 |
56 |
57 | Props
58 |
59 |
60 | Props
61 |
62 |
63 |
64 |
65 |
66 | Resources
67 |
68 |
69 |
70 |
71 | Resources
72 |
73 |
74 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/Entry.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
3 | #include "OuterFilter.h"
4 | #include "../../../src/MyPropertyPage.h"
5 |
6 | namespace
7 | {
8 | // {DF557071-C9FD-433A-9627-81E0D3640ED9}
9 | const GUID filterGuid = {0xdf557071, 0xc9fd, 0x433a, {0x96, 0x27, 0x81, 0xe0, 0xd3, 0x64, 0xe, 0xd9}};
10 | const WCHAR filterName[] = L"Sanear Audio Renderer";
11 |
12 | const GUID statusPageGuid = __uuidof(SaneAudioRenderer::MyPropertyPage);
13 | const WCHAR statusPageName[] = L"Sanear Status Page";
14 |
15 | const AMOVIESETUP_MEDIATYPE pinTypes[] = {
16 | {&MEDIATYPE_Audio, &CLSID_NULL},
17 | };
18 |
19 | const AMOVIESETUP_PIN setupPin = {
20 | L"", TRUE, FALSE, FALSE, FALSE, &CLSID_NULL, nullptr, _countof(pinTypes), pinTypes,
21 | };
22 |
23 | const AMOVIESETUP_FILTER setupFilter = {
24 | &filterGuid, filterName, MERIT_DO_NOT_USE, 1, &setupPin
25 | };
26 | }
27 |
28 | CUnknown* WINAPI CreateFilterInstance(LPUNKNOWN, HRESULT*);
29 | CUnknown* WINAPI CreateStatusPageInstance(LPUNKNOWN, HRESULT*);
30 |
31 | CFactoryTemplate g_Templates[] = {
32 | {filterName, &filterGuid, CreateFilterInstance},
33 | {statusPageName, &statusPageGuid, CreateStatusPageInstance},
34 | };
35 |
36 | int g_cTemplates = _countof(g_Templates);
37 |
38 |
39 | STDAPI RegisterAllServers(LPCWSTR szFileName, BOOL bRegister);
40 |
41 | namespace
42 | {
43 | struct CoFreeUnusedLibrariesHelper
44 | {
45 | ~CoFreeUnusedLibrariesHelper() { CoFreeUnusedLibraries(); };
46 | };
47 |
48 | HRESULT DllRegisterServer(bool reg)
49 | {
50 | wchar_t filename[MAX_PATH];
51 | if (!GetModuleFileName(g_hInst, filename, MAX_PATH))
52 | return AmGetLastErrorToHResult();
53 |
54 | if (reg)
55 | ReturnIfFailed(RegisterAllServers(filename, TRUE));
56 |
57 | {
58 | SaneAudioRenderer::CoInitializeHelper coInitializeHelper(COINIT_APARTMENTTHREADED);
59 | CoFreeUnusedLibrariesHelper coFreeUnusedLibrariesHelper;
60 |
61 | IFilterMapper2Ptr filterMapper;
62 | ReturnIfFailed(CoCreateInstance(CLSID_FilterMapper2, nullptr,
63 | CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&filterMapper)));
64 | {
65 | HRESULT result;
66 |
67 | result = filterMapper->UnregisterFilter(nullptr, nullptr, *setupFilter.clsID);
68 |
69 | if (FAILED(result))
70 | ReturnIfNotEquals(result, 0x80070002);
71 |
72 | result = filterMapper->UnregisterFilter(&CLSID_AudioRendererCategory, nullptr, *setupFilter.clsID);
73 |
74 | if (FAILED(result))
75 | ReturnIfNotEquals(result, 0x80070002);
76 | }
77 |
78 | if (reg)
79 | {
80 | const REGFILTER2 rf = {
81 | 1,
82 | setupFilter.dwMerit,
83 | setupFilter.nPins,
84 | setupFilter.lpPin,
85 | };
86 |
87 | ReturnIfFailed(filterMapper->RegisterFilter(*setupFilter.clsID, setupFilter.strName,
88 | nullptr, &CLSID_AudioRendererCategory, nullptr, &rf));
89 |
90 | ReturnIfFailed(filterMapper->RegisterFilter(*setupFilter.clsID, setupFilter.strName,
91 | nullptr, nullptr, nullptr, &rf));
92 | }
93 | }
94 |
95 | if (!reg)
96 | ReturnIfFailed(RegisterAllServers(filename, FALSE));
97 |
98 | return S_OK;
99 | }
100 | }
101 |
102 | CUnknown* WINAPI CreateFilterInstance(IUnknown* pUnknown, HRESULT* pResult)
103 | {
104 | CheckPointer(pResult, nullptr);
105 |
106 | auto pFilter = new(std::nothrow) SaneAudioRenderer::OuterFilter(pUnknown, filterGuid);
107 |
108 | if (!pFilter)
109 | *pResult = E_OUTOFMEMORY;
110 |
111 | return pFilter;
112 | }
113 |
114 | CUnknown* WINAPI CreateStatusPageInstance(IUnknown* pUnknown, HRESULT* pResult)
115 | {
116 | CheckPointer(pResult, nullptr);
117 |
118 | auto pFilter = new(std::nothrow) SaneAudioRenderer::MyPropertyPage();
119 |
120 | if (!pFilter)
121 | *pResult = E_OUTOFMEMORY;
122 |
123 | return pFilter;
124 | }
125 |
126 | STDAPI DllRegisterServer()
127 | {
128 | if (!IsWindowsVistaOrGreater())
129 | return E_FAIL;
130 |
131 | return DllRegisterServer(true);
132 | }
133 |
134 | STDAPI DllUnregisterServer()
135 | {
136 | return DllRegisterServer(false);
137 | }
138 |
139 | extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
140 |
141 | BOOL WINAPI DllMain(HINSTANCE hDllHandle, DWORD dwReason, LPVOID pReserved)
142 | {
143 | return DllEntryPoint(hDllHandle, dwReason, pReserved);
144 | }
145 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/OuterFilter.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "OuterFilter.h"
3 |
4 | #include "../../../src/Factory.h"
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | namespace
9 | {
10 | const auto DeviceId = L"DeviceId";
11 | const auto DeviceExclusive = L"DeviceExclusive";
12 | const auto DeviceBufferDuration = L"DeviceBufferDuration";
13 | const auto AllowBitstreaming = L"AllowBitstreaming";
14 | const auto CrossfeedEnabled = L"CrossfeedEnabled";
15 | const auto CrossfeedCutoffFrequency = L"CrossfeedCutoffFrequency";
16 | const auto CrossfeedLevel = L"CrossfeedLevel";
17 | const auto IgnoreSystemChannelMixer = L"IgnoreSystemChannelMixer";
18 | }
19 |
20 | OuterFilter::OuterFilter(IUnknown* pUnknown, const GUID& guid)
21 | : CUnknown(L"SaneAudioRenderer::OuterFilter", pUnknown)
22 | , m_guid(guid)
23 | {
24 | }
25 |
26 | OuterFilter::~OuterFilter()
27 | {
28 | BOOL boolValue;
29 | WCHAR* stringValue;
30 | UINT32 uintValue1;
31 | UINT32 uintValue2;
32 |
33 | if (SUCCEEDED(m_settings->GetOuputDevice(&stringValue, &boolValue, &uintValue1)))
34 | {
35 | std::unique_ptr holder(stringValue);
36 | m_registryKey.SetString(DeviceId, stringValue);
37 | m_registryKey.SetUint(DeviceExclusive, boolValue);
38 | m_registryKey.SetUint(DeviceBufferDuration, uintValue1);
39 | }
40 |
41 | m_registryKey.SetUint(AllowBitstreaming, m_settings->GetAllowBitstreaming());
42 |
43 | m_registryKey.SetUint(CrossfeedEnabled, m_settings->GetCrossfeedEnabled());
44 |
45 | m_settings->GetCrossfeedSettings(&uintValue1, &uintValue2);
46 | m_registryKey.SetUint(CrossfeedCutoffFrequency, uintValue1);
47 | m_registryKey.SetUint(CrossfeedLevel, uintValue2);
48 |
49 | m_registryKey.SetUint(IgnoreSystemChannelMixer, m_settings->GetIgnoreSystemChannelMixer());
50 | }
51 |
52 | STDMETHODIMP OuterFilter::NonDelegatingQueryInterface(REFIID riid, void** ppv)
53 | {
54 | if (!m_initialized)
55 | ReturnIfFailed(Init());
56 |
57 | if (riid == IID_IUnknown)
58 | return CUnknown::NonDelegatingQueryInterface(riid, ppv);
59 |
60 | if (riid == IID_ISpecifyPropertyPages)
61 | return m_innerFilter->QueryInterface(__uuidof(ISpecifyPropertyPages2), ppv);
62 |
63 | return m_innerFilter->QueryInterface(riid, ppv);
64 | }
65 |
66 | HRESULT OuterFilter::Init()
67 | {
68 | assert(!m_initialized);
69 |
70 | ReturnIfFailed(Factory::CreateSettings(&m_settings))
71 | ReturnIfFailed(Factory::CreateFilterAggregated(GetOwner(), m_guid, m_settings, &m_innerFilter));
72 | ReturnIfFailed(m_registryKey.Open(HKEY_CURRENT_USER, L"Software\\sanear"));
73 | ReturnIfFailed(m_trayWindow.Init(m_settings));
74 |
75 | m_initialized = true;
76 |
77 | std::vector stringValue;
78 | uint32_t uintValue1;
79 | uint32_t uintValue2;
80 |
81 | if (m_registryKey.GetString(DeviceId, stringValue) &&
82 | m_registryKey.GetUint(DeviceExclusive, uintValue1) &&
83 | m_registryKey.GetUint(DeviceBufferDuration, uintValue2))
84 | {
85 | m_settings->SetOuputDevice(stringValue.data(), uintValue1, uintValue2);
86 | }
87 |
88 | if (m_registryKey.GetUint(AllowBitstreaming, uintValue1))
89 | m_settings->SetAllowBitstreaming(uintValue1);
90 |
91 | if (m_registryKey.GetUint(CrossfeedEnabled, uintValue1))
92 | m_settings->SetCrossfeedEnabled(uintValue1);
93 |
94 | if (m_registryKey.GetUint(CrossfeedCutoffFrequency, uintValue1) &&
95 | m_registryKey.GetUint(CrossfeedLevel, uintValue2))
96 | {
97 | m_settings->SetCrossfeedSettings(uintValue1, uintValue2);
98 | }
99 |
100 | if (m_registryKey.GetUint(IgnoreSystemChannelMixer, uintValue1))
101 | m_settings->SetIgnoreSystemChannelMixer(uintValue1);
102 |
103 | return S_OK;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/OuterFilter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "RegistryKey.h"
4 | #include "TrayWindow.h"
5 |
6 | #include "../../../src/Interfaces.h"
7 |
8 | namespace SaneAudioRenderer
9 | {
10 | class OuterFilter final
11 | : public CUnknown
12 | {
13 | public:
14 |
15 | OuterFilter(IUnknown* pUnknown, const GUID& guid);
16 | ~OuterFilter();
17 | OuterFilter(const OuterFilter&) = delete;
18 | OuterFilter& operator=(const OuterFilter&) = delete;
19 |
20 | DECLARE_IUNKNOWN
21 |
22 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override;
23 |
24 | private:
25 |
26 | HRESULT Init();
27 |
28 | const GUID& m_guid;
29 | bool m_initialized = false;
30 | RegistryKey m_registryKey;
31 | ISettingsPtr m_settings;
32 | IUnknownPtr m_innerFilter;
33 | TrayWindow m_trayWindow;
34 | };
35 | }
36 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/RegistryKey.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "RegistryKey.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | HRESULT RegistryKey::Open(HKEY key, const wchar_t* subkey)
7 | {
8 | Close();
9 |
10 | return RegCreateKeyEx(key, subkey, 0, nullptr, REG_OPTION_NON_VOLATILE,
11 | KEY_READ | KEY_WRITE, nullptr, &m_hKey, nullptr);
12 | }
13 |
14 | void RegistryKey::Close()
15 | {
16 | if (m_hKey != NULL)
17 | {
18 | RegCloseKey(m_hKey);
19 | m_hKey = NULL;
20 | }
21 | }
22 |
23 | RegistryKey::~RegistryKey()
24 | {
25 | Close();
26 | }
27 |
28 | bool RegistryKey::SetString(const wchar_t* key, const wchar_t* value)
29 | {
30 | const DWORD valueSize = (DWORD)(wcslen(value) + 1) * sizeof(wchar_t);
31 | return RegSetValueEx(m_hKey, key, 0, REG_SZ, (const BYTE*)value, valueSize) == ERROR_SUCCESS;
32 | }
33 |
34 | bool RegistryKey::GetString(const wchar_t* name, std::vector& value)
35 | {
36 | DWORD valueSize;
37 | DWORD valuetype;
38 |
39 | if (RegQueryValueEx(m_hKey, name, 0, &valuetype, nullptr, &valueSize) != ERROR_SUCCESS)
40 | return false;
41 |
42 | try
43 | {
44 | value.resize(valueSize / sizeof(wchar_t));
45 | }
46 | catch (std::bad_alloc&)
47 | {
48 | return false;
49 | }
50 |
51 | if (RegQueryValueEx(m_hKey, name, 0, &valuetype, (BYTE*)value.data(), &valueSize) != ERROR_SUCCESS ||
52 | valuetype != REG_SZ)
53 | {
54 | return false;
55 | }
56 |
57 | return true;
58 | }
59 |
60 | bool RegistryKey::SetUint(const wchar_t* name, uint32_t value)
61 | {
62 | return RegSetValueEx(m_hKey, name, 0, REG_DWORD, (BYTE*)&value, sizeof(uint32_t)) == ERROR_SUCCESS;
63 | }
64 |
65 | bool RegistryKey::GetUint(const wchar_t* name, uint32_t& value)
66 | {
67 | DWORD valueSize = sizeof(uint32_t);
68 | DWORD valuetype;
69 |
70 | if (RegQueryValueEx(m_hKey, name, 0, &valuetype, (BYTE*)&value, &valueSize) != ERROR_SUCCESS ||
71 | valuetype != REG_DWORD)
72 | {
73 | return false;
74 | }
75 |
76 | return true;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/RegistryKey.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace SaneAudioRenderer
4 | {
5 | class RegistryKey final
6 | {
7 | public:
8 |
9 | RegistryKey() = default;
10 | ~RegistryKey();
11 | RegistryKey(const RegistryKey&) = delete;
12 | RegistryKey& operator=(const RegistryKey&) = delete;
13 |
14 | HRESULT Open(HKEY key, const wchar_t* subkey);
15 | void Close();
16 |
17 | bool SetString(const wchar_t* name, const wchar_t* value);
18 | bool GetString(const wchar_t* name, std::vector& value);
19 |
20 | bool SetUint(const wchar_t* name, uint32_t value);
21 | bool RegistryKey::GetUint(const wchar_t* name, uint32_t& value);
22 |
23 | private:
24 |
25 | HKEY m_hKey = NULL;
26 | };
27 | }
28 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/TrayWindow.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../../../src/Interfaces.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class TrayWindow final
8 | {
9 | public:
10 |
11 | TrayWindow();
12 | ~TrayWindow();
13 | TrayWindow(const TrayWindow&) = delete;
14 | TrayWindow& operator=(const TrayWindow&) = delete;
15 |
16 | HRESULT Init(ISettings* pSettings);
17 |
18 | DWORD ThreadProc();
19 | LRESULT WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
20 |
21 | private:
22 |
23 | void Destroy();
24 |
25 | void AddIcon();
26 | void RemoveIcon();
27 |
28 | void AddMenu();
29 | void RemoveMenu();
30 |
31 | void OnTrayNotify(WPARAM wParam, LPARAM lParam);
32 | void OnCommand(WPARAM wParam, LPARAM lParam);
33 |
34 | UINT m_taskbarCreatedMessage = 0;
35 | NOTIFYICONDATA m_nid;
36 |
37 | ISettingsPtr m_settings;
38 | HANDLE m_hThread = NULL;
39 | HWND m_hWindow = NULL;
40 | HMENU m_hMenu = NULL;
41 | std::promise m_windowCreated;
42 | std::vector> m_devices;
43 | };
44 | }
45 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/pch.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/pch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../../../src/pch.h"
4 |
5 | #include
6 | #include
7 |
8 | namespace SaneAudioRenderer
9 | {
10 | template
11 | unsigned CALLBACK StaticThreadProc(LPVOID p)
12 | {
13 | return (static_cast(p)->*ThreadProc)();
14 | }
15 |
16 | template
17 | LRESULT CALLBACK StaticWindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
18 | {
19 | if (LONG_PTR userData = GetWindowLongPtr(hWnd, GWLP_USERDATA))
20 | return (reinterpret_cast(userData)->*WindowProc)(hWnd, msg, wParam, lParam);
21 |
22 | if (msg == WM_NCCREATE)
23 | {
24 | CREATESTRUCT* pCreateStruct = reinterpret_cast(lParam);
25 | SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast(pCreateStruct->lpCreateParams));
26 | return (static_cast(pCreateStruct->lpCreateParams)->*WindowProc)(hWnd, msg, wParam, lParam);
27 | }
28 |
29 | return DefWindowProc(hWnd, msg, wParam, lParam);
30 | }
31 |
32 | inline void RunMessageLoop()
33 | {
34 | MSG msg;
35 | while (GetMessage(&msg, NULL, 0, 0))
36 | {
37 | TranslateMessage(&msg);
38 | DispatchMessage(&msg);
39 | }
40 | }
41 | }
42 |
43 | _COM_SMARTPTR_TYPEDEF(IFilterMapper2, __uuidof(IFilterMapper2));
44 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by sanear.rc
4 | //
5 | #define IDI_ICON1 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/sanear.def:
--------------------------------------------------------------------------------
1 | EXPORTS
2 | DllGetClassObject PRIVATE
3 | DllCanUnloadNow PRIVATE
4 | DllRegisterServer PRIVATE
5 | DllUnregisterServer PRIVATE
6 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/sanear.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpc-hc/sanear/f7612c7f71316f357b00e43f5a497d1d0289ffe6/dll/src/sanear-dll/sanear.ico
--------------------------------------------------------------------------------
/dll/src/sanear-dll/sanear.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #include "resource.h"
4 |
5 | #define APSTUDIO_READONLY_SYMBOLS
6 | /////////////////////////////////////////////////////////////////////////////
7 | //
8 | // Generated from the TEXTINCLUDE 2 resource.
9 | //
10 | #include "winres.h"
11 |
12 | /////////////////////////////////////////////////////////////////////////////
13 | #undef APSTUDIO_READONLY_SYMBOLS
14 |
15 | /////////////////////////////////////////////////////////////////////////////
16 | // English (United Kingdom) resources
17 |
18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
19 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
20 | #pragma code_page(1252)
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""winres.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Icon
51 | //
52 |
53 | // Icon with lowest ID value placed first to ensure application icon
54 | // remains consistent on all systems.
55 | IDI_ICON1 ICON "sanear.ico"
56 |
57 | /////////////////////////////////////////////////////////////////////////////
58 | //
59 | // Version
60 | //
61 |
62 | VS_VERSION_INFO VERSIONINFO
63 | FILEVERSION 0,3,0,0
64 | PRODUCTVERSION 0,3,0,0
65 | FILEFLAGSMASK 0x3fL
66 | #ifdef _DEBUG
67 | FILEFLAGS 0x1L
68 | #else
69 | FILEFLAGS 0x0L
70 | #endif
71 | FILEOS 0x40004L
72 | FILETYPE 0x2L
73 | FILESUBTYPE 0x0L
74 | BEGIN
75 | BLOCK "StringFileInfo"
76 | BEGIN
77 | BLOCK "080904b0"
78 | BEGIN
79 | VALUE "FileDescription", "Sanear, a robust DirectShow audio renderer"
80 | VALUE "FileVersion", "0.3.0.0"
81 | VALUE "ProductName", "Sanear Audio Renderer"
82 | VALUE "ProductVersion", "0.3.0.0"
83 | END
84 | END
85 | BLOCK "VarFileInfo"
86 | BEGIN
87 | VALUE "Translation", 0x809, 1200
88 | END
89 | END
90 |
91 | #endif // English (United Kingdom) resources
92 | /////////////////////////////////////////////////////////////////////////////
93 |
94 |
95 |
96 | #ifndef APSTUDIO_INVOKED
97 | /////////////////////////////////////////////////////////////////////////////
98 | //
99 | // Generated from the TEXTINCLUDE 3 resource.
100 | //
101 |
102 |
103 | /////////////////////////////////////////////////////////////////////////////
104 | #endif // not APSTUDIO_INVOKED
105 |
106 |
--------------------------------------------------------------------------------
/dll/src/sanear-dll/sanear.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
80 |
--------------------------------------------------------------------------------
/dll/src/snprintf.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #define snprintf sprintf_s
4 |
--------------------------------------------------------------------------------
/dll/src/soundtouch.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {3C1B816A-645C-4E1F-A006-5C47263E59C5}
23 |
24 |
25 |
26 |
27 | Unicode
28 | StaticLibrary
29 |
30 |
31 | true
32 |
33 |
34 | false
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | Level3
47 | true
48 | true
49 | soundtouch\include
50 |
51 |
52 |
53 |
54 | Disabled
55 | false
56 |
57 |
58 |
59 |
60 | MaxSpeed
61 | true
62 | true
63 |
64 |
65 | true
66 | true
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
--------------------------------------------------------------------------------
/dll/src/soxr-config.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define HAVE_SINGLE_PRECISION 1
4 | #define HAVE_DOUBLE_PRECISION 1
5 | #define HAVE_SIMD 1
6 | #define HAVE_FENV_H 1
7 | #define HAVE_LRINT 1
8 |
9 | #define HAVE_AVFFT 0
10 | #define WORDS_BIGENDIAN 0
11 |
12 | #include
13 | #include
14 |
--------------------------------------------------------------------------------
/dll/src/soxr.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Debug
10 | x64
11 |
12 |
13 | Release
14 | Win32
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | {2D2A92FF-1FB6-4926-AFFB-5E00D27939FC}
23 |
24 |
25 |
26 |
27 | Unicode
28 | StaticLibrary
29 |
30 |
31 | true
32 |
33 |
34 | false
35 | true
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | TurnOffAllWarnings
47 | true
48 | .
49 | _USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;SOXR_LIB;%(PreprocessorDefinitions)
50 |
51 |
52 |
53 |
54 | Disabled
55 | false
56 |
57 |
58 |
59 |
60 | MaxSpeed
61 | true
62 | true
63 |
64 |
65 | true
66 | true
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/AudioDevice.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspChunk.h"
4 | #include "DspFormat.h"
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | struct AudioDeviceBackend final
9 | {
10 | SharedString id;
11 | SharedString adapterName;
12 | SharedString endpointName;
13 | UINT32 endpointFormFactor;
14 | bool supportsSharedEventMode;
15 | bool supportsExclusiveEventMode;
16 |
17 | IAudioClientPtr audioClient;
18 | IAudioRenderClientPtr audioRenderClient;
19 | IAudioClockPtr audioClock;
20 |
21 | SharedWaveFormat mixFormat;
22 |
23 | SharedWaveFormat waveFormat;
24 | DspFormat dspFormat;
25 |
26 | uint32_t bufferDuration;
27 |
28 | REFERENCE_TIME deviceLatency;
29 | UINT32 deviceBufferSize;
30 |
31 | bool exclusive;
32 | bool bitstream;
33 | bool eventMode;
34 | bool realtime;
35 |
36 | bool ignoredSystemChannelMixer;
37 | };
38 |
39 | class AudioDevice
40 | {
41 | public:
42 |
43 | virtual ~AudioDevice() = default;
44 |
45 | virtual void Push(DspChunk& chunk, CAMEvent* pFilledEvent) = 0;
46 | virtual REFERENCE_TIME Finish(CAMEvent* pFilledEvent) = 0;
47 |
48 | virtual int64_t GetPosition() = 0;
49 | virtual int64_t GetEnd() = 0;
50 | virtual int64_t GetSilence() = 0;
51 |
52 | virtual void Start() = 0;
53 | virtual void Stop() = 0;
54 | virtual void Reset() = 0;
55 |
56 | SharedString GetId() const { return m_backend->id; }
57 | SharedString GetAdapterName() const { return m_backend->adapterName; }
58 | SharedString GetEndpointName() const { return m_backend->endpointName; }
59 |
60 | IAudioClockPtr GetClock() { return m_backend->audioClock; }
61 |
62 | SharedWaveFormat GetMixFormat() const { return m_backend->mixFormat; }
63 |
64 | SharedWaveFormat GetWaveFormat() const { return m_backend->waveFormat; }
65 | uint32_t GetRate() const { return m_backend->waveFormat->nSamplesPerSec; }
66 | uint32_t GetChannelCount() const { return m_backend->waveFormat->nChannels; }
67 | DspFormat GetDspFormat() const { return m_backend->dspFormat; }
68 | uint32_t GetBufferDuration() const { return m_backend->bufferDuration; }
69 | REFERENCE_TIME GetStreamLatency() const { return m_backend->deviceLatency; }
70 |
71 | bool IsExclusive() const { return m_backend->exclusive; }
72 | bool IsRealtime() const { return m_backend->realtime; }
73 |
74 | bool IgnoredSystemChannelMixer() const { return m_backend->ignoredSystemChannelMixer; }
75 |
76 | using RenewBackendFunction = std::function&)>;
77 | virtual bool RenewInactive(const RenewBackendFunction& renewBackend, int64_t& position) = 0;
78 |
79 | protected:
80 |
81 | std::shared_ptr m_backend;
82 |
83 | template
84 | bool IsLastInstance(T& smartPointer)
85 | {
86 | bool ret = (smartPointer.GetInterfacePtr()->AddRef() == 2);
87 | smartPointer.GetInterfacePtr()->Release();
88 | return ret;
89 | }
90 |
91 | bool CheckLastInstances()
92 | {
93 | if (!m_backend.unique())
94 | return false;
95 |
96 | if (m_backend->audioClock && !IsLastInstance(m_backend->audioClock))
97 | return false;
98 |
99 | m_backend->audioClock = nullptr;
100 |
101 | if (m_backend->audioRenderClient && !IsLastInstance(m_backend->audioRenderClient))
102 | return false;
103 |
104 | m_backend->audioRenderClient = nullptr;
105 |
106 | if (m_backend->audioClient && !IsLastInstance(m_backend->audioClient))
107 | return false;
108 |
109 | return true;
110 | }
111 | };
112 | }
113 |
--------------------------------------------------------------------------------
/src/AudioDeviceEvent.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "AudioDevice.h"
4 | #include "DspChunk.h"
5 | #include "DspFormat.h"
6 |
7 | namespace SaneAudioRenderer
8 | {
9 | class AudioDeviceEvent final
10 | : public AudioDevice
11 | {
12 | public:
13 |
14 | AudioDeviceEvent(std::shared_ptr backend);
15 | AudioDeviceEvent(const AudioDeviceEvent&) = delete;
16 | AudioDeviceEvent& operator=(const AudioDeviceEvent&) = delete;
17 | ~AudioDeviceEvent();
18 |
19 | void Push(DspChunk& chunk, CAMEvent* pFilledEvent) override;
20 | REFERENCE_TIME Finish(CAMEvent* pFilledEvent) override;
21 |
22 | int64_t GetPosition() override;
23 | int64_t GetEnd() override;
24 | int64_t GetSilence() override;
25 |
26 | void Start() override;
27 | void Stop() override;
28 | void Reset() override;
29 |
30 | bool RenewInactive(const RenewBackendFunction& renewBackend, int64_t& position) override;
31 |
32 | private:
33 |
34 | void EventFeed();
35 |
36 | void PushBufferToDevice();
37 | void PushChunkToBuffer(DspChunk& chunk);
38 |
39 | std::atomic m_endOfStream = false;
40 | int64_t m_endOfStreamPos = 0;
41 |
42 | std::thread m_thread;
43 | CCritSec m_threadMutex;
44 |
45 | CAMEvent m_wake;
46 | std::atomic m_exit = false;
47 | std::atomic m_error = false;
48 |
49 | uint64_t m_sentFrames = 0;
50 | std::atomic m_receivedFrames = 0;
51 | std::atomic m_silenceFrames = 0;
52 |
53 | CCritSec m_bufferMutex;
54 | std::deque m_buffer;
55 | size_t m_bufferFrames = 0;
56 |
57 | bool m_queuedStart = false;
58 |
59 | bool m_observeInactivity = false;
60 | CAMEvent m_observeInactivityWake;
61 | int64_t m_activityPointCounter = 0;
62 |
63 | CCritSec m_renewMutex;
64 | bool m_awaitingRenew = false;
65 | int64_t m_renewPosition = 0;
66 | size_t m_renewSilenceFrames = 0;
67 | };
68 | }
69 |
--------------------------------------------------------------------------------
/src/AudioDeviceManager.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "AudioDevice.h"
4 | #include "Interfaces.h"
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | class AudioDeviceNotificationClient final
9 | : public CUnknown
10 | , public IMMNotificationClient
11 | {
12 | public:
13 |
14 | DECLARE_IUNKNOWN
15 |
16 | AudioDeviceNotificationClient(std::atomic& defaultDeviceSerial);
17 | AudioDeviceNotificationClient(const AudioDeviceNotificationClient&) = delete;
18 | AudioDeviceNotificationClient& operator=(const AudioDeviceNotificationClient&) = delete;
19 |
20 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override;
21 |
22 | STDMETHODIMP OnDeviceStateChanged(LPCWSTR, DWORD) override { return S_OK; }
23 | STDMETHODIMP OnDeviceAdded(LPCWSTR) override { return S_OK; }
24 | STDMETHODIMP OnDeviceRemoved(LPCWSTR) override { return S_OK; }
25 | STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR);
26 | STDMETHODIMP OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY) override { return S_OK; }
27 |
28 | private:
29 |
30 | std::atomic& m_defaultDeviceSerial;
31 | };
32 |
33 | class AudioDeviceManager final
34 | {
35 | public:
36 |
37 | AudioDeviceManager(HRESULT& result);
38 | AudioDeviceManager(const AudioDeviceManager&) = delete;
39 | AudioDeviceManager& operator=(const AudioDeviceManager&) = delete;
40 | ~AudioDeviceManager();
41 |
42 | bool BitstreamFormatSupported(SharedWaveFormat format, ISettings* pSettings);
43 | std::unique_ptr CreateDevice(SharedWaveFormat format, bool realtime, ISettings* pSettings);
44 | bool RenewInactiveDevice(AudioDevice& device, int64_t& position);
45 |
46 | uint32_t GetDefaultDeviceSerial() { return m_defaultDeviceSerial; }
47 | std::unique_ptr GetDefaultDeviceId();
48 |
49 | private:
50 |
51 | std::thread m_thread;
52 | std::atomic m_exit = false;
53 | CAMEvent m_wake;
54 | CAMEvent m_done;
55 |
56 | std::function m_function;
57 | HRESULT m_result = S_OK;
58 |
59 | IMMDeviceEnumeratorPtr m_enumerator;
60 |
61 | IMMNotificationClientPtr m_notificationClient;
62 | std::atomic m_defaultDeviceSerial = 0;
63 | };
64 | }
65 |
--------------------------------------------------------------------------------
/src/AudioDevicePush.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "AudioDevice.h"
4 | #include "DspChunk.h"
5 | #include "DspFormat.h"
6 |
7 | namespace SaneAudioRenderer
8 | {
9 | class AudioDevicePush final
10 | : public AudioDevice
11 | {
12 | public:
13 |
14 | AudioDevicePush(std::shared_ptr backend);
15 | AudioDevicePush(const AudioDevicePush&) = delete;
16 | AudioDevicePush& operator=(const AudioDevicePush&) = delete;
17 | ~AudioDevicePush();
18 |
19 | void Push(DspChunk& chunk, CAMEvent* pFilledEvent) override;
20 | REFERENCE_TIME Finish(CAMEvent* pFilledEvent) override;
21 |
22 | int64_t GetPosition() override;
23 | int64_t GetEnd() override;
24 | int64_t GetSilence() override;
25 |
26 | void Start() override;
27 | void Stop() override;
28 | void Reset() override;
29 |
30 | bool RenewInactive(const RenewBackendFunction& renewBackend, int64_t& position) override;
31 |
32 | private:
33 |
34 | void SilenceFeed();
35 |
36 | void PushChunkToDevice(DspChunk& chunk, CAMEvent* pFilledEvent);
37 | UINT32 PushSilenceToDevice(UINT32 frames);
38 |
39 | bool m_endOfStream = false;
40 | int64_t m_endOfStreamPos = 0;
41 |
42 | uint64_t m_pushedFrames = 0;
43 | std::atomic m_silenceFrames = 0;
44 |
45 | std::thread m_thread;
46 | CAMEvent m_wake;
47 | std::atomic m_exit = false;
48 | std::atomic m_error = false;
49 | };
50 | }
51 |
--------------------------------------------------------------------------------
/src/AudioRenderer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "AudioDevice.h"
4 | #include "AudioDeviceManager.h"
5 | #include "DspBalance.h"
6 | #include "DspCrossfeed.h"
7 | #include "DspDither.h"
8 | #include "DspLimiter.h"
9 | #include "DspMatrix.h"
10 | #include "DspRate.h"
11 | #include "DspTempo.h"
12 | #include "DspTempo2.h"
13 | #include "DspVolume.h"
14 | #include "Interfaces.h"
15 | #include "SampleCorrection.h"
16 |
17 | namespace SaneAudioRenderer
18 | {
19 | class MyClock;
20 |
21 | class AudioRenderer final
22 | : public CCritSec
23 | {
24 | public:
25 |
26 | AudioRenderer(ISettings* pSettings, MyClock& clock, HRESULT& result);
27 | AudioRenderer(const AudioRenderer&) = delete;
28 | AudioRenderer& operator=(const AudioRenderer&) = delete;
29 | ~AudioRenderer();
30 |
31 | void SetClock(IReferenceClock* pClock);
32 |
33 | bool Push(IMediaSample* pSample, AM_SAMPLE2_PROPERTIES& sampleProps, CAMEvent* pFilledEvent);
34 | bool Finish(bool blockUntilEnd, CAMEvent* pFilledEvent);
35 |
36 | void BeginFlush();
37 | void EndFlush();
38 |
39 | bool CheckFormat(SharedWaveFormat inputFormat, bool live);
40 | void SetFormat(SharedWaveFormat inputFormat, bool live);
41 |
42 | void NewSegment(double rate);
43 |
44 | void Play(REFERENCE_TIME startTime);
45 | void Pause();
46 | void Stop();
47 |
48 | float GetVolume() const { return m_volume; }
49 | void SetVolume(float volume) { m_volume = volume; }
50 | float GetBalance() const { return m_balance; }
51 | void SetBalance(float balance) { m_balance = balance; }
52 |
53 | SharedWaveFormat GetInputFormat();
54 | const AudioDevice* GetAudioDevice();
55 | std::vector GetActiveProcessors();
56 |
57 | void TakeGuidedReclock(REFERENCE_TIME offset) { m_guidedReclockOffset += offset; }
58 |
59 | bool OnExternalClock() const { return m_externalClock; }
60 | bool IsLive() const { return m_live; }
61 | bool IsBitstreaming() const { return m_bitstreaming; }
62 |
63 | bool OnGuidedReclock();
64 |
65 | private:
66 |
67 | void CheckDeviceSettings();
68 | void StartDevice();
69 | void CreateDevice();
70 | void ClearDevice();
71 |
72 | REFERENCE_TIME EstimateSlavingJitter();
73 |
74 | void PushReslavingJitter();
75 |
76 | void ApplyClockCorrection();
77 |
78 | void ApplyRateCorrection(DspChunk& chunk);
79 |
80 | void InitializeProcessors();
81 |
82 | template
83 | void EnumerateProcessors(F f)
84 | {
85 | f(&m_dspMatrix);
86 | f(&m_dspRate);
87 | #ifdef SANEAR_GPL_PHASE_VOCODER
88 | f(&m_dspTempo1);
89 | f(&m_dspTempo2);
90 | #else
91 | f(&m_dspTempo);
92 | #endif
93 | f(&m_dspCrossfeed);
94 | f(&m_dspVolume);
95 | f(&m_dspBalance);
96 | f(&m_dspLimiter);
97 | f(&m_dspDither);
98 | }
99 |
100 | bool PushToDevice(DspChunk& chunk, CAMEvent* pFilledEvent);
101 |
102 | AudioDeviceManager m_deviceManager;
103 | std::unique_ptr m_device;
104 |
105 | FILTER_STATE m_state = State_Stopped;
106 |
107 | SampleCorrection m_sampleCorrection;
108 | REFERENCE_TIME m_clockCorrection = 0;
109 |
110 | MyClock& m_myClock;
111 | IReferenceClockPtr m_graphClock;
112 |
113 | std::atomic m_externalClock = false;
114 | std::atomic m_live = false;
115 | std::atomic m_bitstreaming = false;
116 |
117 | SharedWaveFormat m_inputFormat;
118 |
119 | REFERENCE_TIME m_startClockOffset = 0;
120 | REFERENCE_TIME m_startTime = 0;
121 |
122 | CAMEvent m_flush;
123 |
124 | DspMatrix m_dspMatrix;
125 | DspRate m_dspRate;
126 | #ifdef SANEAR_GPL_PHASE_VOCODER
127 | DspTempo m_dspTempo1;
128 | DspTempo2 m_dspTempo2;
129 | #else
130 | DspTempo m_dspTempo;
131 | #endif
132 | DspCrossfeed m_dspCrossfeed;
133 | DspVolume m_dspVolume;
134 | DspBalance m_dspBalance;
135 | DspLimiter m_dspLimiter;
136 | DspDither m_dspDither;
137 |
138 | ISettingsPtr m_settings;
139 | UINT32 m_deviceSettingsSerial = 0;
140 |
141 | uint32_t m_defaultDeviceSerial = 0;
142 |
143 | std::atomic m_volume = 1.0f;
144 | std::atomic m_balance = 0.0f;
145 | double m_rate = 1.0;
146 |
147 | std::atomic m_guidedReclockOffset = 0;
148 | bool m_guidedReclockActive = false;
149 |
150 | size_t m_dropNextFrames = 0;
151 | };
152 | }
153 |
--------------------------------------------------------------------------------
/src/DspBalance.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DspBalance.h"
3 |
4 | #include "AudioRenderer.h"
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | bool DspBalance::Active()
9 | {
10 | return m_renderer.GetBalance() != 0.0f;
11 | }
12 |
13 | void DspBalance::Process(DspChunk& chunk)
14 | {
15 | const float balance = m_renderer.GetBalance();
16 | assert(balance >= -1.0f && balance <= 1.0f);
17 |
18 | if (balance == 0.0f || chunk.IsEmpty() || chunk.GetChannelCount() != 2)
19 | return;
20 |
21 | DspChunk::ToFloat(chunk);
22 |
23 | auto data = reinterpret_cast(chunk.GetData());
24 | const float gain = std::abs(balance);
25 | for (size_t i = (balance < 0.0f ? 1 : 0), n = chunk.GetSampleCount(); i < n; i += 2)
26 | data[i] *= gain;
27 | }
28 |
29 | void DspBalance::Finish(DspChunk& chunk)
30 | {
31 | Process(chunk);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/DspBalance.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class AudioRenderer;
8 |
9 | class DspBalance final
10 | : public DspBase
11 | {
12 | public:
13 |
14 | DspBalance(AudioRenderer& renderer) : m_renderer(renderer) {}
15 | DspBalance(const DspBalance&) = delete;
16 | DspBalance& operator=(const DspBalance&) = delete;
17 |
18 | bool Active() override;
19 |
20 | std::wstring Name() override { return L"Balance"; }
21 |
22 | void Process(DspChunk& chunk) override;
23 | void Finish(DspChunk& chunk) override;
24 |
25 | private:
26 |
27 | const AudioRenderer& m_renderer;
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/src/DspBase.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspChunk.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class DspBase
8 | {
9 | public:
10 |
11 | virtual ~DspBase() = default;
12 |
13 | virtual std::wstring Name() = 0;
14 |
15 | virtual bool Active() = 0;
16 |
17 | virtual void Process(DspChunk& chunk) = 0;
18 | virtual void Finish(DspChunk& chunk) = 0;
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/src/DspChunk.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspFormat.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class DspChunk final
8 | {
9 | public:
10 |
11 | static void ToFormat(DspFormat format, DspChunk& chunk);
12 | static void ToFloat(DspChunk& chunk) { ToFormat(DspFormat::Float, chunk); }
13 | static void ToDouble(DspChunk& chunk) { ToFormat(DspFormat::Double, chunk); }
14 |
15 | static void MergeChunks(DspChunk& chunk, DspChunk& appendage);
16 |
17 | DspChunk();
18 | DspChunk(DspFormat format, uint32_t channels, size_t frames, uint32_t rate);
19 | DspChunk(IMediaSample* pSample, const AM_SAMPLE2_PROPERTIES& sampleProps, const WAVEFORMATEX& sampleFormat);
20 | DspChunk(DspChunk&& other);
21 | DspChunk& operator=(DspChunk&& other);
22 |
23 | bool IsEmpty() const { return m_dataSize == 0; }
24 |
25 | DspFormat GetFormat() const { return m_format; }
26 | uint32_t GetFormatSize() const { return m_formatSize; }
27 | uint32_t GetChannelCount() const { return m_channels; }
28 | uint32_t GetFrameSize() const { return m_formatSize * m_channels; }
29 | uint32_t GetRate() const { return m_rate; }
30 |
31 | size_t GetSize() const { return m_dataSize; }
32 | size_t GetSampleCount() const { assert(m_formatSize); return m_dataSize / m_formatSize; }
33 | size_t GetFrameCount() const { assert(m_channels != 0); return GetSampleCount() / m_channels; }
34 |
35 | char* GetData() { return (m_mediaSample ? m_mediaData : m_data.get()) + m_dataOffset; }
36 |
37 | void PadTail(size_t padFrames);
38 | void PadHead(size_t padFrames);
39 |
40 | void ShrinkTail(size_t toFrames);
41 | void ShrinkHead(size_t toFrames);
42 |
43 | void FreeMediaSample();
44 |
45 | private:
46 |
47 | void Allocate();
48 |
49 | IMediaSamplePtr m_mediaSample;
50 |
51 | DspFormat m_format;
52 | uint32_t m_formatSize;
53 | uint32_t m_channels;
54 | uint32_t m_rate;
55 |
56 | size_t m_dataSize;
57 | char* m_mediaData;
58 | std::unique_ptr m_data;
59 | size_t m_dataOffset;
60 | };
61 | }
62 |
--------------------------------------------------------------------------------
/src/DspCrossfeed.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DspCrossfeed.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | void DspCrossfeed::Initialize(ISettings* pSettings, uint32_t rate, uint32_t channels, DWORD mask)
7 | {
8 | assert(pSettings);
9 | m_settings = pSettings;
10 |
11 | m_possible = (channels == 2 &&
12 | mask == KSAUDIO_SPEAKER_STEREO &&
13 | rate >= BS2B_MINSRATE &&
14 | rate <= BS2B_MAXSRATE);
15 |
16 | if (m_possible)
17 | {
18 | m_bs2b.clear();
19 | m_bs2b.set_srate(rate);
20 | UpdateSettings();
21 | }
22 | }
23 |
24 | bool DspCrossfeed::Active()
25 | {
26 | return m_active;
27 | }
28 |
29 | void DspCrossfeed::Process(DspChunk& chunk)
30 | {
31 | if (m_settingsSerial != m_settings->GetSerial())
32 | UpdateSettings();
33 |
34 | if (!m_active || chunk.IsEmpty())
35 | return;
36 |
37 | assert(chunk.GetChannelCount() == 2);
38 |
39 | DspChunk::ToFloat(chunk);
40 |
41 | m_bs2b.cross_feed((float*)chunk.GetData(), (int)chunk.GetFrameCount());
42 | }
43 |
44 | void DspCrossfeed::Finish(DspChunk& chunk)
45 | {
46 | Process(chunk);
47 | }
48 |
49 | void DspCrossfeed::UpdateSettings()
50 | {
51 | m_settingsSerial = m_settings->GetSerial();
52 |
53 | UINT32 cutoffFrequency;
54 | UINT32 crossfeedLevel;
55 | m_settings->GetCrossfeedSettings(&cutoffFrequency, &crossfeedLevel);
56 |
57 | bool wasActive = m_active;
58 |
59 | BOOL enabled = m_settings->GetCrossfeedEnabled();
60 |
61 | m_active = m_possible && enabled;
62 |
63 | if (m_active)
64 | {
65 | m_bs2b.set_level_fcut(cutoffFrequency);
66 | m_bs2b.set_level_feed(crossfeedLevel);
67 | }
68 | else if (wasActive)
69 | {
70 | m_bs2b.clear();
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/DspCrossfeed.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 | #include "Interfaces.h"
5 |
6 | #include
7 |
8 | namespace SaneAudioRenderer
9 | {
10 | class DspCrossfeed final
11 | : public DspBase
12 | {
13 | public:
14 |
15 | DspCrossfeed() = default;
16 | DspCrossfeed(const DspCrossfeed&) = delete;
17 | DspCrossfeed& operator=(const DspCrossfeed&) = delete;
18 |
19 | void Initialize(ISettings* pSettings, uint32_t rate, uint32_t channels, DWORD mask);
20 |
21 | std::wstring Name() override { return L"Crossfeed"; }
22 |
23 | bool Active() override;
24 |
25 | void Process(DspChunk& chunk) override;
26 | void Finish(DspChunk& chunk) override;
27 |
28 | private:
29 |
30 | void UpdateSettings();
31 |
32 | bs2b_base m_bs2b;
33 |
34 | ISettingsPtr m_settings;
35 | UINT32 m_settingsSerial = 0;
36 |
37 | bool m_possible = false;
38 | bool m_active = false;
39 | };
40 | }
41 |
--------------------------------------------------------------------------------
/src/DspDither.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DspDither.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | void DspDither::Initialize(DspFormat outputFormat)
7 | {
8 | m_enabled = (outputFormat == DspFormat::Pcm16);
9 | m_active = m_enabled;
10 |
11 | for (size_t i = 0; i < 18; i++)
12 | {
13 | m_previous[i] = 0.0f;
14 | m_generator[i].seed((uint32_t)(GetPerformanceCounter() + i));
15 | m_distributor[i] = std::uniform_real_distribution(0, 1.0f);
16 | }
17 | }
18 |
19 | bool DspDither::Active()
20 | {
21 | return m_enabled && m_active;
22 | }
23 |
24 | void DspDither::Process(DspChunk& chunk)
25 | {
26 | if (!m_enabled || chunk.IsEmpty() || chunk.GetFormatSize() <= DspFormatSize(DspFormat::Pcm16))
27 | {
28 | m_active = false;
29 | return;
30 | }
31 |
32 | m_active = true;
33 |
34 | DspChunk::ToFloat(chunk);
35 |
36 | DspChunk output(DspFormat::Pcm16, chunk.GetChannelCount(), chunk.GetFrameCount(), chunk.GetRate());
37 |
38 | auto inputData = reinterpret_cast(chunk.GetData());
39 | auto outputData = reinterpret_cast(output.GetData());
40 | const size_t channels = chunk.GetChannelCount();
41 |
42 | for (size_t frame = 0, frames = chunk.GetFrameCount(); frame < frames; frame++)
43 | {
44 | for (size_t channel = 0; channel < channels; channel++)
45 | {
46 | float inputSample = inputData[frame * channels + channel] * (INT16_MAX - 1);
47 |
48 | // High-pass TPDF, 2 LSB amplitude.
49 | float r = m_distributor[channel](m_generator[channel]);
50 | float noise = r - m_previous[channel];
51 | m_previous[channel] = r;
52 |
53 | float outputSample = std::round(inputSample + noise);
54 | assert(outputSample >= INT16_MIN && outputSample <= INT16_MAX);
55 | outputData[frame * channels + channel] = (int16_t)outputSample;
56 | }
57 | }
58 |
59 | chunk = std::move(output);
60 | }
61 |
62 | void DspDither::Finish(DspChunk& chunk)
63 | {
64 | Process(chunk);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/DspDither.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class DspDither final
8 | : public DspBase
9 | {
10 | public:
11 |
12 | DspDither() = default;
13 | DspDither(const DspDither&) = delete;
14 | DspDither& operator=(const DspDither&) = delete;
15 |
16 | void Initialize(DspFormat outputFormat);
17 |
18 | std::wstring Name() override { return L"Dither"; }
19 |
20 | bool Active() override;
21 |
22 | void Process(DspChunk& chunk) override;
23 | void Finish(DspChunk& chunk) override;
24 |
25 | private:
26 |
27 | bool m_enabled = false;
28 | bool m_active = false;
29 | std::array m_previous;
30 | std::array m_generator;
31 | std::array, 18> m_distributor;
32 | };
33 | }
34 |
--------------------------------------------------------------------------------
/src/DspFormat.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace SaneAudioRenderer
4 | {
5 | enum class DspFormat
6 | {
7 | Unknown,
8 | Pcm8,
9 | Pcm16,
10 | Pcm24,
11 | Pcm24in32,
12 | Pcm32,
13 | Float,
14 | Double,
15 | };
16 |
17 | template
18 | struct DspFormatTraits;
19 |
20 | template <>
21 | struct DspFormatTraits
22 | {
23 | typedef int8_t SampleType;
24 | };
25 |
26 | template <>
27 | struct DspFormatTraits
28 | {
29 | typedef int16_t SampleType;
30 | };
31 |
32 | #pragma pack(push, 1)
33 | typedef struct { int8_t d[3]; } int24_t;
34 | #pragma pack(pop)
35 |
36 | static_assert(sizeof(int24_t) == 3, "Failed to pack the struct properly");
37 |
38 | template <>
39 | struct DspFormatTraits
40 | {
41 | typedef int24_t SampleType;
42 | };
43 |
44 | template <>
45 | struct DspFormatTraits
46 | {
47 | typedef int32_t SampleType;
48 | };
49 |
50 | template <>
51 | struct DspFormatTraits
52 | {
53 | typedef int32_t SampleType;
54 | };
55 |
56 | template <>
57 | struct DspFormatTraits
58 | {
59 | typedef float SampleType;
60 | };
61 |
62 | template <>
63 | struct DspFormatTraits
64 | {
65 | typedef double SampleType;
66 | };
67 |
68 | static_assert(sizeof(float) == 4, "Floats are not IEEE compliant");
69 | static_assert(sizeof(double) == 8, "Floats are not IEEE compliant");
70 |
71 | inline uint32_t DspFormatSize(DspFormat format)
72 | {
73 | return (format == DspFormat::Unknown) ? 0 :
74 | (format == DspFormat::Pcm8) ? 1 :
75 | (format == DspFormat::Pcm16) ? 2 :
76 | (format == DspFormat::Pcm24) ? 3 :
77 | (format == DspFormat::Double) ? 8 : 4;
78 | }
79 |
80 | inline DspFormat DspFormatFromWaveFormat(const WAVEFORMATEX& format)
81 | {
82 | if (format.nSamplesPerSec == 0)
83 | return DspFormat::Unknown;
84 |
85 | if (format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT)
86 | {
87 | switch (format.wBitsPerSample)
88 | {
89 | case 32: return DspFormat::Float;
90 | case 64: return DspFormat::Double;
91 | }
92 | }
93 | else if (format.wFormatTag == WAVE_FORMAT_PCM)
94 | {
95 | switch (format.wBitsPerSample)
96 | {
97 | case 8: return DspFormat::Pcm8;
98 | case 16: return DspFormat::Pcm16;
99 | case 24: return DspFormat::Pcm24;
100 | case 32: return DspFormat::Pcm32;
101 | }
102 | }
103 | else if (format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)
104 | {
105 | const WAVEFORMATEXTENSIBLE& formatExtensible = (const WAVEFORMATEXTENSIBLE&)format;
106 |
107 | if (formatExtensible.SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)
108 | {
109 | switch (format.wBitsPerSample)
110 | {
111 | case 32: return DspFormat::Float;
112 | case 64: return DspFormat::Double;
113 | }
114 | }
115 | else if (formatExtensible.SubFormat == KSDATAFORMAT_SUBTYPE_PCM)
116 | {
117 | switch (format.wBitsPerSample)
118 | {
119 | case 8: return DspFormat::Pcm8;
120 | case 16: return DspFormat::Pcm16;
121 | case 24: return DspFormat::Pcm24;
122 | case 32: return formatExtensible.Samples.wValidBitsPerSample == 24 ? DspFormat::Pcm24in32 :
123 | DspFormat::Pcm32;
124 | }
125 | }
126 | }
127 |
128 | return DspFormat::Unknown;
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/src/DspLimiter.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DspLimiter.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | namespace
7 | {
8 | const float slope = 1.0f - 1.0f / 20.0f; // 20:1 ratio
9 |
10 | template
11 | T GetPeak(const T* data, size_t n)
12 | {
13 | T peak = 0;
14 |
15 | for (size_t i = 0; i < n; i++)
16 | peak = std::max(peak, std::abs(data[i]));
17 |
18 | return peak;
19 | }
20 |
21 | template
22 | void ApplyLimiter(T* data, size_t n, T threshold)
23 | {
24 | for (size_t i = 0; i < n; i++)
25 | {
26 | T& sample = data[i];
27 | const T absSample = std::abs(sample);
28 |
29 | if (absSample > threshold)
30 | sample *= std::pow(threshold / absSample, slope);
31 |
32 | assert(std::abs(sample) <= 1);
33 | }
34 | }
35 | }
36 |
37 | void DspLimiter::Initialize(uint32_t rate, uint32_t channels, bool exclusive)
38 | {
39 | m_exclusive = exclusive;
40 | m_rate = rate;
41 | m_channels = channels;
42 |
43 | m_active = false;
44 | m_holdWindow = 0;
45 | m_peak = 0.0f;
46 | m_threshold = 0.0f;
47 | }
48 |
49 | bool DspLimiter::Active()
50 | {
51 | return m_active;
52 | }
53 |
54 | void DspLimiter::Process(DspChunk& chunk)
55 | {
56 | if (chunk.IsEmpty())
57 | return;
58 |
59 | if (!m_exclusive || (chunk.GetFormat() != DspFormat::Float &&
60 | chunk.GetFormat() != DspFormat::Double))
61 | {
62 | m_active = false;
63 | return;
64 | }
65 |
66 | m_active = true;
67 |
68 | // Analyze samples
69 | float peak;
70 | if (chunk.GetFormat() == DspFormat::Double)
71 | {
72 | double largePeak = GetPeak((double*)chunk.GetData(), chunk.GetSampleCount());
73 | peak = std::nexttoward((float)largePeak, largePeak);
74 | }
75 | else
76 | {
77 | assert(chunk.GetFormat() == DspFormat::Float);
78 | peak = GetPeak((float*)chunk.GetData(), chunk.GetSampleCount());
79 | }
80 |
81 | // Configure limiter
82 | if (peak > 1.0f)
83 | {
84 | if (m_holdWindow <= 0)
85 | {
86 | NewTreshold(std::max(peak, 1.4f));
87 | }
88 | else if (peak > m_peak)
89 | {
90 | NewTreshold(peak);
91 | }
92 |
93 | m_holdWindow = (int64_t)m_rate * m_channels * 10; // 10 seconds
94 | }
95 |
96 | // Apply limiter
97 | if (m_holdWindow > 0)
98 | {
99 | if (chunk.GetFormat() == DspFormat::Double)
100 | {
101 | ApplyLimiter((double*)chunk.GetData(), chunk.GetSampleCount(), m_threshold);
102 | }
103 | else
104 | {
105 | assert(chunk.GetFormat() == DspFormat::Float);
106 | ApplyLimiter((float*)chunk.GetData(), chunk.GetSampleCount(), m_threshold);
107 | }
108 |
109 | m_holdWindow -= chunk.GetSampleCount();
110 | }
111 | }
112 |
113 | void DspLimiter::Finish(DspChunk& chunk)
114 | {
115 | Process(chunk);
116 | }
117 |
118 | void DspLimiter::NewTreshold(float peak)
119 | {
120 | m_peak = peak;
121 | m_threshold = std::pow(1.0f / peak, 1.0f / slope - 1.0f) - 0.0001f;
122 | DebugOut(ClassName(this), "active with", m_peak, "peak and", m_threshold, "threshold");
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/src/DspLimiter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class DspLimiter final
8 | : public DspBase
9 | {
10 | public:
11 |
12 | DspLimiter() = default;
13 | DspLimiter(const DspLimiter&) = delete;
14 | DspLimiter& operator=(const DspLimiter&) = delete;
15 |
16 | void Initialize(uint32_t rate, uint32_t channels, bool exclusive);
17 |
18 | std::wstring Name() override { return L"Limiter"; }
19 |
20 | bool Active() override;
21 |
22 | void Process(DspChunk& chunk) override;
23 | void Finish(DspChunk& chunk) override;
24 |
25 | private:
26 |
27 | void NewTreshold(float peak);
28 |
29 | bool m_exclusive = false;
30 | uint32_t m_rate = 0;
31 | uint32_t m_channels = 0;
32 |
33 | bool m_active = false;
34 | int64_t m_holdWindow = 0;
35 | float m_peak = 0.0f;
36 | float m_threshold = 0.0f;
37 | };
38 | }
39 |
--------------------------------------------------------------------------------
/src/DspMatrix.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class DspMatrix final
8 | : public DspBase
9 | {
10 | public:
11 |
12 | DspMatrix() = default;
13 | DspMatrix(const DspMatrix&) = delete;
14 | DspMatrix& operator=(const DspMatrix&) = delete;
15 |
16 | void Initialize(uint32_t inputChannels, DWORD inputMask,
17 | uint32_t outputChannels, DWORD outputMask);
18 |
19 | std::wstring Name() override { return L"Matrix"; }
20 |
21 | bool Active() override;
22 |
23 | void Process(DspChunk& chunk) override;
24 | void Finish(DspChunk& chunk) override;
25 |
26 | static DWORD GetChannelMask(const WAVEFORMATEX& format);
27 | static bool IsStereoFormat(const WAVEFORMATEX& format);
28 |
29 | private:
30 |
31 | std::array m_matrix;
32 | bool m_active = false;
33 | uint32_t m_inputChannels = 0;
34 | uint32_t m_outputChannels = 0;
35 | };
36 | }
37 |
--------------------------------------------------------------------------------
/src/DspRate.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 |
5 | #include
6 |
7 | namespace SaneAudioRenderer
8 | {
9 | class DspRate final
10 | : public DspBase
11 | {
12 | public:
13 |
14 | DspRate() = default;
15 | DspRate(const DspRate&) = delete;
16 | DspRate& operator=(const DspRate&) = delete;
17 | ~DspRate();
18 |
19 | void Initialize(bool variable, uint32_t inputRate, uint32_t outputRate, uint32_t channels);
20 |
21 | std::wstring Name() override { return L"Rate"; }
22 |
23 | bool Active() override;
24 |
25 | void Process(DspChunk& chunk) override;
26 | void Finish(DspChunk& chunk) override;
27 |
28 | void Adjust(REFERENCE_TIME time);
29 |
30 | private:
31 |
32 | enum class State
33 | {
34 | Passthrough,
35 | Constant,
36 | Variable,
37 | };
38 |
39 | DspChunk ProcessChunk(soxr_t soxr, DspChunk& chunk);
40 | DspChunk ProcessEosChunk(soxr_t soxr, DspChunk& chunk);
41 |
42 | void FinishStateTransition(DspChunk& processedChunk, DspChunk& unprocessedChunk, bool eos);
43 |
44 | void CreateBackend();
45 | soxr_t GetBackend();
46 | void DestroyBackends();
47 |
48 | soxr_t m_soxrc = nullptr;
49 | soxr_t m_soxrv = nullptr;
50 |
51 | State m_state = State::Passthrough;
52 |
53 | bool m_inStateTransition = false;
54 | std::pair m_transitionCorrelation;
55 | std::pair m_transitionChunks;
56 |
57 | uint32_t m_inputRate = 0;
58 | uint32_t m_outputRate = 0;
59 | uint32_t m_channels = 0;
60 |
61 | uint64_t m_variableInputFrames = 0;
62 | uint64_t m_variableOutputFrames = 0;
63 | uint64_t m_variableDelay = 0; // In input samples.
64 |
65 | REFERENCE_TIME m_adjustTime = 0; // Negative time - less samples, positive time - more samples.
66 | };
67 | }
68 |
--------------------------------------------------------------------------------
/src/DspTempo.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DspTempo.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | void DspTempo::Initialize(double tempo, uint32_t rate, uint32_t channels)
7 | {
8 | m_stouch.clear();
9 |
10 | m_active = false;
11 |
12 | m_rate = rate;
13 | m_channels = channels;
14 |
15 | m_tempo = tempo;
16 | m_ftempo1 = (float)tempo;
17 | m_ftempo2 = std::nexttoward(m_ftempo1, tempo);
18 | m_ftempo = m_ftempo1;
19 | m_outSamples1 = 0;
20 | m_outSamples2 = 0;
21 |
22 | if (tempo != 1.0)
23 | {
24 | m_stouch.setSampleRate(rate);
25 | m_stouch.setChannels(channels);
26 |
27 | m_stouch.setTempo(m_ftempo);
28 |
29 | //m_stouch.setSetting(SETTING_SEQUENCE_MS, 40);
30 | //m_stouch.setSetting(SETTING_SEEKWINDOW_MS, 15);
31 | //m_stouch.setSetting(SETTING_OVERLAP_MS, 8);
32 |
33 | m_active = true;
34 | }
35 | }
36 |
37 | bool DspTempo::Active()
38 | {
39 | return m_active;
40 | }
41 |
42 | void DspTempo::Process(DspChunk& chunk)
43 | {
44 | if (!m_active || chunk.IsEmpty())
45 | return;
46 |
47 | assert(chunk.GetRate() == m_rate);
48 | assert(chunk.GetChannelCount() == m_channels);
49 |
50 | // DirectShow speed is in double precision, SoundTouch operates in single.
51 | // We have to adjust it dynamically.
52 | AdjustTempo();
53 |
54 | DspChunk::ToFloat(chunk);
55 |
56 | m_stouch.putSamples((const float*)chunk.GetData(), (uint32_t)chunk.GetFrameCount());
57 |
58 | DspChunk output(DspFormat::Float, m_channels, m_stouch.numSamples(), m_rate);
59 |
60 | uint32_t done = m_stouch.receiveSamples((float*)output.GetData(), (uint32_t)output.GetFrameCount());
61 | assert(done == output.GetFrameCount());
62 | output.ShrinkTail(done);
63 |
64 | auto& outSamples = (m_ftempo == m_ftempo1) ? m_outSamples1 : m_outSamples2;
65 | outSamples += done;
66 |
67 | chunk = std::move(output);
68 | }
69 |
70 | void DspTempo::Finish(DspChunk& chunk)
71 | {
72 | if (!m_active)
73 | return;
74 |
75 | Process(chunk);
76 |
77 | m_stouch.flush();
78 | uint32_t undone = m_stouch.numSamples();
79 |
80 | if (undone > 0)
81 | {
82 | DspChunk output(DspFormat::Float, m_channels, chunk.GetFrameCount() + undone, m_rate);
83 |
84 | if (!chunk.IsEmpty())
85 | memcpy(output.GetData(), chunk.GetData(), chunk.GetSize());
86 |
87 | m_stouch.flush();
88 |
89 | uint32_t done = m_stouch.receiveSamples((float*)output.GetData() + chunk.GetSampleCount(), undone);
90 | assert(done == undone);
91 | output.ShrinkTail(chunk.GetFrameCount() + done);
92 |
93 | chunk = std::move(output);
94 | }
95 | }
96 |
97 | void DspTempo::AdjustTempo()
98 | {
99 | if (m_tempo != m_ftempo)
100 | {
101 | assert(m_tempo != m_ftempo1);
102 | assert(m_tempo != m_ftempo2);
103 |
104 | double ratio21 = std::abs((m_tempo - m_ftempo1) / (m_tempo - m_ftempo2));
105 |
106 | if (m_ftempo != m_ftempo2 &&
107 | m_outSamples1 * ratio21 - m_outSamples2 > 60 * m_rate)
108 | {
109 | DebugOut(ClassName(this), "adjusting for float/double imprecision (2), ratio", ratio21);
110 | m_ftempo = m_ftempo2;
111 | m_stouch.setTempo(m_ftempo);
112 | }
113 | else if (m_ftempo != m_ftempo1 &&
114 | m_outSamples2 - m_outSamples1 * ratio21 > 60 * m_rate)
115 | {
116 | DebugOut(ClassName(this), "adjusting for float/double imprecision (1), ratio", ratio21);
117 | m_ftempo = m_ftempo1;
118 | m_stouch.setTempo(m_ftempo);
119 | }
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/src/DspTempo.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 |
5 | #include
6 |
7 | namespace SaneAudioRenderer
8 | {
9 | class DspTempo final
10 | : public DspBase
11 | {
12 | public:
13 |
14 | DspTempo() = default;
15 | DspTempo(const DspTempo&) = delete;
16 | DspTempo& operator=(const DspTempo&) = delete;
17 |
18 | void Initialize(double tempo, uint32_t rate, uint32_t channels);
19 |
20 | std::wstring Name() override { return L"Tempo"; }
21 |
22 | bool Active() override;
23 |
24 | void Process(DspChunk& chunk) override;
25 | void Finish(DspChunk& chunk) override;
26 |
27 | private:
28 |
29 | void AdjustTempo();
30 |
31 | soundtouch::SoundTouch m_stouch;
32 |
33 | bool m_active = false;
34 |
35 | uint32_t m_rate = 0;
36 | uint32_t m_channels = 0;
37 |
38 | double m_tempo = 1.0;
39 | float m_ftempo1 = 1.0f;
40 | float m_ftempo2 = 1.0f;
41 | float m_ftempo = 1.0f;
42 | uint64_t m_outSamples1 = 0;
43 | uint64_t m_outSamples2 = 0;
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/src/DspTempo2.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DspTempo2.h"
3 |
4 | #ifndef SANEAR_GPL_PHASE_VOCODER
5 | namespace SaneAudioRenderer { void DspTempo2::ShutNoPublicSymbolsWarning() {} }
6 | #else
7 |
8 | namespace SaneAudioRenderer
9 | {
10 | void DspTempo2::Initialize(double tempo, uint32_t rate, uint32_t channels)
11 | {
12 | m_stretcher = nullptr;
13 |
14 | m_active = false;
15 | m_finish = false;
16 |
17 | m_rate = rate;
18 | m_channels = channels;
19 |
20 | if (tempo != 1.0)
21 | {
22 | try
23 | {
24 | auto options = RubberBand::RubberBandStretcher::OptionTransientsMixed |
25 | RubberBand::RubberBandStretcher::OptionProcessRealTime;
26 |
27 | m_stretcher = std::make_unique(rate, channels, options, 1.0 / tempo);
28 |
29 | m_stretcher->setMaxProcessSize(rate);
30 |
31 | m_active = true;
32 | }
33 | catch (std::bad_alloc&)
34 | {
35 | }
36 | }
37 | }
38 |
39 | bool DspTempo2::Active()
40 | {
41 | return m_active;
42 | }
43 |
44 | void DspTempo2::Process(DspChunk& chunk)
45 | {
46 | if (!m_active || chunk.IsEmpty())
47 | return;
48 |
49 | assert(chunk.GetRate() == m_rate);
50 | assert(chunk.GetChannelCount() == m_channels);
51 |
52 | DspChunk::ToFloat(chunk);
53 | m_stretcher->process(Deinterleave(chunk).data(), chunk.GetFrameCount(), m_finish);
54 |
55 | size_t outputFrames = m_stretcher->available();
56 |
57 | if (outputFrames > 0)
58 | {
59 |
60 | DspChunk output(DspFormat::Float, m_channels, outputFrames, m_rate);
61 |
62 | size_t outputDone = m_stretcher->retrieve(MarkData(output).data(), outputFrames);
63 | assert(outputDone == outputFrames);
64 |
65 | Interleave(output);
66 |
67 | chunk = std::move(output);
68 | }
69 | else
70 | {
71 | chunk = DspChunk();
72 | }
73 | }
74 |
75 | void DspTempo2::Finish(DspChunk& chunk)
76 | {
77 | if (!m_active)
78 | return;
79 |
80 | assert(!m_finish);
81 | m_finish = true;
82 |
83 | Process(chunk);
84 | }
85 |
86 | DspTempo2::DeinterleavedData DspTempo2::MarkData(DspChunk& chunk)
87 | {
88 | assert(!chunk.IsEmpty());
89 | assert(chunk.GetFormat() == DspFormat::Float);
90 |
91 | DeinterleavedData data = {};
92 |
93 | for (size_t i = 0; i < m_channels; i++)
94 | data[i] = (float*)(chunk.GetData() + chunk.GetFormatSize() * chunk.GetFrameCount() * i);
95 |
96 | return data;
97 | }
98 |
99 | DspTempo2::DeinterleavedData DspTempo2::Deinterleave(DspChunk& chunk)
100 | {
101 | assert(!chunk.IsEmpty());
102 | assert(chunk.GetFormat() == DspFormat::Float);
103 |
104 | DspChunk output(DspFormat::Float, m_channels, chunk.GetFrameCount(), m_rate);
105 | DeinterleavedData outputData = MarkData(output);
106 |
107 | float* inputData = (float*)chunk.GetData();
108 |
109 | for (size_t channel = 0; channel < m_channels; channel++)
110 | for (size_t i = 0, n = chunk.GetFrameCount(); i < n; i++)
111 | outputData[channel][i] = inputData[channel + i * m_channels];
112 |
113 | chunk = std::move(output);
114 |
115 | return outputData;
116 | }
117 |
118 | void DspTempo2::Interleave(DspChunk& chunk)
119 | {
120 | assert(!chunk.IsEmpty());
121 | assert(chunk.GetFormat() == DspFormat::Float);
122 |
123 | DspChunk output(DspFormat::Float, m_channels, chunk.GetFrameCount(), m_rate);
124 | float* outputData = (float*)output.GetData();
125 |
126 | DeinterleavedData inputData = MarkData(chunk);
127 |
128 | for (size_t channel = 0; channel < m_channels; channel++)
129 | for (size_t i = 0, n = chunk.GetFrameCount(); i < n; i++)
130 | outputData[channel + i * m_channels] = inputData[channel][i];
131 |
132 | chunk = std::move(output);
133 | }
134 | }
135 |
136 | #endif
137 |
--------------------------------------------------------------------------------
/src/DspTempo2.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifndef SANEAR_GPL_PHASE_VOCODER
4 | namespace SaneAudioRenderer { struct DspTempo2 final { void ShutNoPublicSymbolsWarning(); }; }
5 | #else
6 |
7 | #include "DspBase.h"
8 |
9 | #include
10 |
11 | namespace SaneAudioRenderer
12 | {
13 | class DspTempo2 final
14 | : public DspBase
15 | {
16 | public:
17 |
18 | DspTempo2() = default;
19 | DspTempo2(const DspTempo2&) = delete;
20 | DspTempo2& operator=(const DspTempo2&) = delete;
21 |
22 | void Initialize(double tempo, uint32_t rate, uint32_t channels);
23 |
24 | std::wstring Name() override { return L"Tempo"; }
25 |
26 | bool Active() override;
27 |
28 | void Process(DspChunk& chunk) override;
29 | void Finish(DspChunk& chunk) override;
30 |
31 | private:
32 |
33 | using DeinterleavedData = std::array;
34 |
35 | DeinterleavedData MarkData(DspChunk& chunk);
36 | DeinterleavedData Deinterleave(DspChunk& chunk);
37 | void Interleave(DspChunk& chunk);
38 |
39 | std::unique_ptr m_stretcher;
40 |
41 | bool m_active = false;
42 | bool m_finish = false;
43 |
44 | uint32_t m_rate = 0;
45 | uint32_t m_channels = 0;
46 | };
47 | }
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/DspVolume.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "DspVolume.h"
3 |
4 | #include "AudioRenderer.h"
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | bool DspVolume::Active()
9 | {
10 | return m_renderer.GetVolume() != 1.0f;
11 | }
12 |
13 | void DspVolume::Process(DspChunk& chunk)
14 | {
15 | const float volume = m_renderer.GetVolume();
16 | assert(volume >= 0.0f && volume <= 1.0f);
17 |
18 | if (volume == 1.0f || chunk.IsEmpty())
19 | return;
20 |
21 | DspChunk::ToFloat(chunk);
22 |
23 | auto data = reinterpret_cast(chunk.GetData());
24 | for (size_t i = 0, n = chunk.GetSampleCount(); i < n; i++)
25 | data[i] *= volume;
26 | }
27 |
28 | void DspVolume::Finish(DspChunk& chunk)
29 | {
30 | Process(chunk);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/DspVolume.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspBase.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class AudioRenderer;
8 |
9 | class DspVolume final
10 | : public DspBase
11 | {
12 | public:
13 |
14 | DspVolume(AudioRenderer& renderer) : m_renderer(renderer) {}
15 | DspVolume(const DspVolume&) = delete;
16 | DspVolume& operator=(const DspVolume&) = delete;
17 |
18 | std::wstring Name() override { return L"Volume"; }
19 |
20 | bool Active() override;
21 |
22 | void Process(DspChunk& chunk) override;
23 | void Finish(DspChunk& chunk) override;
24 |
25 | private:
26 |
27 | const AudioRenderer& m_renderer;
28 | };
29 | }
30 |
--------------------------------------------------------------------------------
/src/Factory.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Factory.h"
3 |
4 | #include "MyFilter.h"
5 | #include "Settings.h"
6 |
7 | namespace SaneAudioRenderer
8 | {
9 | HRESULT Factory::CreateSettings(ISettings** ppOut)
10 | {
11 | IUnknownPtr unknown;
12 | ReturnIfFailed(CreateSettingsAggregated(nullptr, &unknown));
13 | return unknown->QueryInterface(IID_PPV_ARGS(ppOut));
14 | }
15 |
16 | HRESULT Factory::CreateSettingsAggregated(IUnknown* pOwner, IUnknown** ppOut)
17 | {
18 | CheckPointer(ppOut, E_POINTER);
19 |
20 | *ppOut = nullptr;
21 |
22 | auto pSettings = new(std::nothrow) Settings(pOwner);
23 |
24 | if (!pSettings)
25 | return E_OUTOFMEMORY;
26 |
27 | pSettings->NonDelegatingAddRef();
28 |
29 | HRESULT result = pSettings->NonDelegatingQueryInterface(IID_PPV_ARGS(ppOut));
30 |
31 | pSettings->NonDelegatingRelease();
32 |
33 | return result;
34 | }
35 |
36 | HRESULT Factory::CreateFilter(ISettings* pSettings, IBaseFilter** ppOut)
37 | {
38 | IUnknownPtr unknown;
39 | ReturnIfFailed(CreateFilterAggregated(nullptr, GetFilterGuid(), pSettings, &unknown));
40 | return unknown->QueryInterface(IID_PPV_ARGS(ppOut));
41 | }
42 |
43 | HRESULT Factory::CreateFilterAggregated(IUnknown* pOwner, const GUID& guid,
44 | ISettings* pSettings, IUnknown** ppOut)
45 | {
46 | CheckPointer(ppOut, E_POINTER);
47 | CheckPointer(pSettings, E_POINTER);
48 |
49 | *ppOut = nullptr;
50 |
51 | auto pFilter = new(std::nothrow) MyFilter(pOwner, guid);
52 |
53 | if (!pFilter)
54 | return E_OUTOFMEMORY;
55 |
56 | pFilter->NonDelegatingAddRef();
57 |
58 | HRESULT result = pFilter->Init(pSettings);
59 |
60 | if (SUCCEEDED(result))
61 | result = pFilter->NonDelegatingQueryInterface(IID_PPV_ARGS(ppOut));
62 |
63 | pFilter->NonDelegatingRelease();
64 |
65 | return result;
66 | }
67 |
68 | const GUID& Factory::GetFilterGuid()
69 | {
70 | static const GUID guid = {0x2AE00773, 0x819A, 0x40FB, {0xA5, 0x54, 0x54, 0x82, 0x7E, 0x11, 0x63, 0x59}};
71 | return guid;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/Factory.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | #include "Interfaces.h"
7 |
8 | namespace SaneAudioRenderer
9 | {
10 | class Factory final
11 | {
12 | public:
13 |
14 | Factory() = delete;
15 |
16 | static HRESULT CreateSettings(ISettings** ppOut);
17 | static HRESULT CreateSettingsAggregated(IUnknown* pOwner, IUnknown** ppOut);
18 |
19 | static HRESULT CreateFilter(ISettings* pSettings, IBaseFilter** ppOut);
20 | static HRESULT CreateFilterAggregated(IUnknown* pOwner, const GUID& guid,
21 | ISettings* pSettings, IUnknown** ppOut);
22 |
23 | static const GUID& GetFilterGuid();
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/src/Interfaces.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | struct __declspec(uuid("ED41579C-C96A-4D8C-9813-856AB99F405E"))
9 | ISettings : IUnknown
10 | {
11 | STDMETHOD_(UINT32, GetSerial)() = 0;
12 |
13 | enum
14 | {
15 | OUTPUT_DEVICE_BUFFER_MIN_MS = 60,
16 | OUTPUT_DEVICE_BUFFER_MAX_MS = 1000,
17 | OUTPUT_DEVICE_BUFFER_DEFAULT_MS = 200,
18 | };
19 | STDMETHOD(SetOuputDevice)(LPCWSTR pDeviceId, BOOL bExclusive, UINT32 uBufferMS) = 0;
20 | STDMETHOD(GetOuputDevice)(LPWSTR* ppDeviceId, BOOL* pbExclusive, UINT32* puBufferMS) = 0;
21 |
22 | STDMETHOD_(void, SetAllowBitstreaming)(BOOL bAllowBitstreaming) = 0;
23 | STDMETHOD_(BOOL, GetAllowBitstreaming)() = 0;
24 |
25 | STDMETHOD_(void, SetCrossfeedEnabled)(BOOL bEnable) = 0;
26 | STDMETHOD_(BOOL, GetCrossfeedEnabled)() = 0;
27 |
28 | enum
29 | {
30 | CROSSFEED_CUTOFF_FREQ_MIN = 300,
31 | CROSSFEED_CUTOFF_FREQ_MAX = 2000,
32 | CROSSFEED_CUTOFF_FREQ_CMOY = 700,
33 | CROSSFEED_CUTOFF_FREQ_JMEIER = 650,
34 | CROSSFEED_LEVEL_MIN = 10,
35 | CROSSFEED_LEVEL_MAX = 150,
36 | CROSSFEED_LEVEL_CMOY = 60,
37 | CROSSFEED_LEVEL_JMEIER = 95,
38 | };
39 | STDMETHOD(SetCrossfeedSettings)(UINT32 uCutoffFrequency, UINT32 uCrossfeedLevel) = 0;
40 | STDMETHOD_(void, GetCrossfeedSettings)(UINT32* puCutoffFrequency, UINT32* puCrossfeedLevel) = 0;
41 |
42 | STDMETHOD_(void, SetIgnoreSystemChannelMixer)(BOOL bEnable) = 0;
43 | STDMETHOD_(BOOL, GetIgnoreSystemChannelMixer)() = 0;
44 |
45 | enum
46 | {
47 | TIMESTRETCH_METHOD_SOLA = 0,
48 | TIMESTRETCH_METHOD_PHASE_VOCODER = 1,
49 | };
50 | STDMETHOD(SetTimestretchSettings)(UINT32 uTimestretchMethod) = 0;
51 | STDMETHOD_(void, GetTimestretchSettings)(UINT32* puTimestretchMethod) = 0;
52 | };
53 | _COM_SMARTPTR_TYPEDEF(ISettings, __uuidof(ISettings));
54 |
55 | struct __declspec(uuid("03481710-D73E-4674-839F-03EDE2D60ED8"))
56 | ISpecifyPropertyPages2 : ISpecifyPropertyPages
57 | {
58 | STDMETHOD(CreatePage)(const GUID& guid, IPropertyPage** ppPage) = 0;
59 | };
60 | _COM_SMARTPTR_TYPEDEF(ISpecifyPropertyPages2, __uuidof(ISpecifyPropertyPages2));
61 | }
62 |
--------------------------------------------------------------------------------
/src/MyBasicAudio.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "MyBasicAudio.h"
3 |
4 | #include "AudioRenderer.h"
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | MyBasicAudio::MyBasicAudio(IUnknown* pUnknown, AudioRenderer& renderer)
9 | : CBasicAudio(L"SaneAudioRenderer::MyBasicAudio", pUnknown)
10 | , m_renderer(renderer)
11 | {
12 | }
13 |
14 | STDMETHODIMP MyBasicAudio::put_Volume(long volume)
15 | {
16 | if (volume < -10000 || volume > 0)
17 | return E_FAIL;
18 |
19 | float f = (volume == 0) ?
20 | 1.0f : pow(10.0f, (float)volume / 2000.0f);
21 |
22 | m_renderer.SetVolume(f);
23 |
24 | return S_OK;
25 | }
26 |
27 | STDMETHODIMP MyBasicAudio::get_Volume(long* pVolume)
28 | {
29 | CheckPointer(pVolume, E_POINTER);
30 |
31 | float f = m_renderer.GetVolume();
32 |
33 | *pVolume = (f == 1.0f) ?
34 | 0 : (long)(log10(f) * 2000.0f);
35 |
36 | assert(*pVolume <= 0 && *pVolume >= -10000);
37 |
38 | return S_OK;
39 | }
40 |
41 | STDMETHODIMP MyBasicAudio::put_Balance(long balance)
42 | {
43 | if (balance < -10000 || balance > 10000)
44 | return E_FAIL;
45 |
46 | float f = (balance == 0) ?
47 | 0.0f : pow(10.0f, (float)abs(balance) / -2000.0f);
48 |
49 | m_renderer.SetBalance(copysign(f, (float)balance));
50 |
51 | return S_OK;
52 | }
53 |
54 | STDMETHODIMP MyBasicAudio::get_Balance(long* pBalance)
55 | {
56 | CheckPointer(pBalance, E_POINTER);
57 |
58 | float f = m_renderer.GetBalance();
59 |
60 | *pBalance = (f == 0.0f) ?
61 | 0 : (long)(copysign(log10(abs(f)), f) * 2000.0f);
62 |
63 | assert(*pBalance >= -10000 && *pBalance <= 10000);
64 |
65 | return S_OK;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/MyBasicAudio.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace SaneAudioRenderer
4 | {
5 | class AudioRenderer;
6 |
7 | class MyBasicAudio final
8 | : public CBasicAudio
9 | {
10 | public:
11 |
12 | MyBasicAudio(IUnknown* pUnknown, AudioRenderer& renderer);
13 | MyBasicAudio(const MyBasicAudio&) = delete;
14 | MyBasicAudio& operator=(const MyBasicAudio&) = delete;
15 |
16 | STDMETHODIMP put_Volume(long volume) override;
17 | STDMETHODIMP get_Volume(long* pVolume) override;
18 | STDMETHODIMP put_Balance(long balance) override;
19 | STDMETHODIMP get_Balance(long* pBalance) override;
20 |
21 | private:
22 |
23 | AudioRenderer& m_renderer;
24 | };
25 | }
26 |
--------------------------------------------------------------------------------
/src/MyClock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../IGuidedReclock.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class AudioRenderer;
8 |
9 | class MyClock final
10 | : public CBaseReferenceClock
11 | , public IGuidedReclock
12 | {
13 | public:
14 |
15 | MyClock(IUnknown* pUnknown, const std::unique_ptr& renderer, HRESULT& result);
16 | MyClock(const MyClock&) = delete;
17 | MyClock& operator=(const MyClock&) = delete;
18 |
19 | DECLARE_IUNKNOWN
20 |
21 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override;
22 |
23 | REFERENCE_TIME GetPrivateTime() override;
24 |
25 | void SlaveClockToAudio(IAudioClock* pAudioClock, int64_t audioStart);
26 | void UnslaveClockFromAudio();
27 | void OffsetAudioClock(REFERENCE_TIME offsetTime);
28 | HRESULT GetAudioClockTime(REFERENCE_TIME* pAudioTime, REFERENCE_TIME* pCounterTime);
29 | HRESULT GetAudioClockStartTime(REFERENCE_TIME* pStartTime);
30 |
31 | STDMETHODIMP SlaveClock(DOUBLE multiplier) override;
32 | STDMETHODIMP UnslaveClock() override;
33 | STDMETHODIMP OffsetClock(LONGLONG offset) override;
34 | STDMETHODIMP GetImmediateTime(LONGLONG* pTime) override;
35 |
36 | private:
37 |
38 | bool CanDoGuidedReclock();
39 |
40 | int64_t GetCounterTime() { return llMulDiv(GetPerformanceCounter(), OneSecond, m_performanceFrequency, 0); }
41 |
42 | const std::unique_ptr& m_renderer;
43 |
44 | const int64_t m_performanceFrequency;
45 |
46 | IAudioClockPtr m_audioClock;
47 | int64_t m_audioStart = 0;
48 | uint64_t m_audioInitialPosition = 0;
49 | int64_t m_audioOffset = 0;
50 | int64_t m_counterOffset = 0;
51 |
52 | bool m_guidedReclockSlaving = false;
53 | double m_guidedReclockMultiplier = 1.0;
54 | int64_t m_guidedReclockStartTime = 0;
55 | int64_t m_guidedReclockStartClock = 0;
56 | };
57 | }
58 |
--------------------------------------------------------------------------------
/src/MyFilter.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Interfaces.h"
4 | #include "MyPropertyPage.h"
5 |
6 | namespace SaneAudioRenderer
7 | {
8 | class MyClock;
9 | class AudioRenderer;
10 | class MyBasicAudio;
11 | class MyPin;
12 |
13 | class MyFilter final
14 | : public CCritSec
15 | , public CBaseFilter
16 | , public ISpecifyPropertyPages2
17 | , public IStatusPageData
18 | {
19 | public:
20 |
21 | MyFilter(IUnknown* pUnknown, REFIID guid);
22 | MyFilter(const MyFilter&) = delete;
23 | MyFilter& operator=(const MyFilter&) = delete;
24 |
25 | HRESULT Init(ISettings* pSettings);
26 |
27 | DECLARE_IUNKNOWN
28 |
29 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override;
30 |
31 | int GetPinCount() override;
32 | CBasePin* GetPin(int n) override;
33 |
34 | STDMETHODIMP Stop() override;
35 | STDMETHODIMP Pause() override;
36 | STDMETHODIMP Run(REFERENCE_TIME startTime) override;
37 |
38 | STDMETHODIMP GetState(DWORD timeoutMilliseconds, FILTER_STATE* pState) override;
39 |
40 | STDMETHODIMP SetSyncSource(IReferenceClock* pClock) override;
41 |
42 | STDMETHODIMP GetPages(CAUUID* pPages) override;
43 | STDMETHODIMP CreatePage(const GUID& guid, IPropertyPage** ppPage) override;
44 |
45 | STDMETHODIMP GetPageData(bool resize, std::vector& data) override;
46 |
47 | private:
48 |
49 | template
50 | STDMETHODIMP ChangeState(PinFunction pinFunction);
51 |
52 | std::unique_ptr m_clock;
53 | //IReferenceClockPtr m_testClock;
54 | CAMEvent m_bufferFilled;
55 | std::unique_ptr m_renderer;
56 | std::unique_ptr m_basicAudio;
57 | std::unique_ptr m_pin;
58 | IUnknownPtr m_seeking;
59 | };
60 | }
61 |
--------------------------------------------------------------------------------
/src/MyPin.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace SaneAudioRenderer
4 | {
5 | class AudioRenderer;
6 |
7 | class MyPin final
8 | : public CCritSec
9 | , public CBaseInputPin
10 | {
11 | public:
12 |
13 | MyPin(AudioRenderer& renderer, CBaseFilter* pFilter, HRESULT& result);
14 | MyPin(const MyPin&) = delete;
15 | MyPin& operator=(const MyPin&) = delete;
16 |
17 | HRESULT CheckMediaType(const CMediaType* pmt) override;
18 | HRESULT SetMediaType(const CMediaType* pmt) override;
19 | HRESULT CheckConnect(IPin* pPin) override;
20 |
21 | STDMETHODIMP NewSegment(REFERENCE_TIME startTime, REFERENCE_TIME stopTime, double rate) override;
22 | STDMETHODIMP ReceiveCanBlock() override { return S_OK; }
23 | STDMETHODIMP Receive(IMediaSample* pSample) override;
24 | STDMETHODIMP EndOfStream() override;
25 |
26 | STDMETHODIMP BeginFlush() override;
27 | STDMETHODIMP EndFlush() override;
28 |
29 | HRESULT Active() override;
30 | HRESULT Run(REFERENCE_TIME startTime) override;
31 | HRESULT Inactive() override;
32 |
33 | bool StateTransitionFinished(uint32_t timeoutMilliseconds);
34 |
35 | private:
36 |
37 | bool CheckLive(IPin* pPin);
38 |
39 | FILTER_STATE m_state = State_Stopped;
40 | bool m_eosUp = false;
41 | bool m_eosDown = false;
42 |
43 | bool m_live = false;
44 |
45 | CCritSec m_receiveMutex;
46 | HANDLE m_hReceiveThread = NULL;
47 |
48 | CAMEvent m_bufferFilled;
49 | AudioRenderer& m_renderer;
50 | };
51 | }
52 |
--------------------------------------------------------------------------------
/src/MyPropertyPage.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace SaneAudioRenderer
4 | {
5 | class AudioDevice;
6 |
7 | // NOTE: This is internal interface and shouldn't be used outside of Sanear.
8 | struct __declspec(uuid("361657BC-CC1E-420A-BE7B-21C34E3D9F76"))
9 | IStatusPageData : IUnknown
10 | {
11 | STDMETHOD(GetPageData)(bool resize, std::vector& data) = 0;
12 | };
13 | _COM_SMARTPTR_TYPEDEF(IStatusPageData, __uuidof(IStatusPageData));
14 |
15 | class _declspec(uuid("7EEEDEC8-8B8E-4220-AF12-08BC0CE844F0"))
16 | MyPropertyPage final
17 | : public CUnknown
18 | , public IPropertyPage
19 | {
20 | public:
21 |
22 | static std::vector CreateDialogData(bool resize, SharedWaveFormat inputFormat, const AudioDevice* device,
23 | std::vector processors, bool externalClock, bool live,
24 | bool guidedReclock);
25 |
26 | MyPropertyPage();
27 | MyPropertyPage(HRESULT& result, IStatusPageData* pData);
28 | MyPropertyPage(const MyPropertyPage&) = delete;
29 | MyPropertyPage& operator=(const MyPropertyPage&) = delete;
30 |
31 | DECLARE_IUNKNOWN
32 |
33 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override;
34 |
35 | STDMETHODIMP SetPageSite(IPropertyPageSite* pPageSite) override;
36 | STDMETHODIMP Activate(HWND hParent, LPCRECT pRect, BOOL bModal) override;
37 | STDMETHODIMP Deactivate() override;
38 | STDMETHODIMP GetPageInfo(PROPPAGEINFO* pPageInfo) override;
39 | STDMETHODIMP SetObjects(ULONG nObjects, IUnknown** ppUnk) override;
40 | STDMETHODIMP Show(UINT cmdShow) override;
41 | STDMETHODIMP Move(LPCRECT pRect) override;
42 | STDMETHODIMP IsPageDirty() override { return S_FALSE; }
43 | STDMETHODIMP Apply() override { return S_OK; }
44 | STDMETHODIMP Help(LPCOLESTR) override { return E_NOTIMPL; }
45 | STDMETHODIMP TranslateAccelerator(MSG*) override { return E_NOTIMPL; }
46 |
47 | private:
48 |
49 | const bool m_delayedData;
50 | std::vector m_dialogData;
51 | IPropertyPageSitePtr m_pageSite;
52 | HWND m_hWindow = NULL;
53 | };
54 | }
55 |
--------------------------------------------------------------------------------
/src/MyTestClock.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "MyTestClock.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | MyTestClock::MyTestClock(IUnknown* pUnknown, HRESULT& result)
7 | : CBaseReferenceClock(L"SaneAudioRenderer::MyTestClock", pUnknown, &result)
8 | , m_performanceFrequency(GetPerformanceFrequency())
9 | {
10 | }
11 |
12 | REFERENCE_TIME MyTestClock::GetPrivateTime()
13 | {
14 | return llMulDiv(GetPerformanceCounter(), OneSecond, m_performanceFrequency, 0);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/MyTestClock.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | namespace SaneAudioRenderer
4 | {
5 | class MyTestClock final
6 | : public CBaseReferenceClock
7 | {
8 | public:
9 |
10 | MyTestClock(IUnknown* pUnknown, HRESULT& result);
11 | MyTestClock(const MyTestClock&) = delete;
12 | MyTestClock& operator=(const MyTestClock&) = delete;
13 |
14 | REFERENCE_TIME GetPrivateTime() override;
15 |
16 | private:
17 |
18 | const int64_t m_performanceFrequency;
19 | };
20 | }
21 |
--------------------------------------------------------------------------------
/src/SampleCorrection.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "SampleCorrection.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | void SampleCorrection::NewFormat(SharedWaveFormat format)
7 | {
8 | assert(format);
9 | assert(format->nSamplesPerSec > 0);
10 |
11 | if (m_format)
12 | {
13 | m_segmentTimeInPreviousFormats += FramesToTime(m_segmentFramesInCurrentFormat);
14 | m_segmentFramesInCurrentFormat = 0;
15 | }
16 |
17 | m_format = format;
18 | m_bitstream = (DspFormatFromWaveFormat(*m_format) == DspFormat::Unknown);
19 | }
20 |
21 | void SampleCorrection::NewSegment(double rate)
22 | {
23 | assert(rate > 0.0);
24 |
25 | m_rate = rate;
26 |
27 | m_segmentTimeInPreviousFormats = 0;
28 | m_segmentFramesInCurrentFormat = 0;
29 |
30 | m_lastFrameEnd = 0;
31 |
32 | m_timeDivergence = 0;
33 | }
34 |
35 | void SampleCorrection::NewDeviceBuffer()
36 | {
37 | m_freshBuffer = true;
38 | }
39 |
40 | DspChunk SampleCorrection::ProcessSample(IMediaSample* pSample, AM_SAMPLE2_PROPERTIES& sampleProps, bool realtimeDevice)
41 | {
42 | assert(m_format);
43 |
44 | DspChunk chunk(pSample, sampleProps, *m_format);
45 |
46 | if (m_bitstream)
47 | {
48 | if (m_freshBuffer && !(sampleProps.dwSampleFlags & AM_SAMPLE_SPLICEPOINT))
49 | {
50 | // Drop the sample.
51 | DebugOut(ClassName(this), "drop [", sampleProps.tStart, sampleProps.tStop, "]");
52 | chunk = DspChunk();
53 | assert(chunk.IsEmpty());
54 | }
55 | }
56 | else if (!realtimeDevice && (m_lastFrameEnd == 0 || (sampleProps.dwSampleFlags & AM_SAMPLE_TIMEDISCONTINUITY)))
57 | {
58 | if ((sampleProps.dwSampleFlags & AM_SAMPLE_STOPVALID) && sampleProps.tStop <= m_lastFrameEnd)
59 | {
60 | // Drop the sample.
61 | DebugOut(ClassName(this), "drop [", sampleProps.tStart, sampleProps.tStop, "]");
62 | chunk = DspChunk();
63 | assert(chunk.IsEmpty());
64 | }
65 | else if ((sampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) && sampleProps.tStart < m_lastFrameEnd)
66 | {
67 | // Crop the sample.
68 | const size_t cropFrames = (size_t)TimeToFrames(m_lastFrameEnd - sampleProps.tStart);
69 |
70 | if (cropFrames > 0)
71 | {
72 | DebugOut(ClassName(this), "crop", cropFrames, "frames from [",
73 | sampleProps.tStart, sampleProps.tStop, "]");
74 |
75 | chunk.ShrinkHead(chunk.GetFrameCount() > cropFrames ? chunk.GetFrameCount() - cropFrames : 0);
76 |
77 | sampleProps.tStart += FramesToTime(cropFrames);
78 | }
79 | }
80 | else if ((sampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID) && sampleProps.tStart > m_lastFrameEnd)
81 | {
82 | // Zero-pad the sample.
83 | const size_t padFrames = (size_t)TimeToFrames(sampleProps.tStart - m_lastFrameEnd);
84 |
85 | if (padFrames > 0 &&
86 | FramesToTime(padFrames) < 10 * OneSecond)
87 | {
88 | DebugOut(ClassName(this), "pad", padFrames, "frames before [",
89 | sampleProps.tStart, sampleProps.tStop, "]");
90 |
91 | chunk.PadHead(padFrames);
92 |
93 | sampleProps.tStart -= FramesToTime(padFrames);
94 | }
95 | }
96 | }
97 |
98 | AccumulateTimings(sampleProps, chunk.GetFrameCount());
99 |
100 | return chunk;
101 | }
102 |
103 | uint64_t SampleCorrection::TimeToFrames(REFERENCE_TIME time)
104 | {
105 | assert(m_format);
106 | assert(m_rate > 0.0);
107 | return (size_t)(llMulDiv(time, m_format->nSamplesPerSec, OneSecond, 0) * m_rate);
108 | }
109 |
110 | REFERENCE_TIME SampleCorrection::FramesToTime(uint64_t frames)
111 | {
112 | assert(m_format);
113 | assert(m_rate > 0.0);
114 | return (REFERENCE_TIME)(llMulDiv(frames, OneSecond, m_format->nSamplesPerSec, 0) / m_rate);
115 | }
116 |
117 | void SampleCorrection::AccumulateTimings(AM_SAMPLE2_PROPERTIES& sampleProps, size_t frames)
118 | {
119 | assert(m_format);
120 | assert(m_rate > 0.0);
121 |
122 | if (frames == 0)
123 | return;
124 |
125 | if (sampleProps.dwSampleFlags & AM_SAMPLE_TIMEVALID)
126 | m_timeDivergence = sampleProps.tStart - m_lastFrameEnd;
127 |
128 | m_segmentFramesInCurrentFormat += frames;
129 |
130 | m_lastFrameEnd = m_segmentTimeInPreviousFormats + FramesToTime(m_segmentFramesInCurrentFormat);
131 |
132 | m_freshBuffer = false;
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/src/SampleCorrection.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "DspChunk.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class SampleCorrection final
8 | {
9 | public:
10 |
11 | SampleCorrection() = default;
12 |
13 | void NewFormat(SharedWaveFormat format);
14 | void NewSegment(double rate);
15 | void NewDeviceBuffer();
16 |
17 | DspChunk ProcessSample(IMediaSample* pSample, AM_SAMPLE2_PROPERTIES& sampleProps, bool realtimeDevice);
18 |
19 | REFERENCE_TIME GetLastFrameEnd() const { return m_lastFrameEnd; }
20 | REFERENCE_TIME GetTimeDivergence() const { return m_timeDivergence; }
21 |
22 | private:
23 |
24 | void AccumulateTimings(AM_SAMPLE2_PROPERTIES& sampleProps, size_t frames);
25 |
26 | uint64_t TimeToFrames(REFERENCE_TIME time);
27 | REFERENCE_TIME FramesToTime(uint64_t frames);
28 |
29 | SharedWaveFormat m_format;
30 | bool m_bitstream = false;
31 |
32 | double m_rate = 1.0;
33 |
34 | REFERENCE_TIME m_segmentTimeInPreviousFormats = 0;
35 | uint64_t m_segmentFramesInCurrentFormat = 0;
36 |
37 | REFERENCE_TIME m_lastFrameEnd = 0;
38 |
39 | REFERENCE_TIME m_timeDivergence = 0;
40 |
41 | bool m_freshBuffer = true;
42 | };
43 | }
44 |
--------------------------------------------------------------------------------
/src/Settings.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 | #include "Settings.h"
3 |
4 | namespace SaneAudioRenderer
5 | {
6 | Settings::Settings(IUnknown* pUnknown)
7 | : CUnknown("Audio Renderer Settings", pUnknown)
8 | {
9 | }
10 |
11 | STDMETHODIMP Settings::NonDelegatingQueryInterface(REFIID riid, void** ppv)
12 | {
13 | return (riid == __uuidof(ISettings)) ?
14 | GetInterface(static_cast(this), ppv) :
15 | CUnknown::NonDelegatingQueryInterface(riid, ppv);
16 | }
17 |
18 | STDMETHODIMP_(UINT32) Settings::GetSerial()
19 | {
20 | return m_serial;
21 | }
22 |
23 | STDMETHODIMP Settings::SetOuputDevice(LPCWSTR pDeviceId, BOOL bExclusive, UINT32 uBufferMS)
24 | {
25 | if (uBufferMS < OUTPUT_DEVICE_BUFFER_MIN_MS || uBufferMS > OUTPUT_DEVICE_BUFFER_MAX_MS)
26 | return E_INVALIDARG;
27 |
28 | CAutoLock lock(this);
29 |
30 | if (m_exclusive != bExclusive ||
31 | m_buffer != uBufferMS ||
32 | (pDeviceId && m_deviceId != pDeviceId) ||
33 | (!pDeviceId && !m_deviceId.empty()))
34 | {
35 | try
36 | {
37 | m_deviceId = pDeviceId ? pDeviceId : L"";
38 | m_exclusive = bExclusive;
39 | m_buffer = uBufferMS;
40 | m_serial++;
41 | }
42 | catch (std::bad_alloc&)
43 | {
44 | return E_OUTOFMEMORY;
45 | }
46 | }
47 |
48 | return S_OK;
49 | }
50 |
51 | STDMETHODIMP Settings::GetOuputDevice(LPWSTR* ppDeviceId, BOOL* pbExclusive, UINT32* puBufferMS)
52 | {
53 | CAutoLock lock(this);
54 |
55 | if (pbExclusive)
56 | *pbExclusive = m_exclusive;
57 |
58 | if (ppDeviceId)
59 | {
60 | size_t size = sizeof(wchar_t) * (m_deviceId.length() + 1);
61 |
62 | *ppDeviceId = static_cast(CoTaskMemAlloc(size));
63 |
64 | if (!*ppDeviceId)
65 | return E_OUTOFMEMORY;
66 |
67 | memcpy(*ppDeviceId, m_deviceId.c_str(), size);
68 | }
69 |
70 | if (puBufferMS)
71 | *puBufferMS = m_buffer;
72 |
73 | return S_OK;
74 | }
75 |
76 | STDMETHODIMP_(void) Settings::SetAllowBitstreaming(BOOL bAllowBitstreaming)
77 | {
78 | CAutoLock lock(this);
79 |
80 | if (m_allowBitstreaming != bAllowBitstreaming)
81 | {
82 | m_allowBitstreaming = bAllowBitstreaming;
83 | m_serial++;
84 | }
85 | }
86 |
87 | STDMETHODIMP_(BOOL) Settings::GetAllowBitstreaming()
88 | {
89 | CAutoLock lock(this);
90 |
91 | return m_allowBitstreaming;
92 | }
93 |
94 | STDMETHODIMP_(void) Settings::SetCrossfeedEnabled(BOOL bEnable)
95 | {
96 | CAutoLock lock(this);
97 |
98 | if (m_crossfeedEnabled != bEnable)
99 | {
100 | m_crossfeedEnabled = bEnable;
101 | m_serial++;
102 | }
103 | }
104 |
105 | STDMETHODIMP_(BOOL) Settings::GetCrossfeedEnabled()
106 | {
107 | CAutoLock lock(this);
108 |
109 | return m_crossfeedEnabled;
110 | }
111 |
112 | STDMETHODIMP Settings::SetCrossfeedSettings(UINT32 uCutoffFrequency, UINT32 uCrossfeedLevel)
113 | {
114 | if (uCutoffFrequency < CROSSFEED_CUTOFF_FREQ_MIN ||
115 | uCutoffFrequency > CROSSFEED_CUTOFF_FREQ_MAX ||
116 | uCrossfeedLevel < CROSSFEED_LEVEL_MIN ||
117 | uCrossfeedLevel > CROSSFEED_LEVEL_MAX)
118 | {
119 | return E_INVALIDARG;
120 | }
121 |
122 | CAutoLock lock(this);
123 |
124 | if (m_crossfeedCutoffFrequency != uCutoffFrequency ||
125 | m_crossfeedLevel != uCrossfeedLevel)
126 | {
127 | m_crossfeedCutoffFrequency = uCutoffFrequency;
128 | m_crossfeedLevel = uCrossfeedLevel;
129 | m_serial++;
130 | }
131 |
132 | return S_OK;
133 | }
134 |
135 | STDMETHODIMP_(void) Settings::GetCrossfeedSettings(UINT32* puCutoffFrequency, UINT32* puCrossfeedLevel)
136 | {
137 | CAutoLock lock(this);
138 |
139 | if (puCutoffFrequency)
140 | *puCutoffFrequency = m_crossfeedCutoffFrequency;
141 |
142 | if (puCrossfeedLevel)
143 | *puCrossfeedLevel = m_crossfeedLevel;
144 | }
145 |
146 | STDMETHODIMP_(void) Settings::SetIgnoreSystemChannelMixer(BOOL bEnable)
147 | {
148 | CAutoLock lock(this);
149 |
150 | if (m_ignoreSystemChannelMixer != bEnable)
151 | {
152 | m_ignoreSystemChannelMixer = bEnable;
153 | m_serial++;
154 | }
155 | }
156 |
157 | STDMETHODIMP_(BOOL) Settings::GetIgnoreSystemChannelMixer()
158 | {
159 | CAutoLock lock(this);
160 |
161 | return m_ignoreSystemChannelMixer;
162 | }
163 |
164 | STDMETHODIMP Settings::SetTimestretchSettings(UINT32 uTimestretchMethod)
165 | {
166 | if (uTimestretchMethod != TIMESTRETCH_METHOD_SOLA &&
167 | uTimestretchMethod != TIMESTRETCH_METHOD_PHASE_VOCODER)
168 | {
169 | return E_INVALIDARG;
170 | }
171 |
172 | #ifndef SANEAR_GPL_PHASE_VOCODER
173 | if (uTimestretchMethod == TIMESTRETCH_METHOD_PHASE_VOCODER)
174 | return E_NOTIMPL;
175 | #endif
176 |
177 | CAutoLock lock(this);
178 |
179 | if (uTimestretchMethod != m_timestretchMethod)
180 | {
181 | m_timestretchMethod = uTimestretchMethod;
182 | m_serial++;
183 | }
184 |
185 | return S_OK;
186 | }
187 |
188 | STDMETHODIMP_(void) Settings::GetTimestretchSettings(UINT32* puTimestretchMethod)
189 | {
190 | CAutoLock lock(this);
191 |
192 | if (puTimestretchMethod)
193 | *puTimestretchMethod = m_timestretchMethod;
194 | }
195 | }
196 |
--------------------------------------------------------------------------------
/src/Settings.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Interfaces.h"
4 |
5 | namespace SaneAudioRenderer
6 | {
7 | class Settings final
8 | : public CUnknown
9 | , public ISettings
10 | , private CCritSec
11 | {
12 | public:
13 |
14 | DECLARE_IUNKNOWN
15 |
16 | Settings(IUnknown* pUnknown);
17 | Settings(const Settings&) = delete;
18 | Settings& operator=(const Settings&) = delete;
19 |
20 | STDMETHODIMP NonDelegatingQueryInterface(REFIID riid, void** ppv) override;
21 |
22 | STDMETHODIMP_(UINT32) GetSerial() override;
23 |
24 | STDMETHODIMP SetOuputDevice(LPCWSTR pDeviceId, BOOL bExclusive, UINT32 uBufferMS) override;
25 | STDMETHODIMP GetOuputDevice(LPWSTR* ppDeviceId, BOOL* pbExclusive, UINT32* puBufferMS) override;
26 |
27 | STDMETHODIMP_(void) SetAllowBitstreaming(BOOL bAllowBitstreaming) override;
28 | STDMETHODIMP_(BOOL) GetAllowBitstreaming() override;
29 |
30 | STDMETHODIMP_(void) SetCrossfeedEnabled(BOOL bEnable) override;
31 | STDMETHODIMP_(BOOL) GetCrossfeedEnabled() override;
32 |
33 | STDMETHODIMP SetCrossfeedSettings(UINT32 uCutoffFrequency, UINT32 uCrossfeedLevel) override;
34 | STDMETHODIMP_(void) GetCrossfeedSettings(UINT32* puCutoffFrequency, UINT32* puCrossfeedLevel) override;
35 |
36 | STDMETHODIMP_(void) SetIgnoreSystemChannelMixer(BOOL bEnable) override;
37 | STDMETHODIMP_(BOOL) GetIgnoreSystemChannelMixer() override;
38 |
39 | STDMETHODIMP SetTimestretchSettings(UINT32 uTimestretchMethod) override;
40 | STDMETHODIMP_(void) GetTimestretchSettings(UINT32* puTimestretchMethod) override;
41 |
42 | private:
43 |
44 | std::atomic m_serial = 0;
45 |
46 | std::wstring m_deviceId;
47 | BOOL m_exclusive = FALSE;
48 | UINT32 m_buffer = OUTPUT_DEVICE_BUFFER_DEFAULT_MS;
49 |
50 | BOOL m_allowBitstreaming = TRUE;
51 |
52 | BOOL m_sharedModePeakLimiterEnabled = FALSE;
53 |
54 | BOOL m_crossfeedEnabled = FALSE;
55 | UINT32 m_crossfeedCutoffFrequency = CROSSFEED_CUTOFF_FREQ_CMOY;
56 | UINT32 m_crossfeedLevel = CROSSFEED_LEVEL_CMOY;
57 |
58 | BOOL m_ignoreSystemChannelMixer = TRUE;
59 |
60 | UINT32 m_timestretchMethod =
61 | #ifdef SANEAR_GPL_PHASE_VOCODER
62 | TIMESTRETCH_METHOD_PHASE_VOCODER;
63 | #else
64 | TIMESTRETCH_METHOD_SOLA;
65 | #endif
66 | };
67 | }
68 |
--------------------------------------------------------------------------------
/src/pch.cpp:
--------------------------------------------------------------------------------
1 | #include "pch.h"
2 |
--------------------------------------------------------------------------------
/src/pch.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifndef NOMINMAX
4 | # define NOMINMAX
5 | #endif
6 |
7 | #include
8 |
9 | #include
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 |
18 | #include
19 |
20 | #include
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 |
33 | #include "Utils.h"
34 |
35 | namespace SaneAudioRenderer
36 | {
37 | _COM_SMARTPTR_TYPEDEF(IGlobalInterfaceTable, __uuidof(IGlobalInterfaceTable));
38 |
39 | _COM_SMARTPTR_TYPEDEF(IMMDeviceEnumerator, __uuidof(IMMDeviceEnumerator));
40 | _COM_SMARTPTR_TYPEDEF(IMMDeviceCollection, __uuidof(IMMDeviceCollection));
41 | _COM_SMARTPTR_TYPEDEF(IMMDevice, __uuidof(IMMDevice));
42 | _COM_SMARTPTR_TYPEDEF(IMMNotificationClient, __uuidof(IMMNotificationClient));
43 |
44 | _COM_SMARTPTR_TYPEDEF(IAudioClient, __uuidof(IAudioClient));
45 | _COM_SMARTPTR_TYPEDEF(IAudioRenderClient, __uuidof(IAudioRenderClient));
46 | _COM_SMARTPTR_TYPEDEF(IAudioClock, __uuidof(IAudioClock));
47 | _COM_SMARTPTR_TYPEDEF(IPropertyStore, __uuidof(IPropertyStore));
48 |
49 | _COM_SMARTPTR_TYPEDEF(IMediaSample, __uuidof(IMediaSample));
50 | _COM_SMARTPTR_TYPEDEF(IPropertyPageSite, __uuidof(IPropertyPageSite));
51 | _COM_SMARTPTR_TYPEDEF(IReferenceClock, __uuidof(IReferenceClock));
52 | _COM_SMARTPTR_TYPEDEF(IAMGraphStreams, __uuidof(IAMGraphStreams));
53 | _COM_SMARTPTR_TYPEDEF(IAMPushSource, __uuidof(IAMPushSource));
54 | }
55 |
--------------------------------------------------------------------------------