master d5a7f6f3e64f cached
53 files
252.3 KB
67.2k tokens
146 symbols
1 requests
Download .txt
Showing preview only (268K chars total). Download the full file or copy to clipboard to get everything.
Repository: rdp/virtual-audio-capture-grabber-device
Branch: master
Commit: d5a7f6f3e64f
Files: 53
Total size: 252.3 KB

Directory structure:
gitextract_thvsja40/

├── .gitignore
├── .gitmodules
├── ChangeLog.txt
├── LICENSE
├── README.TXT
├── TODO
├── downloads_have_moved_here.txt
├── how_to_setup_code.txt
├── innosetup_installer_options.iss
├── notes
├── propaganda
└── source_code/
    ├── acam/
    │   ├── Dll.cpp
    │   ├── ReadMe.txt
    │   ├── acam.def
    │   ├── acam.h
    │   ├── acam.vcxproj
    │   ├── acam.vcxproj.filters
    │   ├── acam.vcxproj.user
    │   ├── common.h
    │   ├── directshow_fillbuffer.cpp
    │   ├── directshow_stuff.cpp
    │   ├── dll_main.cpp
    │   ├── loopback-capture-helpers.cpp
    │   ├── loopback-capture.cpp
    │   ├── silence.h
    │   ├── silence_background_thread.cpp
    │   ├── silence_control.cpp
    │   ├── stdafx.cpp
    │   ├── stdafx.h
    │   ├── targetver.h
    │   └── utilities.cpp
    ├── acam_is_where_all_the_code_is
    ├── startup_debug_options
    ├── synth_deprecated/
    │   ├── Synth.vcxproj
    │   ├── Synth.vcxproj.filters
    │   ├── Synth.vcxproj.user
    │   ├── dynsrc.cpp
    │   ├── dynsrc.h
    │   ├── isynth.h
    │   ├── loopback-capture-helpers.cpp
    │   ├── loopback-capture.cpp
    │   ├── resource.h
    │   ├── synth.cpp
    │   ├── synth.def
    │   ├── synth.h
    │   ├── synth.rc
    │   ├── synth.sln
    │   ├── synth.vcproj
    │   ├── synthprp.cpp
    │   ├── synthprp.h
    │   └── useless_synth.cpp
    ├── virtual audio output sniffer.sln
    └── yo.GRF

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
source_code/.vs/**
source_code/Debug/*
!source_code/Debug/audio_sniffer.dll
source_code/Release/*
!source_code/Release/audio_sniffer.dll
source_code/x64/Debug/*
!source_code/x64/Debug/audio_sniffer.dll
source_code/x64/Release/*
!source_code/x64/Release/audio_sniffer-x64.dll
source_code/acam/Debug/*
source_code/acam/Release/*
source_code/acam/x64/Release/*
source_code/acam/x64/Debug/*



================================================
FILE: .gitmodules
================================================
[submodule "screen-capture-recorder-to-video-windows-free"]
	path = screen-capture-recorder-to-video-windows-free
	url = https://rdp@github.com/rdp/screen-capture-recorder-to-video-windows-free.git


================================================
FILE: ChangeLog.txt
================================================
0.4.6:
  possible async fix LOL

0.4.5:
  possible async fix?
  UI user friendly fixes
  
0.4.4:
  UI fix for selecting devices

0.4.3:
  cleanup UI

0.4.2:
  updated to latest shortcuts
  minor ui improvements

0.4.1:
  fix it to not use as much cpu win. 8 [untested]

0.4.0
  hopefully windows 8 friendlier...

0.3.14
  icons hopefully work after poor previous distro

0.3.13

  work with FMLE again <sigh>

0.3.12
?
  
0.3.11

actually work with ffmpeg (scripts)

0.3.10

actually end ffmpeg's now

0.3.9

Accomodate for cmd.exe's redirect failures better (I hope).  I.e. let the program start.

Try to write debug outputs to a consistent place now.

Allow for spaces in dshow devices.

0.3.8

5.1 support now. If you have an ASUS Xonar card you may need to "disable gx" (the little gx green-light-button in the xonar control dock).

0.3.7

make compatible with FMLE now [hopefully], minor cleanups, but FMLE still "freezes" a lot I'm not sure why.

0.3.6

hopefully fix ffmpeg complaining like:

[libmp3lame @ 00670aa0] Que input is backward in time
Audio timestamp 329016 < 329026 invalid, cliping00:05:29.05 bitrate= 738.6kbits/s
[libmp3lame @ 00670aa0] Que input is backward in time


0.3.5

bug fixes in recording

0.3.4

can also record to ac3/video now
includes the 64 bit device now, too.

0.3.3 

cleaner recorder, add broadcast links, allow xp users to install it, device didn't change at all

0.3.2 

 fix for 64 bit windows, fix button recording

0.3.1

new program icons, new record option

0.3.0

Fix output for 48000 Hz etc. Sweet!

0.2.10 

Fix installer.

0.2.9 5/8/12

  move an assertion, also we use a more "directshowy" fillbuffer now, which...is probably wrong but hey :P
  more debug logs

0.2.8 2-21-12
  64 bit release kind of

0.2.7 1-5-12
  some minor directshow stuff has been updated, I believe

0.2.6
  some stuff from earlier, like adding bigger buffers and setting it to the graph's timestamp.

0.2.3: better timestamps barely

0.2.2: rename program files icon, new README

0.2.1: slightly better gui

0.2.0: make the capture thread realtime priority (better performance), add some record scripts, make timestamps match up now [I think this is right]

================================================
FILE: LICENSE
================================================
Contact me about a (free) open source license (MIT ?).

Basically I can release the code under "some license", but it cannot be the GPL, or so I'm told:
http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/a3e8f60b-39e4-4621-837b-50a9a9a469b7

In essence, since its its own DLL (and I hereby grant license to distribute it free of charge, no warranty given of course) you can use it "verbatim" in your project, so you don't need to worry too much about its license per se, since it's "its own dll" project.

Cheers!


================================================
FILE: README.TXT
================================================
This is an audio capture device allowing you to capture all the "wave out sound" that is playing on your speakers 
(i.e. record what you hear) for Windows 7/Vista.  Windows XP users please read the "history" section
for something else you can try in its place.

NB THAT IF YOU WANT TO USE WITH SCREEN RECORDING THEN PLEASE INSTALL
THE MORE FULL FEATURED 
https://github.com/rdp/screen-capture-recorder-to-video-windows-free

== Installation ==

To use, download+install from here: 

http://sourceforge.net/projects/screencapturer/files

(it says "on screen capture recorder"
then use it via its included start menu utilities "start menu/windows orb -> screen capturer -> ...", or use it
as input to any other program that can take directshow devices as an input.

== Usage ==

Example: VLC media player: media [menu] -> open capture device -> select capture audio device "virtual-audio-capturer"

Example: ffmpeg (to save audio to file yo.mp3 from what is currently playing):
$ ffmpeg  -f dshow -i audio="virtual-audio-capturer" yo.mp3

(also see https://github.com/rdp/screen-capture-recorder-program if you want to stream your desktop with audio
as well or capture it or the like)

NB that you'll need java JRE previously installed to use the included helper apps.

== Troubleshooting/Contact/feature requests ==

Basically, if you have a problem/feature request (ex: recording multiple audio at the same time, adding ability to strip silence, etc.), ask!

rogerdpack@gmail.com or mailing list http://groups.google.com/group/roger-projects
Or submit an idea/feature request to our uservoice: http://rdp.uservoice.com

Also note that VLC directshow input might need buffers of at least 40 or 50 ms or it fails for some reason.  But trying even higher might help.

Notes from users:

"I was able to reduce the VLC delay messages by changing the output frame rate from 30 to 24 and increasing the dshow buffer from 200 to 20000" (you shouldn't need to though).

If I make the "PlayOn Virtual Audio Device" or the "Virtual Audio Cable" the Playback Default device instead of the Realtek speakers all the problems with your filter go away. So it would seem the problem is really with the Realtek Driver. 

If it doesn't work well for you (of course please report this fact), then you may be able to turn on "record what you hear"/"wave out mix" for your system,
see "alternatives".

If that also doesn't work then you could use a small audio cable to connect your input jack with your output jack,
and then record using that.  See end section of "alternatives".


If you use it in VLC you'll need a directshow cache of at least 40ms, for whatever reason.
Also note that it's tuned set to work best for recording "what you hear" 
if this doesn't work for you then ping me I maybe could add a more "realtime" option or 
something.
Basically any feedback welcome, if it doesn't work.
Also note that if you turn down your system volume within windows, it will still continue recording
or playing, as apparently it captures it at "normal volume" regardless of how high your speaker output is.
Any feedback welcome, including feature requests like "support more audio channels than 2".

If you want a smaller download you can just download the file source_code\Release\audio_sniffer.ax then run regsvr32 audio_sniffer.ax on it as an admin user, or use the "just device" distro.


= History/XP users/Alternatives =

Basically, with windows XP, you can typically already "record what you hear"
Run sndvol32 (Start menu -> Accessories -> Volume/Audio), choose options [menu] -> properties -> recording radio button, click ok, 
now click the "select" checkbox underneath "Wave Out Mix"

Now with for example VLC choose "Open Capture Device" -> Audio Device Name -> select "your soundcard's name" (other
programs just select your soundcard's name).

With Windows Vista/7, for some reason many sound card drivers do not include this as an option.
Some do though. You can check if yours already does by following instructions here:
http://downloadsquad.switched.com/2007/01/15/how-to-enable-wave-out-recording-in-vista
You may want to download and install new audio drivers first before looking for it, sometimes that helps.

If you're in Vista/Windows 7 and see a "Wave Out Mix" following the above instructions
then you're good to go: enable it, and you can use it (you thus don't need virtual-audio-capture-grabber-device at
all).

If you don't see it then you're in luck this, device is for you.
Windows Vista/7 offer a new interface called a "loopback" adapter that captures the outgoing audio just
as it is sent to your speakers [1].

This little utility captures the loopback audio and offers it to you as an input device
that you can then record (it's captured as a directshow audio capture device, if that means anything to you).
VLC can use this to record, for example.  There are some example apps included with this package.

Basically I programmed this as an open source (free) competitor to virtual audio cable.
Ping me if you want me to convert it into a "real" kernel level audio device so that any program can use it,
not just directshow compatible ones.
Ping me if you want an easier "start/stop" recorder, too.

Another option is "If your sound card doesn't have the option to record what you hear, 
use a cable (with 3.5mm headphone jacks on both ends) to connect the line out of your 
sound card to the line in (using a splitter if you need to be able to hear what you're doing, 
and disabling mic boost if you use a microphone input)."

But that's hardware and this is a software answer :)

== related ==

There are a handful of (mostly closed source) similar projects, some with more functionality <heh>
see http://superuser.com/questions/98720/is-there-a-free-or-open-source-equivalent-to-vac

== building ==

If you want to hack on the source code see the file how_to_setup_code.txt

== Attribution ==

Some source code originally from the windows SDK samples, some based on [1]
So you'll probably need to install the Windows SDK before playing around with the source code, legally.

Enjoy!

[1] http://blogs.msdn.com/b/matthew_van_eerde/archive/2008/12/16/sample-wasapi-loopback-capture-record-what-you-hear.aspx


================================================
FILE: TODO
================================================
== actually do==
  a "real" kernel level receive from driver
    esp. if I ever need buffering in dshow, intead...

	it does not record wav right?!
	
	
if no audio device, return -1 or what not...

== maybe ==

  simpler/easier "just audio straight" GUI recorder...

== meh/never ==

it can be set to 24 bit audio if their input "is" 24 bit audio? maybe?

it doesn't complain whn I choose an unwritable dir and writing fails?  It also displays as "recording to /\" if I choose the base?  

bad icons? background console?

this gui setup is awkward...

new name?
  new web page/real web page

provide a "straight -> 2" pin always, for those 5.1'ers
  provide a "32 bit" pin

VAC: use real mutex no sleep(1)

2 pins, one with 32 bit audio :)

some thing that shows the current "bars" of how much it could/would be capturing...

figure out/debug pauses in FME when clicking "stop"...huh?

faster script startup speeds?

One feature I had thought of would be a "strip trailing silence" option or the like.  I know if I were recording things I might like it :)
Another option that might be useful/interesting might be to record/merge several audio input streams at a time.  This might be useful for recording skype calls so you can get the microphone as well as the "audio out".

  copy broadcaster here I guess?

  fix "everybody's bug"
      sleep 0's?
      reproduce?
      timestamps offset with a maximum end time?
     max(should, real) etc.!
      maybe it's fixed/ok? http://msdn.microsoft.com/en-us/library/windows/desktop/dd407208(v=vs.85).aspx

	  maybe something like VAC's usefulness for gamers or something? 

try "mixing" of several? http://msdn.microsoft.com/en-us/library/windows/hardware/ff537517%28v=vs.85%29.aspx
  
system tray "start" "stop"

figure out a way to stream to say ps3: http://superuser.com/questions/44629/application-to-stream-any-audio-to-upnp-device-xbox-360
  have an "easy streamer" option
    or just have screen capture so it can stream, too :P
    
have a "real" webpage for it so I can track analytics/adsense

do the propaganda file
  also propaganda something like "record what you hear program" or whatever to compete with freecorder and the like

can "convert" any audio file to an media player friendlier mp3 :)

higher quality, like more than 2 tracks/44Khz [possible?]

work when paused (esp. VLC)...hmm...do we need a realtime option? single-threaded m/b?
  actually...in this instance shouldn't I be calculating my own timestamps, starting from when I first got non discontinuous data? hmm...
   pass in the current ref time...hmm...or maybe if the buffer is too large I arbitrarily dump some of it?  I don't accomodate VLC pause but 
   maybe I'm ok realtime still, as is currently?  
  
real ddk thing [if anybody asks for it]

== notes ==

note: the silence thing I think works...based on not hitting that line...
note: output setting volume "doesn't" matter...


================================================
FILE: downloads_have_moved_here.txt
================================================
please download releases from here (it is packaged within it):

https://github.com/rdp/screen-capture-recorder-to-video-windows-free

================================================
FILE: how_to_setup_code.txt
================================================
Install Windows 10 SDK and at least Visual Studio Express 2019

The directshow baseclasses example is no longer part of the Windows SDK. Get
the samples by cloning https://github.com/microsoft/Windows-classic-samples 
to D:\build

mkdir D:\build
cd /d D:\build
git clone https://github.com/microsoft/Windows-classic-samples

Build directshow baseclasses from the SDK: 
Open 
D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses\baseclasses.sln
in Visual Studio, let Visual Studio upgrade the version and build
it (all combinations Debug x86, Release x86, x64... especialy for the platform you want to build 
audio_sniffer.dll for).

Clone the virtual-audio-capture-grabber-device repository

cd /d D:\build
git clone https://github.com/rdp/virtual-audio-capture-grabber-device
cd virtual-audio-capture-grabber-device
git submodule update --init --recursive

then open the visual studio project file \source_code\acam\acam.vcxproj 

let Visual Studio upgrade the version and build it.

It outputs a .dll file that you "register" via (in administrator console) 
$ regsvr32 XXX.dll (and unregister when you're done with regsvr32 /u XXX.dll)

In essence this is the "WASAPI loopback" sample
https://blogs.msdn.microsoft.com/matthew_van_eerde/2008/12/16/sample-wasapi-loopback-capture-record-what-you-hear/

combined with the "capture source filter" http://tmhare.mvps.org/downloads.htm but with many improvements :)

So go to those two to learn the basics.

This is meant to provide a "directshow filter" you can use in your graph, not a demo of how to do graphs.


================================================
FILE: innosetup_installer_options.iss
================================================
; use the innosetup from screen-capturer instead now instead of this one...even though "it's" the submodule, that's how its paths are setup as of today...

================================================
FILE: notes
================================================
notes:

= 5.1 =

with "gx" enabled, I could still capture 5.1 when playing a file through WMP (and it could play in 5.1).
with "gx" disabled, SDL_Audio couldn't create a 5.1 output
with "right click and test" from control panel, with or without gx enabled, could capture.
Maybe it's an openSDL bug? :)
should still report it to ASUS though...in 5.1 with GX enabled, it does not capture wave's played by ffplay (even stereo).
 
= the need for "true" =
 
"C:\Programs\VLC TEST 1.1.10\vlc.exe" -vvv dshow:// --sout=#transcode{venc=ffmpeg,vcodec=mp2v,vb=10000,fps=30,scale=0.5,width=1280,acodec=mp3,ab=192,channels=2,samplerate=44100,soverlay}:std{access=http,mux=ts,dst=:8081} --no-sout-rtp-sap --no-sout-standard-sap --ttl=1 --sout-keep  :dshow-vdev=screen-capture-recorder :dshow-adev=virtual-audio-capturer  :dshow-caching=0
  I think play it with VLC, or with mplayer, and/or substitute VAC with it, see what happens.
   check for "tearing" and out of sync audio...
  
 = random =
 
 increase dshow-caching=200 to dshow-caching=900 ?
 
 
ng VLC 1.0.0 native, w

disable "cool'n'quiet"
  Changing back to High Performance Power Plan is a workaround to fix it, but consumes a lot more energy and produces more heat.



subtracting at beginning didn't help it...

adding "sleeps"
resulted in this message very fast:
...
main debug: Decoder buffering done in 0 ms
main warning: received buffer in the future
main warning: received buffer in the future
main warning: PTS is out of range (-10000), dropping buffer
main warning: PTS is out of range (-21000), dropping buffer
main warning: PTS is out of range (-32000), dropping buffer
main warning: output date isn't PTS date, requesting resampling (68000)
*repeat* with similar numbers.

"normal" doesn't have the output date isn't PTS date message, just
  main warning: buffer is 40569 late, triggering upsampling
  main warning: resampling stopped after 5324000 usec (drift: -1875)
  after awhile

MIN() didn't help VLC

with "choose the MAX I know what you want!:"
creeps up,
tons of

main warning: received buffer in the future
main warning: PTS is out of range (-10000), dropping buffer
main warning: PTS is out of range (-33219), dropping buffer
main warning: buffer is 68850 late, triggering upsampling
main warning: output date isn't PTS date, requesting resampling (58561)
main warning: audio drift is too big (120953), dropping buffer
main warning: timing screwed, stopping resampling
main warning: buffer is 110795 late, triggering upsampling
main warning: audio drift is too big (120316), dropping buffer
main warning: output date isn't PTS date, requesting resampling (45000)
main warning: audio drift is too big (155214), dropping buffer


with "subtract":

main debug: Buffering 80%
main debug: Buffering 90%
main debug: Stream buffering done (100 ms in 110 ms)
main debug: Decoder buffering done in 0 ms
main warning: received buffer in the future
main warning: PTS is out of range (-10000), dropping buffer
main warning: PTS is out of range (-33219), dropping buffer
main warning: PTS is out of range (-9841), dropping buffer
main warning: PTS is out of range (-18841), dropping buffer
main warning: output date isn't PTS date, requesting resampling (40159)
main warning: buffer is 68108 late, triggering upsampling
main warning: output date isn't PTS date, requesting resampling (45000)
main warning: resampling stopped after 7688000 usec (drift: -40807)
main warning: buffer is 40966 late, triggering upsampling
main warning: output date isn't PTS date, requesting resampling (45000)
main warning: resampling stopped after 5839000 usec (drift: -43702)
main warning: buffer is 43860 late, triggering upsampling
weird weird stuff there...gah!


normal "set it like they tell me to:"

main debug: Buffering 71%
main debug: Buffering 81%
main debug: Buffering 91%
main debug: Stream buffering done (101 ms in 95 ms)
main debug: Decoder buffering done in 0 ms
main warning: PTS is out of range (-10000), dropping buffer
main warning: PTS is out of range (-20158), dropping buffer
main warning: PTS is out of range (-30317), dropping buffer

after a long while:

main warning: buffer is 40176 late, triggering upsampling
main warning: output date isn't PTS date, requesting resampling (44524)
main warning: resampling stopped after 5862000 usec (drift: -42776)
main warning: buffer is 42777 late, triggering upsampling
main warning: resampling stopped after 6079000 usec (drift: 765)
main warning: output date isn't PTS date, requesting resampling (45000)
main warning: buffer is 44792 late, triggering upsampling
main warning: resampling stopped after 6225000 usec (drift: 1394)




threaded:

with 5 other threads, dual core, they both seem to start giving bad feedback, possibly single threaded with smaller sizes [?]

with high prioritied single thread:  4480, some big though...seems as good as single thread maybe...

seemed that it avoided discontinuity messages even if "lots" of them were running at once [!]
  unless one had to pause to delete a file, then it could get it.


virtual "they can play into me:"
  http://social.msdn.microsoft.com/Forums/en-AU/wdk/thread/5dce267b-d452-4d1c-ad18-0c5b6edcff5f

================================================
FILE: propaganda
================================================
waveout mix 1600
audio sniffer 390
record what you hear 12,000
virtual audio interface 320
audio loopback 1900
record speakers 12,100

audio capture 246_000
virtual audio 135_000
audio grabber 165,000

virtual audio capture grabber device

alternative.to virtual audio cable

propaganda from the propaganda fella

http://superuser.com/questions/190093/how-to-play-mp3-files-into-the-microphone-input
http://www.google.com/search?rlz=1C1SKPL_enUS426US426&sourceid=chrome&ie=UTF-8&q=record+what+you+hear+windows+7&safe=active

================================================
FILE: source_code/acam/Dll.cpp
================================================


================================================
FILE: source_code/acam/ReadMe.txt
================================================
TODO:

msvad: yeah do it some day LOL

notes:
big buffer: blips 2, 3
a little "fast forward snip" at the beginning when it's catching up (and has tons of blips)...

with threads 1, full size:
  a few fast forwards...


with threads 2:
lots of fast forward blips at the beginning, blips through, "stumbles forward"

with threads 2, actually using it, still just 2 blips
I think it's ok to use.

================================================
FILE: source_code/acam/acam.def
================================================
EXPORTS
    DllGetClassObject PRIVATE
    DllCanUnloadNow PRIVATE
    DllRegisterServer PRIVATE
    DllUnregisterServer PRIVATE

================================================
FILE: source_code/acam/acam.h
================================================
// The following ifdef block is the standard way of creating macros which make exporting 
// from a DLL simpler. All files within this DLL are compiled with the ACAM_EXPORTS
// symbol defined on the command line. This symbol should not be defined on any project
// that uses this DLL. This way any other project whose source files include this file see 
// ACAM_API functions as being imported from a DLL, whereas this DLL sees symbols
// defined with this macro as being exported.
#ifdef ACAM_EXPORTS
#define ACAM_API __declspec(dllexport)
#else
#define ACAM_API __declspec(dllimport)
#endif

#include <streams.h>
#include <dllsetup.h>
#include <stdio.h>
#include <Windows.h>
#include "common.h"
#include <assert.h>

//extern CCritSec m_cSharedState; // unused

// This class is exported from the acam.dll
class ACAM_API Cacam {
public:
	Cacam(void);
	// TODO: add your methods here.
};

extern ACAM_API int nacam;

ACAM_API int fnacam(void);

EXTERN_C const GUID CLSID_VirtualCam; // reuse it...

// the "parent" class
class CVCam : public CSource // not needed "public IMediaFilter" since CSource is already that
{
public:
    //////////////////////////////////////////////////////////////////////////
    //  IUnknown
    //////////////////////////////////////////////////////////////////////////
    static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);

    IFilterGraph *GetGraph() {return m_pGraph;};

    //////////////////////////////////////////////////////////////////////////
    //  IMediaFilter overrides [added]
    //////////////////////////////////////////////////////////////////////////
    STDMETHODIMP Run(REFERENCE_TIME tStart); // it does call this...
    STDMETHODIMP GetState(DWORD dw, FILTER_STATE *pState);
    STDMETHODIMP Pause();

	//protected:

   // IReferenceClock *m_pClock; // wrong place I think

	// CBaseFilter
	STDMETHODIMP Stop();

private:
    CVCam(LPUNKNOWN lpunk, HRESULT *phr);
};

// child
// I think stream means "a pin" as it were...
class CVCamStream : public CSourceStream, public IAMStreamConfig, public IKsPropertySet, public IAMBufferNegotiation, public IAMFilterMiscFlags //IAMPushSource
{
public:

    //////////////////////////////////////////////////////////////////////////
    //  IUnknown
    //////////////////////////////////////////////////////////////////////////
    STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
    STDMETHODIMP_(ULONG) AddRef() { return GetOwner()->AddRef(); }                                                          \
    STDMETHODIMP_(ULONG) Release() { return GetOwner()->Release(); }

    //////////////////////////////////////////////////////////////////////////
    //  IQualityControl
    //////////////////////////////////////////////////////////////////////////
    STDMETHODIMP Notify(IBaseFilter * pSender, Quality q);

    //////////////////////////////////////////////////////////////////////////
    //  IAMStreamConfig
    //////////////////////////////////////////////////////////////////////////
    HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt);
    HRESULT STDMETHODCALLTYPE GetFormat(AM_MEDIA_TYPE **ppmt);
    HRESULT STDMETHODCALLTYPE GetNumberOfCapabilities(int *piCount, int *piSize);
    HRESULT STDMETHODCALLTYPE GetStreamCaps(int iIndex, AM_MEDIA_TYPE **pmt, BYTE *pSCC);

	// IAMPushSource [not implemented yet]
	/*HRESULT STDMETHODCALLTYPE GetLatency(REFERENCE_TIME *in) {return S_OK;};
	HRESULT STDMETHODCALLTYPE GetPushSourceFlags(ULONG *in){return S_OK;};
	HRESULT STDMETHODCALLTYPE SetPushSourceFlags(ULONG) {return S_OK;};
	HRESULT STDMETHODCALLTYPE SetStreamOffset(REFERENCE_TIME) { return E_FAIL; }
	HRESULT STDMETHODCALLTYPE GetStreamOffset(REFERENCE_TIME *) {return S_OK;};
	HRESULT STDMETHODCALLTYPE GetMaxStreamOffset(REFERENCE_TIME *) {return S_OK;};
	HRESULT STDMETHODCALLTYPE SetMaxStreamOffset(REFERENCE_TIME) {return S_OK;};*/

    //////////////////////////////////////////////////////////////////////////
    //  IKsPropertySet
    //////////////////////////////////////////////////////////////////////////
    HRESULT STDMETHODCALLTYPE Set(REFGUID guidPropSet, DWORD dwID, void *pInstanceData, DWORD cbInstanceData, void *pPropData, DWORD cbPropData);
    HRESULT STDMETHODCALLTYPE Get(REFGUID guidPropSet, DWORD dwPropID, void *pInstanceData,DWORD cbInstanceData, void *pPropData, DWORD cbPropData, DWORD *pcbReturned);
    HRESULT STDMETHODCALLTYPE QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport);
    
    //////////////////////////////////////////////////////////////////////////
    //  CSourceStream
    //////////////////////////////////////////////////////////////////////////
    HRESULT FillBuffer(IMediaSample *pms);
    HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties);
    HRESULT CheckMediaType(const CMediaType *pMediaType);
    HRESULT GetMediaType(int iPosition, CMediaType *pmt);
    HRESULT SetMediaType(const CMediaType *pmt);
    HRESULT OnThreadCreate(void);
    HRESULT OnThreadDestroy(void);
	/* don't seem to get called... */
    HRESULT Stop(void);
    HRESULT Exit(void);
    HRESULT Inactive(void); // ondisconnect :)

    CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName);
    ~CVCamStream();
    CRefTime     m_rtPreviousSampleEndTime;


	// IAMBufferNegotiation -- never gets called...
	HRESULT STDMETHODCALLTYPE SuggestAllocatorProperties( /* [in] */ const ALLOCATOR_PROPERTIES *pprop);
    HRESULT STDMETHODCALLTYPE GetAllocatorProperties( ALLOCATOR_PROPERTIES *pprop);

	// IAMFilterMiscFlags -- never gets called...
	ULONG STDMETHODCALLTYPE GetMiscFlags() { return AM_FILTER_MISC_FLAGS_IS_SOURCE; }

private:
    CVCam *m_pParent;
    // unused now? REFERENCE_TIME m_rtLastTime;
    HBITMAP m_hLogoBmp;
    // IReferenceClock *m_pClock; // did we ever used to set this up?

	HRESULT setAsNormal(CMediaType *pmt);

};


================================================
FILE: source_code/acam/acam.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{B6830EAD-C98E-490D-8999-CAA246788BF7}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <RootNamespace>acam</RootNamespace>
    <ProjectName>audio_sniffer</ProjectName>
    <WindowsTargetPlatformVersion>10.0.22000.0</WindowsTargetPlatformVersion>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <CharacterSet>Unicode</CharacterSet>
    <PlatformToolset>v142</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <CharacterSet>Unicode</CharacterSet>
    <PlatformToolset>v142</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <PlatformToolset>v142</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
    <PlatformToolset>v142</PlatformToolset>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
    <LibraryPath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses\Debug;$(WindowsSDK_LibraryPath_x86);$(LibraryPath);$(UniversalCRT_LibraryPath_x86)</LibraryPath>
    <IncludePath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses;$(IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(VC_IncludePath)</IncludePath>
    <TargetExt>.dll</TargetExt>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LinkIncremental>true</LinkIncremental>
    <LibraryPath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses\x64\Debug;$(WindowsSDK_LibraryPath_x64);$(LibraryPath);$(UniversalCRT_LibraryPath_x64)</LibraryPath>
    <IncludePath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses;$(WindowsSDK_IncludePath);$(IncludePath);$(UniversalCRT_IncludePath);$(VC_IncludePath)</IncludePath>
    <TargetExt>.dll</TargetExt>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
    <IncludePath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses;$(IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(VC_IncludePath)</IncludePath>
    <LibraryPath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses\Release;$(WindowsSDK_LibraryPath_x86);$(LibraryPath);$(UniversalCRT_LibraryPath_x86)</LibraryPath>
    <TargetExt>.dll</TargetExt>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LinkIncremental>false</LinkIncremental>
    <IncludePath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses;$(IncludePath);$(WindowsSDK_IncludePath);$(UniversalCRT_IncludePath);$(VC_IncludePath)</IncludePath>
    <LibraryPath>D:\Build\Windows-classic-samples\Samples\Win7Samples\multimedia\directshow\baseclasses\x64\Release;$(WindowsSDK_LibraryPath_x64);$(LibraryPath);$(UniversalCRT_LibraryPath_x64)</LibraryPath>
    <TargetExt>.dll</TargetExt>
    <TargetName>audio_sniffer-x64</TargetName>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ACAM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalDependencies>strmbasd.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <ModuleDefinitionFile>acam.def</ModuleDefinitionFile>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <ClCompile>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ACAM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalDependencies>strmbasd.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <ModuleDefinitionFile>acam.def</ModuleDefinitionFile>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ACAM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <AdditionalDependencies>strmbase.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Avrt.lib;%(AdditionalDependencies);</AdditionalDependencies>
      <ModuleDefinitionFile>acam.def</ModuleDefinitionFile>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>Use</PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ACAM_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <AdditionalDependencies>strmbase.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;Avrt.lib;%(AdditionalDependencies);</AdditionalDependencies>
      <ModuleDefinitionFile>acam.def</ModuleDefinitionFile>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <None Include="ReadMe.txt" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="acam.h" />
    <ClInclude Include="common.h" />
    <ClInclude Include="silence.h" />
    <ClInclude Include="stdafx.h" />
    <ClInclude Include="targetver.h" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="directshow_fillbuffer.cpp" />
    <ClCompile Include="directshow_stuff.cpp" />
    <ClCompile Include="loopback-capture-helpers.cpp" />
    <ClCompile Include="loopback-capture.cpp" />
    <ClCompile Include="dll_main.cpp">
      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
      </PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
      </PrecompiledHeader>
      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
      <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
      </PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
      </PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="silence_background_thread.cpp" />
    <ClCompile Include="silence_control.cpp" />
    <ClCompile Include="stdafx.cpp">
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
    </ClCompile>
    <ClCompile Include="utilities.cpp" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

================================================
FILE: source_code/acam/acam.vcxproj.filters
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <None Include="ReadMe.txt" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="stdafx.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="targetver.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="acam.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="common.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="silence.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="stdafx.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="loopback-capture.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="loopback-capture-helpers.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="directshow_stuff.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="directshow_fillbuffer.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="dll_main.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="utilities.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="silence_control.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="silence_background_thread.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
</Project>

================================================
FILE: source_code/acam/acam.vcxproj.user
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LocalDebuggerCommand>C:\installs\graphstudionext.exe</LocalDebuggerCommand>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
    <LocalDebuggerCommandArguments>c:\dev\ffmpeg\audio\audio_only.grf</LocalDebuggerCommandArguments>
    <LocalDebuggerWorkingDirectory>c:\dev\ffmpeg\audio</LocalDebuggerWorkingDirectory>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LocalDebuggerCommand>C:\Program Files (x86)\VideoLAN\VLC\vlc.exe</LocalDebuggerCommand>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LocalDebuggerCommand>c:\vids\ffmpeg.exe</LocalDebuggerCommand>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LocalDebuggerCommandArguments>-f dshow -r 4 -i video=screen-capture-recorder:audio=virtual-audio-capturer -y yo.mp4</LocalDebuggerCommandArguments>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <LocalDebuggerWorkingDirectory>c:\vids</LocalDebuggerWorkingDirectory>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LocalDebuggerCommand>C:\installs\ffmpeg-20160415-git-21acc4d-win64-static\bin\ffmpeg.exe</LocalDebuggerCommand>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LocalDebuggerCommandArguments>-f dshow -i audio=virtual-audio-capturer -y out.mp3</LocalDebuggerCommandArguments>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <LocalDebuggerWorkingDirectory>c:\dev</LocalDebuggerWorkingDirectory>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
  </PropertyGroup>
</Project>

================================================
FILE: source_code/acam/common.h
================================================
#include <mmdeviceapi.h>
#include <mmsystem.h>
#define SECOND_FRACTIONS_TO_GRAB 16

// dangerous macros!
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) 
#define MAX(a, b) ((a) > (b) ? (a) : (b))
extern bool bDiscontinuityDetected;
extern bool bVeryFirstPacket;
void ShowOutput(const char *str, ...);
HRESULT set_config_string_setting(LPCTSTR szValueName, wchar_t *szToThis );

int getHtzRate(HRESULT *hr);
int getBitsPerSample();
int getChannels();

HRESULT LoopbackCaptureTakeFromBuffer(BYTE pBuf[], int iSize, WAVEFORMATEX* ifNotNullThenJustSetTypeOnly, LONG* sizeWrote);

#define BITS_PER_BYTE 8

#define VIRTUAL_AUDIO_VERSION L"0.6.0"

void LoopbackCaptureClear();

HRESULT get_default_device(IMMDevice **ppMMDevice);

================================================
FILE: source_code/acam/directshow_fillbuffer.cpp
================================================
#include "stdafx.h"
#include "acam.h"


CCritSec gSharedState;

extern int totalBlips;
//
// FillBuffer
//
// Stuffs the buffer with data
// "they" call this, every so often...
HRESULT CVCamStream::FillBuffer(IMediaSample *pms) 
{	
	// I don't expect these...the parent controls this/us and doesn't call us when it is stopped I guess, so we should always be active...
	ShowOutput("downstream requested an audio frame (FillBuffer cal led)");
	//assert(m_pParent->IsActive()); // one of these can cause freezing on "stop button" in FME
	//assert(!m_pParent->IsStopped());
	
    CheckPointer(pms, E_POINTER);
    BYTE *pData;
    HRESULT hr = pms->GetPointer(&pData);
    if (FAILED(hr)) {
		assert(false);
        return hr;
    }

	// allow it to warmup until Run is called...so StreamTime can work right (ai ai) see http://stackoverflow.com/questions/2469855/how-to-get-imediacontrol-run-to-start-a-file-playing-with-no-delay/2470548#2470548
	FILTER_STATE myState;
	CSourceStream::m_pFilter->GetState(INFINITE, &myState); // get parent filter state which is only set to Run "after pause" etc.
	while(myState != State_Running) {
		ShowOutput("sleeping till graph running for audio...");
		ShowOutput("clearing loop back capture buffer"); // why have extra from "during" the paused state? just trash it! :)
   	    LoopbackCaptureClear(); // could stop and restart it I guess here, too...in theory...but that seems a bit violent and this more the "dshow way of doing things"
		// also sets bVeryFirstPacket
		Sleep(1);
		Command com;
        if(CheckRequest(&com)) { // from http://microsoft.public.multimedia.directx.dshow.programming.narkive.com/h8ZxbM9E/csourcestream-fillbuffer-timing
          if(com == CMD_STOP) {
			  ShowOutput("exiting early from CMD_STOP thinger");
              return S_FALSE;
		  }
        }
		m_pParent->GetState(INFINITE, &myState);  
	}

	if (bVeryFirstPacket)
	  LoopbackCaptureClear(); // this is to recover from pause resumes :|

	// the real meat -- get all the incoming audio data
	LONG totalWrote = -1;
	hr = LoopbackCaptureTakeFromBuffer(pData, pms->GetSize(), NULL, &totalWrote);
	if(FAILED(hr)) {
		// this one can return false during shutdown, so it's actually ok to just return from here...
		// assert(false);
		ShowOutput("capture failed 1");
		return hr; 
		// don't return false here or people may get a "the graph was unable to change state unspecified error return code: 0x80004005) when hitting the stop button in graphedit :|
		// which actually occurs during shutdown...not sure what to really do here...
		//pms->SetActualDataLength(0);
		//return S_OK;
		// except we *want* the graph to abort if they've unplugged something hrm...
	}

	CAutoLock cAutoLockShared(&gSharedState); // for the bFirstPacket boolean control, except there's probably still some odd race conditions er other...
	hr = pms->SetActualDataLength(totalWrote);
	if(FAILED(hr)) {
  	  	assert(false);
		//return hr;
	}

    // Now set the sample's start and end time stamps...
	
	WAVEFORMATEX* pwfexCurrent = (WAVEFORMATEX*)m_mt.Format();
	CRefTime sampleTimeUsed = (REFERENCE_TIME)(UNITS * totalWrote) / 
                     (REFERENCE_TIME)pwfexCurrent->nAvgBytesPerSec;
    CRefTime rtStart;
	if(bDiscontinuityDetected || bVeryFirstPacket) { // could either use bFirstPacket or true here...true seemed to help that one guy...
      CSourceStream::m_pFilter->StreamTime(rtStart); // this is (zero based clock_time if Run already called) but we don't have access to start_offset, and want (just clock time) so don't use it... :|	  
	  if(bDiscontinuityDetected && !bVeryFirstPacket) {
	    ShowOutput("audio discontinuity detected");
	  }
	  if(bVeryFirstPacket) {
		  // my theory is that sometimes the very first packet is "big" and there's tons there [slow ffmpeg startup for instance, or something like that] and it would mess up our timing to say that it "starts" now and goes "until" its end
		  rtStart -= sampleTimeUsed; // so instruct it to think this frame started slightly in the past...
		  // in an effort to try and avoid some async issues
		  ShowOutput("initial very first packet size %I64d", sampleTimeUsed);
	  } else if (bDiscontinuityDetected) {
		  // same deal [as if I knew what I were doing...LOL]
		  rtStart = MAX(m_rtPreviousSampleEndTime, rtStart - sampleTimeUsed);
	  }
	} else {
		// since there hasn't been discontinuity, I think we should be safe to tell it
		// that this packet starts where the previous packet ended off
		// since that's theoretically accurate...
		// exept that it ends up being bad [?]
		// I don't "think" this will hurt graphs that have no reference clock...hopefully...

		rtStart = m_rtPreviousSampleEndTime;

        // CRefTime cur_time;
	    // m_pParent->StreamTime(cur_time);
	    // rtStart = max(rtStart, cur_time);
		// hopefully this being commented out avoids this message/error:
		// [libmp3lame @ 00670aa0] Que input is backward in time
        // Audio timestamp 329016 < 329026 invalid, cliping 00:05:29.05 bitrate= 738.6kbits/s
        // [libmp3lame @ 00670aa0] Que input is backward in time
	}

	// I once tried to change it to always have monotonicity of timestamps at this point, but it didn't fix any problems, and seems to do all right without it so maybe ok [?]
    m_rtPreviousSampleEndTime = rtStart + sampleTimeUsed;

	// attempt to disallow drift/keep these in sync :|
	CRefTime now;
    CSourceStream::m_pFilter->StreamTime(now);
    CRefTime diff = now - m_rtPreviousSampleEndTime;
    if (diff > 0)
        m_rtPreviousSampleEndTime += CRefTime((long)1);
    else if (diff < -100000)
        m_rtPreviousSampleEndTime -= CRefTime((long)1);

	// NB that this *can* set it to a negative start time...hmm...which apparently is "ok" when a graph is just starting up it's expected...
	ShowOutput("timestamping audio packet as %lld -> %lld", rtStart, m_rtPreviousSampleEndTime);
    hr = pms->SetTime((REFERENCE_TIME*) &rtStart, (REFERENCE_TIME*) &m_rtPreviousSampleEndTime);
	if (FAILED(hr)) {
		assert(false);
        //return hr;
    }
	// if we do SetTime(NULL, NULL) here then VLC can "play" it with directshows buffers of size 0ms.
	// however, then VLC cannot then stream it at all.  So we leave it set to some time, and just require you to have VLC buffers of at least 40 or 50 ms
	// [a possible VLC bug?] http://forum.videolan.org/viewtopic.php?f=14&t=92659&hilit=+50ms

	// whatever SetMediaTime even means...
    // hr = pms->SetMediaTime((REFERENCE_TIME*)&rtStart, (REFERENCE_TIME*)&m_rtPreviousSampleEndTime);
    //m_llSampleMediaTimeStart = m_rtSampleEndTime;

	if (FAILED(hr)) {
		assert(false);
        //return hr;
    }

    // Set the sample's properties.
    hr = pms->SetPreroll(FALSE); // tell it that this isn't preroll, so to actually use it...I think.
    if (FAILED(hr)) {
		assert(false);
        //return hr;
    }

    hr = pms->SetMediaType(NULL);
    if (FAILED(hr)) {
		assert(false);
        //return hr;
    }
   
    hr = pms->SetDiscontinuity(bDiscontinuityDetected || bVeryFirstPacket);
    if (FAILED(hr)) {
		assert(false);
        //return hr;
    }
    
	// Set TRUE on every sample for PCM audio http://msdn.microsoft.com/en-us/library/windows/desktop/dd407021%28v=vs.85%29.aspx
    hr = pms->SetSyncPoint(TRUE);
	if (FAILED(hr)) {
		assert(false);
        return hr;
    }
	FILTER_STATE State;
	m_pParent->GetState(0, &State);
	
    bDiscontinuityDetected = false; // reset late since I use it for the SetDiscontinuity method
	bVeryFirstPacket = false;

	ShowOutput("sent audio frame, %d blips, filter state %d", totalBlips, State);
    return S_OK;

} // end FillBuffer


================================================
FILE: source_code/acam/directshow_stuff.cpp
================================================
#include "stdafx.h"

//////////////////////////////////////////////////////////////////////////
//  This file contains routines to register / Unregister the 
//  Directshow filter 'Virtual Cam'
//  We do not use the inbuilt BaseClasses routines as we need to register as
//  a capture source
//////////////////////////////////////////////////////////////////////////


#include <streams.h>
#include <dllsetup.h>
#include <stdio.h>
#include "acam.h"

#pragma once

#define DECLARE_PTR(type, ptr, expr) type* ptr = (type*)(expr);

extern long expectedMaxBufferSize;
extern long pBufOriginalSize; 

//////////////////////////////////////////////////////////////////////////
//  CVCam is the source filter which masquerades as a capture device
//////////////////////////////////////////////////////////////////////////
CUnknown * WINAPI CVCam::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
{
    ASSERT(phr);
    CUnknown *punk = new CVCam(lpunk, phr);

	return punk;
}

IReferenceClock *globalClock;

CVCam::CVCam(LPUNKNOWN lpunk, HRESULT *phr) : 
    CSource(NAME("Virtual cam5"), lpunk, CLSID_VirtualCam)
{
    ASSERT(phr);
	//m_pClock is null at this point...
    m_paStreams = (CSourceStream **) new CVCamStream*[1];
    m_paStreams[0] = new CVCamStream(phr, this, L"Capture Virtual Audio Pin");
}

HRESULT CVCam::QueryInterface(REFIID riid, void **ppv)
{
    //Forward request for IAMStreamConfig & IKsPropertySet to the pin
    if(riid == _uuidof(IAMStreamConfig) || riid == _uuidof(IKsPropertySet))
        return m_paStreams[0]->QueryInterface(riid, ppv);
    else
        return CSource::QueryInterface(riid, ppv);
}

// this does seem to get called frequently... http://msdn.microsoft.com/en-us/library/dd377472%28v=vs.85%29.aspx
// I believe theoretically return VFW_S_CANT_CUE means "don't call me for data" so we should be safe here [?] but somehow still FillBuffer is called :|
STDMETHODIMP CVCam::GetState(DWORD dw, FILTER_STATE *pState)
{
	//ShowOutput("GetState call ed");
    CheckPointer(pState, E_POINTER);
    *pState = m_State;
    if (m_State == State_Paused)
    {
        return VFW_S_CANT_CUE;
    }
    else
    {
        return S_OK;
    }
}


//////////////////////////////////////////////////////////////////////////
// CVCamStream is the one and only output pin of CVCam which handles 
// all the stuff.
//////////////////////////////////////////////////////////////////////////
CVCamStream::CVCamStream(HRESULT *phr, CVCam *pParent, LPCWSTR pPinName) :
    CSourceStream(NAME("Virtual cam5"),phr, pParent, pPinName), m_pParent(pParent)
{
    // Set the default media type...
	GetMediaType(0, &m_mt);
}

void loopBackRelease();

CVCamStream::~CVCamStream()
{
	// don't get here with any consistency...
	ShowOutput("destructor");
} 

// these latency/pushsource stuffs never seem to get called...ever...at least by VLC...
/* therefore unimplemented yet...
HRESULT STDMETHODCALLTYPE CVCamStream::GetLatency(REFERENCE_TIME *storeItHere) {
	*storeItHere = 10000/SECOND_FRACTIONS_TO_GRAB;
	// 1_000_000ns per s, this is in 100 ns or 10_000/s
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CVCamStream::GetPushSourceFlags(ULONG *storeHere) {
	storeHere = 0; // the default (0) is ok...
	return S_OK;
}

HRESULT STDMETHODCALLTYPE CVCamStream::SetPushSourceFlags(ULONG storeHere) {
	return E_UNEXPECTED; // shouldn't ever call this...
}

HRESULT STDMETHODCALLTYPE CVCamStream::GetStreamOffset(REFERENCE_TIME *toHere) {
	return E_UNEXPECTED; // shouldn't ever call this...

//  *toHere = m_tStart; // guess this is right... huh? offset? to what?
}

HRESULT STDMETHODCALLTYPE CVCamStream::GetMaxStreamOffset(REFERENCE_TIME *toHere) {
  *toHere = 0; // TODO set this to a reasonable value...
  return S_OK;
}

HRESULT STDMETHODCALLTYPE CVCamStream::SetMaxStreamOffset(REFERENCE_TIME) {
	return E_UNEXPECTED; // I don't think they'd ever call this either...
}*/

HRESULT CVCamStream::QueryInterface(REFIID riid, void **ppv)
{   
    // Standard OLE stuff...allow it to query for our interfaces that we implement...
    if(riid == _uuidof(IAMStreamConfig))
        *ppv = (IAMStreamConfig*)this;
    else if(riid == _uuidof(IKsPropertySet))
        *ppv = (IKsPropertySet*)this;
	else if(riid == _uuidof(IAMBufferNegotiation))
		 *ppv = (IAMBufferNegotiation*)this;
    else
        return CSourceStream::QueryInterface(riid, ppv);

    AddRef();
    return S_OK;
}

//
// Notify
// Ignore quality management messages sent from the downstream filter
STDMETHODIMP CVCamStream::Notify(IBaseFilter * pSender, Quality q)
{
    return E_NOTIMPL;
} // Notify

//////////////////////////////////////////////////////////////////////////
// This is called when the output format has been negotiated
//////////////////////////////////////////////////////////////////////////
HRESULT CVCamStream::SetMediaType(const CMediaType *pmt)
{
	// call the base class' SetMediaType...
    HRESULT hr = CSourceStream::SetMediaType(pmt);
    return hr;
}

HRESULT setupPwfex(WAVEFORMATEX *pwfex, AM_MEDIA_TYPE *pmt) { // called super early during negotiation...
	// we prefer PCM since WAVE_FORMAT_EXTENSIBLE seems to cause IFilterGraph::DirectConnect to fail, and many programs use it [VLC maybe does?]
	// also we set it up to auto convert to PCM for us
	// see also the bInt16 setting
	pwfex->wFormatTag = WAVE_FORMAT_PCM;
	pwfex->cbSize = 0;                  // apparently should be zero if using WAVE_FORMAT_PCM http://msdn.microsoft.com/en-us/library/ff538799(VS.85).aspx
	pwfex->nChannels = getChannels();               // 1 for mono, 2 for stereo..
	HRESULT hr;
	pwfex->nSamplesPerSec = getHtzRate(&hr);
	if (hr != S_OK) {
		return hr;
	}
	pwfex->wBitsPerSample = 16;          // 16 bit sound
	pwfex->nBlockAlign = (WORD)((pwfex->wBitsPerSample * pwfex->nChannels) / BITS_PER_BYTE);
	pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nBlockAlign; // it can't calculate this itself? huh?
		
	// copy this info into the pmt
    hr = ::CreateAudioMediaType(pwfex, pmt, FALSE /* dont allocate more memory */);
	return hr;
}

HRESULT CVCamStream::setAsNormal(CMediaType *pmt) {
  WAVEFORMATEX *pwfex;
  pwfex = (WAVEFORMATEX *) pmt->AllocFormatBuffer(sizeof(WAVEFORMATEX));
  ZeroMemory(pwfex, sizeof(WAVEFORMATEX));
  if(NULL == pwfex)
   {
       return E_OUTOFMEMORY;
   }
   return setupPwfex(pwfex, pmt);
}

// GetMediaType
// I believe "they" call this...
// we only have one type at a time...
// so we just return our one type...
// which we already told them what it was.
HRESULT CVCamStream::GetMediaType(int iPosition, CMediaType *pmt) 
{
    if (iPosition < 0) {
        return E_INVALIDARG;
    }

	if (iPosition > 0) {
        return VFW_S_NO_MORE_ITEMS;
	}

    WAVEFORMATEX *pwfex = (WAVEFORMATEX *) pmt->AllocFormatBuffer(sizeof(WAVEFORMATEX));
	
	setupPwfex(pwfex, pmt);
	return S_OK;
}

// This method is called to see if a given output format is supported
HRESULT CVCamStream::CheckMediaType(const CMediaType *pMediaType)
{
	int cbFormat = pMediaType->cbFormat;
    if(*pMediaType != m_mt) {
        return E_INVALIDARG;
	}
    return S_OK;
} // CheckMediaType


// Size of each allocated buffer
// seems arbitrary
// maybe downstream needs a certain size?
const int WaveBufferChunkSize = 16*1024;     

// DecideBufferSize
//
// This will always be called after the format has been sucessfully
// negotiated. So we have a look at m_mt to see what format we agreed to.
// Then we can ask for buffers of the correct size to contain them.
HRESULT CVCamStream::DecideBufferSize(IMemAllocator *pAlloc,
                                       ALLOCATOR_PROPERTIES *pProperties)
{
    CheckPointer(pAlloc,E_POINTER);
    CheckPointer(pProperties,E_POINTER);

    WAVEFORMATEX *pwfexCurrent = (WAVEFORMATEX*)m_mt.Format();

	// just use our max size for the buffer size (or whatever they specified for us, if they did)
	pProperties->cBuffers = 1;
	pProperties->cbBuffer = expectedMaxBufferSize;

    // Ask the allocator to reserve us this much memory...
	
    ALLOCATOR_PROPERTIES Actual;
    HRESULT hr = pAlloc->SetProperties(pProperties, &Actual);
    if(FAILED(hr))
    {
        return hr;
    }

    // Is this allocator unsuitable

    if(Actual.cbBuffer < pProperties->cbBuffer)
    {
        return E_FAIL;
    }

    return NOERROR;

} // DecideBufferSize

HRESULT LoopbackCaptureSetup();

HRESULT CVCamStream::OnThreadDestroy()
{
	ShowOutput("OnThreadDestroy");
	return S_OK; 
}

//less useful, for VLC anyway..
HRESULT CVCamStream::Stop()
{
	// never get here
	ShowOutput("pin stop called");
	// call Inactive to initiate shutdown anyway just in case :)
	Inactive();
	return S_OK;
}

HRESULT CVCamStream::Exit()
{
	// never seem to get here
    ShowOutput("exit called");
	return S_OK;
}

int currentlyRunning = 0;

HRESULT CVCamStream::Inactive()
{
	// we get here at least with vlc
	ShowOutput("stream inactive called");
	return CSourceStream::Inactive(); //parent method
}

STDMETHODIMP CVCam::Stop()
{
	ShowOutput("parent stop called");
	if (currentlyRunning)
	{
      ShowOutput("about to release loopback");
	  loopBackRelease();
	  ShowOutput("loopback released");
  	  currentlyRunning = 0; // allow it to restart later...untested...
	}

	return CSource::Stop();
}

STDMETHODIMP CVCam::Pause()
{
	// pause also gets called at "graph setup" time somehow before an initial Run, and always, weirdly...
	// but not at "teardown" or "stop" time apparently...
	// but yes at "pause" time as it were (though some requests for packets still occur, even after that, yikes!)
	// pause is also called immediately before Stop...yikes!
	// so the order is pause, run, pause, stop
	// or, with a pause in there
	// pause, run, pause, run, pause, stop
	// or have I seen run pause before, initially [?] ai ai
	// unfortunately after each pause it still "requires" a few samples out or the graph will die (well, as we're doing it ???)
	// see also http://microsoft.public.multimedia.directx.dshow.programming.narkive.com/h8ZxbM9E/csourcestream-fillbuffer-timing this thing shucks..huh?
	// so current plan: just start it once, leave it going...but when Run is called it clears a buffer somewhere...
	ShowOutput("parent pause called");
	return CBaseFilter::Pause();
}

// Called when graph is first started
HRESULT CVCamStream::OnThreadCreate()
{
	ShowOutput("OnThreadCreate called"); // seems like this gets called pretty early...
    GetMediaType(0, &m_mt); // give it a default type...do we even  need this? LOL

	assert(currentlyRunning == 0); // sanity check no double starts...
	currentlyRunning = TRUE;

    HRESULT hr = LoopbackCaptureSetup();
    if (FAILED(hr)) {
       printf("IAudioCaptureClient::setup failed");
       return hr;
    }

    return NOERROR;
}
void LoopbackCaptureClear();
STDMETHODIMP CVCam::Run(REFERENCE_TIME tStart) {
	ShowOutput("Parent Run called");
	LoopbackCaptureClear(); // post pause, want to clear this to alert it to use the right time stamps...I think hope!

	// LODO why is this called seemingly *way* later than packets are already collected? I guess it calls Pause first or something, to let filters "warm up" ... so in essence, this means "unPause! go!"
	// ((CVCamStream*) m_paStreams[0])->m_rtPreviousSampleEndTime = 0;
	// looks like we accomodate for "resetting" within our own discontinuity stuff...
	// LODO should we...umm...not give any samples before second one or not here?
	return CSource::Run(tStart); // this just calls CBaseFilter::Run (which calls Run on all the pins *then* sets its state to running)
}

//////////////////////////////////////////////////////////////////////////
//  IAMStreamConfig
//////////////////////////////////////////////////////////////////////////

HRESULT STDMETHODCALLTYPE CVCamStream::SetFormat(AM_MEDIA_TYPE *pmt)
{
	// this is them saying you "must" use this type from now on...unless pmt is NULL that "means" reset...LODO handle it someday...
	if(!pmt) {
	  return S_OK; // *sure* we reset..yeah...sure we did...
	}
	
   if(CheckMediaType((CMediaType *) pmt) != S_OK) {
	return E_FAIL; // just in case :P [FME...]
   }
	
	m_mt = *pmt;

	IPin* pin; 
	ConnectedTo(&pin);
	if(pin)
	{
		IFilterGraph *pGraph = m_pParent->GetGraph();
		pGraph->Reconnect(this);
	}

    return S_OK;
}

// set format or "preferred" format if none set.  It's all always the same for us, and was already set to it.
HRESULT STDMETHODCALLTYPE CVCamStream::GetFormat(AM_MEDIA_TYPE **ppmt)
{
    *ppmt = CreateMediaType(&m_mt);
    return S_OK;
}

HRESULT STDMETHODCALLTYPE CVCamStream::GetNumberOfCapabilities(int *piCount, int *piSize)
{
    *piCount = 1; // only allow one type currently...
    *piSize = sizeof(AUDIO_STREAM_CONFIG_CAPS);
    return S_OK;
}

HRESULT STDMETHODCALLTYPE CVCamStream::GetStreamCaps(int iIndex, AM_MEDIA_TYPE **ppMediaType, BYTE *pSCC)
{	 
	
	if(iIndex < 0)
		return E_INVALIDARG;
	if(iIndex > 0)
		return S_FALSE;
	if(pSCC == NULL)
		return E_POINTER;

    *ppMediaType = CreateMediaType(&m_mt);
	if (*ppMediaType == NULL) return E_OUTOFMEMORY;

    DECLARE_PTR(WAVEFORMATEX, pAudioFormat, (*ppMediaType)->pbFormat);
	
	AM_MEDIA_TYPE * pm = *ppMediaType;
	
	setupPwfex(pAudioFormat, pm);

	AUDIO_STREAM_CONFIG_CAPS* pASCC = (AUDIO_STREAM_CONFIG_CAPS*) pSCC;
	ZeroMemory(pSCC, sizeof(AUDIO_STREAM_CONFIG_CAPS)); 

	// Set up audio capabilities [one type only, for now]
	pASCC->guid = MEDIATYPE_Audio;
	pASCC->MaximumChannels = pAudioFormat->nChannels;
	pASCC->MinimumChannels = pAudioFormat->nChannels;
	pASCC->ChannelsGranularity = 1; // doesn't matter
	pASCC->MaximumSampleFrequency = pAudioFormat->nSamplesPerSec;
	pASCC->MinimumSampleFrequency = pAudioFormat->nSamplesPerSec;
	pASCC->SampleFrequencyGranularity = 11025; // doesn't matter
	pASCC->MaximumBitsPerSample = pAudioFormat->wBitsPerSample;
	pASCC->MinimumBitsPerSample = pAudioFormat->wBitsPerSample;
	pASCC->BitsPerSampleGranularity = 16; // doesn't matter

	return S_OK;
}

//////////////////////////////////////////////////////////////////////////
// IKsPropertySet
//////////////////////////////////////////////////////////////////////////

HRESULT CVCamStream::Set(REFGUID guidPropSet, DWORD dwID, void *pInstanceData, 
                        DWORD cbInstanceData, void *pPropData, DWORD cbPropData)
{// Set: Cannot set any properties.
    return E_NOTIMPL;
}

// Get: Return the pin category (our only property). 
HRESULT CVCamStream::Get(
    REFGUID guidPropSet,   // Which property set.
    DWORD dwPropID,        // Which property in that set.
    void *pInstanceData,   // Instance data (ignore).
    DWORD cbInstanceData,  // Size of the instance data (ignore).
    void *pPropData,       // Buffer to receive the property data.
    DWORD cbPropData,      // Size of the buffer.
    DWORD *pcbReturned     // Return the size of the property.
)
{
    if (guidPropSet != AMPROPSETID_Pin)             return E_PROP_SET_UNSUPPORTED;
    if (dwPropID != AMPROPERTY_PIN_CATEGORY)        return E_PROP_ID_UNSUPPORTED;
    if (pPropData == NULL && pcbReturned == NULL)   return E_POINTER;
    
    if (pcbReturned) *pcbReturned = sizeof(GUID);
    if (pPropData == NULL)          return S_OK; // Caller just wants to know the size. 
    if (cbPropData < sizeof(GUID))  return E_UNEXPECTED;// The buffer is too small.
        
    *(GUID *)pPropData = PIN_CATEGORY_CAPTURE;
    return S_OK;
}

// QuerySupported: Query whether the pin supports the specified property.
HRESULT CVCamStream::QuerySupported(REFGUID guidPropSet, DWORD dwPropID, DWORD *pTypeSupport)
{
    if (guidPropSet != AMPROPSETID_Pin) return E_PROP_SET_UNSUPPORTED;
    if (dwPropID != AMPROPERTY_PIN_CATEGORY) return E_PROP_ID_UNSUPPORTED;
    // We support getting this property, but not setting it.
    if (pTypeSupport) *pTypeSupport = KSPROPERTY_SUPPORT_GET; 
    return S_OK;
}


HRESULT STDMETHODCALLTYPE CVCamStream::SuggestAllocatorProperties( /* [in] */ const ALLOCATOR_PROPERTIES *pprop) {
	// maybe we shouldn't even care though...I mean like seriously...why let them make it smaller <sigh>
	// LODO test it both ways with FME, fast computer/slow computer does it make a difference?
	int requested = pprop->cbBuffer;
	if(pprop->cBuffers > 0)
	    requested *= pprop->cBuffers;
	if(pprop->cbPrefix > 0)
	    requested += pprop->cbPrefix;
	
	if(requested <= pBufOriginalSize) {
 		expectedMaxBufferSize = requested;
		return S_OK; // they requested it? ok you got it! You're requesting possible problems! oh well! you requested it!
	} else {
		return E_FAIL;
	}
}

HRESULT STDMETHODCALLTYPE CVCamStream::GetAllocatorProperties( ALLOCATOR_PROPERTIES *pprop) {return NULL;} // they never call this...


================================================
FILE: source_code/acam/dll_main.cpp
================================================
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include <olectl.h>

//////////////////////////////////////////////////////////////////////////
//  This file contains routines to register / Unregister the 
//  Directshow filter 'Virtual Cam'
//  We do not use the inbuilt BaseClasses routines as we need to register as
//  a capture source
//////////////////////////////////////////////////////////////////////////


#include <streams.h>
#include <initguid.h>
#include <dllsetup.h>
#include <stdio.h>



#pragma comment(lib, "kernel32")
#pragma comment(lib, "user32")
#pragma comment(lib, "gdi32")
#pragma comment(lib, "advapi32")
#pragma comment(lib, "winmm")
#pragma comment(lib, "ole32")
#pragma comment(lib, "oleaut32")

#ifdef _DEBUG
    #pragma comment(lib, "strmbasd")
#else
    #pragma comment(lib, "strmbase")
#endif

#include <olectl.h>
#include <initguid.h> // can only include this once/project
#include <dllsetup.h>
#include "acam.h"

#define CreateComObject(clsid, iid, var) CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void **)&var);

STDAPI AMovieSetupRegisterServer( CLSID   clsServer, LPCWSTR szDescription, LPCWSTR szFileName, LPCWSTR szThreadingModel = L"Both", LPCWSTR szServerType     = L"InprocServer32" );
STDAPI AMovieSetupUnregisterServer( CLSID clsServer );

#ifdef _WIN64
// was {8E14549A-DB61-4309-AFA1-3578E927E933}
// {8E14549B-DB61-4309-AFA1-3578E927E935} now...
DEFINE_GUID(CLSID_VirtualCam,
            0x8e146464, 0xdb61, 0x4309, 0xaf, 0xa1, 0x35, 0x78, 0xe9, 0x27, 0xe9, 0x35);
#else
// was {8E14549A-DB61-4309-AFA1-3578E927E933}
// {8E14549B-DB61-4309-AFA1-3578E927E935} now...
DEFINE_GUID(CLSID_VirtualCam,
            0x8e14549b, 0xdb61, 0x4309, 0xaf, 0xa1, 0x35, 0x78, 0xe9, 0x27, 0xe9, 0x35);
#endif

const AMOVIESETUP_MEDIATYPE AMSMediaTypesVCam = 
{ &MEDIATYPE_Audio      // clsMajorType
, &MEDIASUBTYPE_NULL }; // clsMinorType

const AMOVIESETUP_PIN AMSPinVCam=
{
    L"Output",             // Pin string name
    FALSE,                 // Is it rendered
    TRUE,                  // Is it an output
    FALSE,                 // Can we have none
    FALSE,                 // Can we have many
    &CLSID_NULL,           // Connects to filter
    NULL,                  // Connects to pin
    1,                     // Number of types
    &AMSMediaTypesVCam      // Pin Media types
};

const AMOVIESETUP_FILTER AMSFilterVCam =
{
    &CLSID_VirtualCam,  // Filter CLSID
    L"virtual-audio-capturer",     // String name
    MERIT_DO_NOT_USE,      // Filter merit
    1,                     // Number pins
    &AMSPinVCam             // Pin details
};

CFactoryTemplate g_Templates[] = 
{
    {
        L"virtual-audio-capturer",
        &CLSID_VirtualCam,
        CVCam::CreateInstance,
        NULL,
        &AMSFilterVCam
    },

};

int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

// straight call to here on init, instead of to
// AMovieDllRegisterServer2 which is what the other fella does...
// which I assume is similar to this...maybe?
STDAPI RegisterFilters( BOOL bRegister )
{
    HRESULT hr = NOERROR;
    WCHAR achFileName[MAX_PATH];
    char achTemp[MAX_PATH];
    ASSERT(g_hInst != 0);

    if( 0 == GetModuleFileNameA(g_hInst, achTemp, sizeof(achTemp))) 
        return AmHresultFromWin32(GetLastError());

    MultiByteToWideChar(CP_ACP, 0L, achTemp, lstrlenA(achTemp) + 1, 
                       achFileName, NUMELMS(achFileName));
  
    hr = CoInitialize(0);
    if(bRegister)
    {
        hr = AMovieSetupRegisterServer(CLSID_VirtualCam, L"virtual-audio-capturer", achFileName, L"Both", L"InprocServer32");
    }

    if( SUCCEEDED(hr) )
    {
        IFilterMapper2 *fm = 0;
        hr = CreateComObject( CLSID_FilterMapper2, IID_IFilterMapper2, fm );
        if( SUCCEEDED(hr) )
        {
            if(bRegister)
            {
                IMoniker *pMoniker = 0;
                REGFILTER2 rf2;
                rf2.dwVersion = 1;
                rf2.dwMerit = MERIT_DO_NOT_USE;
                rf2.cPins = 1;
                rf2.rgPins = &AMSPinVCam;
                hr = fm->RegisterFilter(CLSID_VirtualCam, L"virtual-audio-capturer", &pMoniker, &CLSID_AudioInputDeviceCategory, NULL, &rf2);
            }
            else
            {
                hr = fm->UnregisterFilter(&CLSID_AudioInputDeviceCategory, 0, CLSID_VirtualCam);
            }
        }

      // release interface
      if(fm)
          fm->Release();
    }

    if( SUCCEEDED(hr) && !bRegister )
        hr = AMovieSetupUnregisterServer( CLSID_VirtualCam );

    CoFreeUnusedLibraries();
    CoUninitialize();
    return hr;
}

// DLL.cpp

//////////////////////////////////////////////////////////////////////////
//  This file contains routines to register / Unregister the 
//  Directshow filter 'Virtual Cam'
//  We do not use the inbuilt BaseClasses routines as we need to register as
//  a capture source
//////////////////////////////////////////////////////////////////////////
#include <stdio.h>

STDAPI RegisterFilters( BOOL bRegister );

STDAPI DllRegisterServer()
{
	printf("hello there"); // we actually never see this...
    return RegisterFilters(TRUE);
}

STDAPI DllUnregisterServer()
{
    return RegisterFilters(FALSE);
}

STDAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

extern "C" BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)
{
	return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}



================================================
FILE: source_code/acam/loopback-capture-helpers.cpp
================================================
#include "stdafx.h"

#include <windows.h>
#include <mmsystem.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <stdio.h>
#include <avrt.h>

// I guess this is the default...audio output device...
HRESULT get_default_device(IMMDevice **ppMMDevice) {
    HRESULT hr;
    IMMDeviceEnumerator *pMMDeviceEnumerator;
    // activate a device enumerator
    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, 
        __uuidof(IMMDeviceEnumerator),
        (void**)&pMMDeviceEnumerator
    );
    if (FAILED(hr)) {
        printf("CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x\n", hr);
        return hr;
    }

    // get the default render endpoint
    hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, ppMMDevice);
    pMMDeviceEnumerator->Release();
    if (FAILED(hr)) {
        printf("IMMDeviceEnumerator::GetDefaultAudioEndpoint failed: hr = 0x%08x\n", hr); // we get here if no headphones plugged in
        return hr;
    }
    return S_OK;
}


================================================
FILE: source_code/acam/loopback-capture.cpp
================================================
#include "stdafx.h"

#include <streams.h>
#include <windows.h>
#include <audioclient.h>
#include <stdio.h>
#include <avrt.h>
#include "common.h"
#include "assert.h"
#include <memory.h>

//HRESULT open_file(LPCWSTR szFileName, HMMIO *phFile);


void outputStats();
HRESULT start_silence_thread();
HRESULT join_silence_thread();
IAudioCaptureClient *pAudioCaptureClient;
IAudioClient *pAudioClient;
HANDLE hTask;
bool bDiscontinuityDetected; // init'd eleswhere
bool bVeryFirstPacket; // init'd elsewhere
IMMDevice *m_pMMDevice;
UINT32 nBlockAlign;
UINT32 pnFrames;

bool propagatingNormally;

CCritSec csMyLock;  // shared critical section. Starts not locked...

int shouldStop = true;

BYTE pBufLocal[1024*1024]; // 1MB is quite awhile I think...
long pBufOriginalSize = 1024*1024;
//long pBufLocalSize = 1024*1024; // used for buffer size negotiation method, use expectedmaxbuffersize instead
long pBufLocalCurrentEndLocation = 0;

long expectedMaxBufferSize = 1024*1024; // TODO make non-global

HANDLE m_hThread;

static DWORD WINAPI propagateBufferForever(LPVOID pv);


#define EXIT_ON_ERROR(hres)  \
              if (FAILED(hres)) { return hres; }
#define REFTIMES_PER_SEC  10000000


const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);

void propagateWithRawCurrentFormat(WAVEFORMATEX *toThis, HRESULT *hrOut) {
	WAVEFORMATEX *pwfx;
	IMMDevice *pMMDevice;
	IAudioClient *pAudioClient;
    HANDLE hTask;
    DWORD nTaskIndex = 0;
    hTask = AvSetMmThreadCharacteristics(L"Capture", &nTaskIndex);

    HRESULT hr = get_default_device(&pMMDevice);
    if (FAILED(hr)) {
		*hrOut = hr;
		return;
    }
	// activate an (the default, for us, since we want loopback) IAudioClient
    hr = pMMDevice->Activate(
        __uuidof(IAudioClient),
        CLSCTX_ALL, NULL,
        (void**)&pAudioClient
    );
    if (FAILED(hr)) {
        ShowOutput("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x", hr);
		*hrOut = hr;
		return;
    }

	hr = pAudioClient->GetMixFormat(&pwfx);
    if (FAILED(hr)) {
        ShowOutput("IAudioClient::GetMixFormat failed: hr = 0x%08x\n", hr);
        CoTaskMemFree(pwfx);
        pAudioClient->Release();
		*hrOut = hr;
		return;
    }
	pAudioClient->Stop();
    AvRevertMmThreadCharacteristics(hTask);
    pAudioClient->Release();
    pMMDevice->Release();
	memcpy(toThis, pwfx, sizeof(WAVEFORMATEX));
	CoTaskMemFree(pwfx); 
	*hrOut = S_OK;
}

int getHtzRate(HRESULT *hr) { // called earliest so return "is it alive?"
	WAVEFORMATEX format;
	propagateWithRawCurrentFormat(&format, hr);
	return format.nSamplesPerSec;
}
/*
int getBitsPerSample() {
	WAVEFORMATEX format;
	propagateWithRawCurrentFormat(&format);
	return format.wBitsPerSample;
}
*/
int getChannels() {
	WAVEFORMATEX format;
    HRESULT hr;
	propagateWithRawCurrentFormat(&format, &hr);
	return format.nChannels;
}

// we only call this once...per hit of the play button :)
HRESULT LoopbackCaptureSetup()
{
	assert(shouldStop); // double start would be odd...
	shouldStop = false; // allow graphs to restart, if they so desire...
	pnFrames = 0;
	bool bInt16 = true; // makes it actually work, for some reason...my guess is it's a more common format
	
    HRESULT hr;
    hr = get_default_device(&m_pMMDevice); // so it can re-place our pointer...
    if (FAILED(hr)) {
        return hr;
    }

	// tell it to not overflow one buffer's worth <sigh> not sure if this is right or not, and thus we don't "cache" or "buffer" more than that much currently...
	// but a buffer size is a buffer size...hmm...as long as we keep it small though...
	assert(expectedMaxBufferSize <= pBufOriginalSize);
    // activate an (the default, for us, since we want loopback) IAudioClient
    hr = m_pMMDevice->Activate(
        __uuidof(IAudioClient),
        CLSCTX_ALL, NULL,
        (void**)&pAudioClient
    );
    if (FAILED(hr)) {
        ShowOutput("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x", hr);
        return hr;
    }
    
    // get the default device periodicity, why? I don't know...
    REFERENCE_TIME hnsDefaultDevicePeriod;
    hr = pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, NULL);
    if (FAILED(hr)) {
        ShowOutput("IAudioClient::GetDevicePeriod failed: hr = 0x%08x\n", hr);
        pAudioClient->Release();
        return hr;
    }

    // get the default device format (incoming...)
    WAVEFORMATEX *pwfx; // incoming wave...
	// apparently propogated by GetMixFormat...
    hr = pAudioClient->GetMixFormat(&pwfx); // we free pwfx
    if (FAILED(hr)) {
        ShowOutput("IAudioClient::GetMixFormat failed: hr = 0x%08x\n", hr);
        CoTaskMemFree(pwfx);
        pAudioClient->Release();
        return hr;
    }

    if (true /*bInt16*/) {
        // coerce int-XX wave format (like int-16 or int-32)
        // can do this in-place since we're not changing the size of the format
        // also, the engine will auto-convert from float to int for us
        switch (pwfx->wFormatTag) {
            case WAVE_FORMAT_IEEE_FLOAT:
				assert(false);// we never get here...I never have anyway...my guess is windows vista+ by default just uses WAVE_FORMAT_EXTENSIBLE
                pwfx->wFormatTag = WAVE_FORMAT_PCM;
                pwfx->wBitsPerSample = 16;
                pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
                pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
                break;

            case WAVE_FORMAT_EXTENSIBLE: // 65534
                {
                    // naked scope for case-local variable
                    PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
                    if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat)) {
						// WE GET HERE!
                        pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
						// convert it to PCM, but let it keep as many bits of precision as it has initially...though it always seems to be 32
						// comment this out and set wBitsPerSample to  pwfex->wBitsPerSample = getBitsPerSample(); to get an arguably "better" quality 32 bit pcm
						// unfortunately flash media live encoder basically rejects 32 bit pcm, and it's not a huge gain sound quality-wise, so disabled for now.
                        pwfx->wBitsPerSample = 16;
						pEx->Samples.wValidBitsPerSample = pwfx->wBitsPerSample;
                        pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
                        pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
						// see also setupPwfex method
                    } else {
                        ShowOutput("Don't know how to coerce mix format to int-16\n");
                        CoTaskMemFree(pwfx);
                        pAudioClient->Release();
                        return E_UNEXPECTED;
                    }
                }
                break;

            default:
                ShowOutput("Don't know how to coerce WAVEFORMATEX with wFormatTag = 0x%08x to int-16\n", pwfx->wFormatTag);
                CoTaskMemFree(pwfx);
                pAudioClient->Release();
                return E_UNEXPECTED;
        }
    }

    MMCKINFO ckRIFF = {0};
    MMCKINFO ckData = {0};

    nBlockAlign = pwfx->nBlockAlign;
    

// avoid stuttering on close when using loopback
// http://social.msdn.microsoft.com/forums/en-US/windowspro-audiodevelopment/thread/c7ba0a04-46ce-43ff-ad15-ce8932c00171/ 
	
//IAudioClient *pAudioClient = NULL;
//IAudioCaptureClient *pCaptureClient = NULL;
	
IMMDeviceEnumerator *pEnumerator = NULL;
IMMDevice *pDevice = NULL;

IAudioRenderClient *pRenderClient = NULL;
WAVEFORMATEXTENSIBLE *captureDataFormat = NULL;
BYTE *captureData;

    REFERENCE_TIME hnsRequestedDuration = REFTIMES_PER_SEC;

    hr = CoCreateInstance(
           CLSID_MMDeviceEnumerator, NULL,
           CLSCTX_ALL, IID_IMMDeviceEnumerator,
           (void**)&pEnumerator);
    EXIT_ON_ERROR(hr)

    hr = get_default_device(&pDevice);
    EXIT_ON_ERROR(hr)

    hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
    EXIT_ON_ERROR(hr)

    hr = pAudioClient->GetMixFormat((WAVEFORMATEX **)&captureDataFormat);
    EXIT_ON_ERROR(hr)

	
    // Silence: initialise in sharedmode [this is the "silence" bug overwriter, so buffer doesn't matter as much...]
    hr = pAudioClient->Initialize(
                         AUDCLNT_SHAREMODE_SHARED,
                         0,
					     REFTIMES_PER_SEC, // buffer size a full 1.0s, though prolly doesn't matter here.
                         0,
                         pwfx,
                         NULL);
    EXIT_ON_ERROR(hr)

    // get the frame count
    UINT32  bufferFrameCount;
    hr = pAudioClient->GetBufferSize(&bufferFrameCount);
    EXIT_ON_ERROR(hr)

    // create a render client
    hr = pAudioClient->GetService(IID_IAudioRenderClient, (void**)&pRenderClient);
    EXIT_ON_ERROR(hr)

    // get the buffer
    hr = pRenderClient->GetBuffer(bufferFrameCount, &captureData);
    EXIT_ON_ERROR(hr)

    // release it
    hr = pRenderClient->ReleaseBuffer(bufferFrameCount, AUDCLNT_BUFFERFLAGS_SILENT);
    EXIT_ON_ERROR(hr)

    // release the audio client
    pAudioClient->Release();
    EXIT_ON_ERROR(hr)


    // create a new IAudioClient
    hr = pDevice->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void**)&pAudioClient);
    EXIT_ON_ERROR(hr)

    // -============================ now the sniffing code initialization stuff, direct from mauritius... ===================================

	// call IAudioClient::Initialize
    // note that AUDCLNT_STREAMFLAGS_LOOPBACK and AUDCLNT_STREAMFLAGS_EVENTCALLBACK
    // do not work together...
    // the "data ready" event never gets set
    // so we're going to have to do this in a timer-driven loop...

    hr = pAudioClient->Initialize(
        AUDCLNT_SHAREMODE_SHARED,
        AUDCLNT_STREAMFLAGS_LOOPBACK,
        REFTIMES_PER_SEC, // buffer size a full 1.0s, seems ok VLC
		0, pwfx, 0
    );
    if (FAILED(hr)) {
        ShowOutput("IAudioClient::Initialize failed: hr = 0x%08x\n", hr);
        pAudioClient->Release();
        return hr;
    }
    CoTaskMemFree(pwfx);

    // activate an IAudioCaptureClient
    hr = pAudioClient->GetService(
        __uuidof(IAudioCaptureClient),
        (void**)&pAudioCaptureClient
    );

    if (FAILED(hr)) {
        ShowOutput("IAudioClient::GetService(IAudioCaptureClient) failed: hr 0x%08x\n", hr);
        pAudioClient->Release();
        return hr;
    }
    
    // register with MMCSS
    DWORD nTaskIndex = 0;

    hTask = AvSetMmThreadCharacteristics(L"Capture", &nTaskIndex);
    if (NULL == hTask) {
        DWORD dwErr = GetLastError();
        ShowOutput("AvSetMmThreadCharacteristics failed: last error = %u\n", dwErr);
        pAudioCaptureClient->Release();
        pAudioClient->Release();
        return HRESULT_FROM_WIN32(dwErr);
    }    

    // call IAudioClient::Start
    hr = pAudioClient->Start();
    if (FAILED(hr)) {
        ShowOutput("IAudioClient::Start failed: hr = 0x%08x\n", hr);
        AvRevertMmThreadCharacteristics(hTask);
        pAudioCaptureClient->Release();
        pAudioClient->Release();
        return hr;
    }
    
	// init some var's [XXXX using global vars doesn't work if I had 2 of these at the same time in the same process [?]]
    bDiscontinuityDetected = true;
	bVeryFirstPacket = true;

	// start the forever grabbing thread...
	DWORD dwThreadID;
    m_hThread = CreateThread(NULL,
                            0,
                            propagateBufferForever,
                            0,
                            0,
                            &dwThreadID);
    if(!m_hThread)
    {
        DWORD dwErr = GetLastError();
        return HRESULT_FROM_WIN32(dwErr);
    } else {
		// we...shouldn't need this...maybe?
		// seems to make no difference anyway, and probably won't hurt...
		hr = SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL);
        if (FAILED(hr)) {
		  return hr;
  	    }
	}
	hr = start_silence_thread();
	return hr;
} // end LoopbackCaptureSetup


HRESULT propagateBufferOnce();

extern CCritSec gSharedState;

int totalSuccessFullyread = 0;
int totalBlips = 0;
int totalOverflows = 0;

HRESULT propagateBufferOnce() {
	HRESULT hr = S_OK;

    // grab next audio chunk...
	int gotAnyAtAll = FALSE;
	DWORD start_time = timeGetTime();
    while (!shouldStop) {
        UINT32 nNextPacketSize;
        hr = pAudioCaptureClient->GetNextPacketSize(&nNextPacketSize); // get next packet, if one is ready...
        if (FAILED(hr)) {
            ShowOutput("IAudioCaptureClient::GetNextPacketSize failed after %u frames: hr = 0x%08x\n", pnFrames, hr);
            /*pAudioClient->Stop(); // cleaned up in the teardown, don't do it twice -> segfault! [we get here if unplug headphones]
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release();*/            
            return hr;
        }

        if (0 == nNextPacketSize) {
            // (CA) - this condition appears on Win8 when there is "silence" in the audio stream 
			// (CA) - we don't appear to hit this condition in Win7 .. so I have eliminated the logic in here for right now...

			/*
			// no data yet, we're waiting, between incoming chunks of audio. [occurs even with silence on the line--it just means no new data yet]
			DWORD millis_to_fill = (DWORD) (1.0/SECOND_FRACTIONS_TO_GRAB*1000); // truncate is ok :) -- 1s
			assert(millis_to_fill > 1); // sanity
			DWORD current_time = timeGetTime();
			if((current_time - start_time > millis_to_fill)) {
				// I don't think we ever get to here anymore...thankfully, since it's mostly broken code probably, anyway
				if(!gotAnyAtAll) {
				  // We get here under high load...
			      // ignore for now, but sleep more
			      ShowOutput("detected high amount of time without receiving a packet from the capturer!");
				  start_time = timeGetTime();
				  Sleep(0);
				}
			} else {
			  Sleep(1); // doesn't seem to hurt cpu--"sleep x ms"
			  continue;
			}
			*/
			Sleep(1);
			continue;
        } else {
		  gotAnyAtAll = TRUE;
		  totalSuccessFullyread++;
		}
		
        // get the captured data
        BYTE *pData;
        UINT32 nNumFramesToRead;
        DWORD dwFlags;

		// I guess it gives us...as much audio as possible to read...probably

        hr = pAudioCaptureClient->GetBuffer(
            &pData,
            &nNumFramesToRead,
            &dwFlags,
            NULL,
            NULL
        ); // ACTUALLY GET THE BUFFER which I assume it reads in the format of the fella we passed in
        
        
        if (FAILED(hr)) {
            ShowOutput("IAudioCaptureClient::GetBuffer failed after %u frames: hr = 0x%08x\n", pnFrames, hr);
            /*pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release();*/            
            return hr;            
        }

		{
  		  CAutoLock cAutoLockShared(&gSharedState);  // for the booleans, we lock csMyLock later :| XXXX weird?

			if( dwFlags == 0 ) {
			  // the good case, got audio packet
			  // we'll let fillbuffer set bDiscontinuityDetected = false; since it uses it to know if the next packet should restart, etc.
			} else if (bDiscontinuityDetected && AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {
				ShowOutput("Probably spurious glitch reported on first packet, or two discontinuity errors occurred before it read from the cached buffer\n");
				
				bDiscontinuityDetected = true; // won't hurt, even if it is a real first packet :)
				
				// XXXX it should probably clear the buffers if it ever gets discontinuity
				// or "let" it clear the buffers then send the new data on
				// as we have any left-over data that will be assigned a wrong timestamp
				// but it won't be too far wrong, compared to what it would otherwise be with always
				// assigning it the current graph timestamp, like we used to...
			} else if (AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {
				  ShowOutput("IAudioCaptureClient::discontinuity GetBuffer set flags to 0x%08x after %u frames\n", dwFlags, pnFrames);
				  // expected your CPU gets behind or what not. I guess.
				  /*pAudioClient->Stop();
				  AvRevertMmThreadCharacteristics(hTask);
				  pAudioCaptureClient->Release();		  
				  pAudioClient->Release();            
				  return E_UNEXPECTED;*/
				  
				  bDiscontinuityDetected = true;
			} else if (AUDCLNT_BUFFERFLAGS_SILENT == dwFlags) {
     		  // ShowOutput("IAudioCaptureClient::silence (just) from GetBuffer after %u frames\n", pnFrames);
			  // expected if there's silence (i.e. nothing playing), since we now include the "silence generator" work-around...
		      // at least in windows 7, we get here...
			} else {
			  // probably silence + discontinuity
     		  ShowOutput("IAudioCaptureClient::unknown discontinuity GetBuffer set flags to 0x%08x after %u frames\n", dwFlags, pnFrames);			  
			  bDiscontinuityDetected = true; // probably is some type of discontinuity :P
			}

			if(bDiscontinuityDetected)
				totalBlips++;

			if (0 == nNumFramesToRead) {
			  // we should probably never get here, right?
				// my guess is that we don't, even in win8?
				// I mean, this is probably really messed up it told us it had some data to grab, we try to grab it, it returns us nothing?
				/*
				ShowOutput("death failure: IAudioCaptureClient::GetBuffer said to read 0 frames after %u frames\n", pnFrames);
				pAudioClient->Stop();
				AvRevertMmThreadCharacteristics(hTask);
				pAudioCaptureClient->Release();
				pAudioClient->Release();
				return E_UNEXPECTED;  
				*/
			}

			pnFrames += nNumFramesToRead; // increment total count...		

			// lBytesToWrite typically 1792 bytes...
			LONG lBytesToWrite = nNumFramesToRead * nBlockAlign; // nBlockAlign is "audio block size" or frame size, for one audio segment...
			{
			  CAutoLock cObjectLock(&csMyLock);  // Lock the critical section, releases scope after block is over...

			  if(pBufLocalCurrentEndLocation > expectedMaxBufferSize) { 
				// this happens during VLC pauses...
				// I have no idea what I'm doing here... this doesn't fix it, but helps a bit... TODO FINISH THIS
				// it seems like if you're just straight recording then you want this big...otherwise you want it like size 0 and non-threaded [pausing with graphedit, for example]... [?]
				// if you were recording skype, you'd want it non realtime...hmm...
				// it seems that if the cpu is loaded, we run into this if it's for the next packet...hmm...
				// so basically we don't accomodate realtime at all currently...hmmm...
	  			ShowOutput("overfilled buffer, cancelling/flushing."); //over flow overflow appears VLC just keeps reading though, when paused [?] but not graphedit...or does it?
				pBufLocalCurrentEndLocation = 0;
				totalOverflows++;
				bDiscontinuityDetected = true;
			  }

			  for(INT i = 0; i < lBytesToWrite && pBufLocalCurrentEndLocation < expectedMaxBufferSize; i++) {
				pBufLocal[pBufLocalCurrentEndLocation++] = pData[i];
			  }
			}
		}
        
        hr = pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead);
        if (FAILED(hr)) {
            ShowOutput("IAudioCaptureClient::ReleaseBuffer failed after %u frames: hr = 0x%08x\n", pnFrames, hr);
            /*pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release(); */            
            return hr;            
        }
        
		return hr;
    } // while !got anything && should continue loop

	return S_OK; // stop was called...

}

// iSize is max size of the BYTE buffer...so maybe...we should just drop it if we have past that size? hmm...we're probably
HRESULT LoopbackCaptureTakeFromBuffer(BYTE pBuf[], int iSize, WAVEFORMATEX* ifNotNullThenJustSetTypeOnly, LONG* totalBytesWrote)
 {
	while(!shouldStop) { // allow this to exit, too, at shutdown, possibly a few times we kind of got stuck in here, waiting for more data, but it was shutdown so not receiving any more data :|
       {
        CAutoLock cObjectLock(&csMyLock);  // Lock the critical section, releases scope after block is done...
		if(pBufLocalCurrentEndLocation > 0) {
		  // fails lodo is that ok though? 
		  // assert(pBufLocalCurrentEndLocation <= expectedMaxBufferSize);
		  int totalToWrite = MIN(pBufLocalCurrentEndLocation, expectedMaxBufferSize);
		  ASSERT(totalToWrite <= iSize); // just in case...just in case almost...
		  memcpy(pBuf, pBufLocal, totalToWrite);
          *totalBytesWrote = totalToWrite;
		  pBufLocalCurrentEndLocation = 0;
          return S_OK;
		} // else fall through to sleep outside the lock...
	  }
	  // sleep outside the lock ...
	  // using sleep doesn't seem to hurt the cpu
	  // and it seems to not get many "discontinuity" messages currently...
      Sleep(1);
	  if (!propagatingNormally) {
		  return E_FAIL; // the capture has died, Jim!
	  }
	}
	return E_FAIL; // we didn't fill anything...and are shutting down...
}

void LoopbackCaptureClear() {
        CAutoLock cObjectLock(&csMyLock);  // Lock the critical section, releases scope after block is done...
		pBufLocalCurrentEndLocation = 0;
		bDiscontinuityDetected = 1; // it uses this for timestamping the next packet
}

// clean up
void loopBackRelease() {
	// tell running collector thread to end...
	shouldStop = 1;
	WaitForSingleObject(m_hThread, INFINITE);
    CloseHandle(m_hThread);
    m_hThread = NULL;
	if (pAudioClient) {
      m_pMMDevice->Release();
	  pAudioClient->Stop();
	  //pAudioClient->GetService();
      pAudioCaptureClient->Release();
      pAudioClient->Release();

	}
    AvRevertMmThreadCharacteristics(hTask);

	// thread is done, we are exiting...
	pBufLocalCurrentEndLocation = 0;
	outputStats();
	join_silence_thread();
}


void outputStats() {
	wchar_t output[250];
	wsprintf(output, L"v. %s total reads %d total discontinuity blips %d,  total overflows %d", VIRTUAL_AUDIO_VERSION, totalSuccessFullyread , totalBlips - 1, totalOverflows);
	set_config_string_setting(L"last_output", output);
}

// called via reflection :)
static DWORD WINAPI propagateBufferForever(LPVOID pv) {
  propagatingNormally = true; // XXXX use events, the coolio way :|
  while(!shouldStop) {
    HRESULT hr = propagateBufferOnce();
	if(FAILED(hr)) {
	  propagatingNormally = false;
	  return hr; // exit thread
	}
  }
  return S_OK;
}


================================================
FILE: source_code/acam/silence.h
================================================
#include "common.h"
struct PlaySilenceThreadFunctionArguments {
    IMMDevice *pMMDevice;
    HANDLE hStartedEvent;
    HANDLE hStopEvent;
    HRESULT hr;
};

================================================
FILE: source_code/acam/silence_background_thread.cpp
================================================
// silence.cpp from msdn blog
#include "stdafx.h"
#include <windows.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <stdio.h>
#include <avrt.h>

#include "silence.h"

// started in its own thread
DWORD WINAPI PlaySilenceThreadFunction(LPVOID pContext) {
    PlaySilenceThreadFunctionArguments *pArgs =
        (PlaySilenceThreadFunctionArguments*)pContext;

    IMMDevice *pMMDevice = pArgs->pMMDevice;
    HRESULT &hr = pArgs->hr;

    // CoInitialize (probably don't even need this...)
    hr = CoInitialize(NULL);
    if (FAILED(hr)) {
        printf("CoInitialize failed: hr = 0x%08x\n", hr);
        return 0;
    }

    // activate an IAudioClient
    IAudioClient *pAudioClient;
    hr = pMMDevice->Activate(
        __uuidof(IAudioClient),
        CLSCTX_ALL, NULL,
        (void**)&pAudioClient
    );
    if (FAILED(hr)) {
        printf("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x", hr);
        //CoUninitialize();
        return 0;
    }

    // get the mix format
    WAVEFORMATEX *pwfx;
    hr = pAudioClient->GetMixFormat(&pwfx);
    if (FAILED(hr)) {
        printf("IAudioClient::GetMixFormat failed: hr = 0x%08x\n", hr);
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }

    // initialize the audio client
    hr = pAudioClient->Initialize(
        AUDCLNT_SHAREMODE_SHARED,
        AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
        0, 0, pwfx, NULL
    );
    CoTaskMemFree(pwfx);
    if (FAILED(hr)) {
        printf("IAudioClient::Initialize failed: hr 0x%08x\n", hr);
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }

    // get the buffer size
    UINT32 nFramesInBuffer;
    hr = pAudioClient->GetBufferSize(&nFramesInBuffer);
    if (FAILED(hr)) {
        printf("IAudioClient::GetBufferSize failed: hr 0x%08x\n", hr);
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }

    // get an IAudioRenderClient
    IAudioRenderClient *pAudioRenderClient;
    hr = pAudioClient->GetService(
        __uuidof(IAudioRenderClient),
        (void**)&pAudioRenderClient
    );
    if (FAILED(hr)) {
        printf("IAudioClient::GetService(IAudioRenderClient) failed: hr 0x%08x\n", hr);
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }

    // create a "feed me" event
    HANDLE hFeedMe;
    hFeedMe = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (NULL == hFeedMe) {
        DWORD dwErr = GetLastError();
        hr = HRESULT_FROM_WIN32(dwErr);
        printf("CreateEvent failed: last error is %u\n", dwErr);
        pAudioRenderClient->Release();
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }

    // set it as the event handle
    hr = pAudioClient->SetEventHandle(hFeedMe);
    if (FAILED(hr)) {
        printf("IAudioClient::SetEventHandle failed: hr = 0x%08x\n", hr);
        pAudioRenderClient->Release();
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }

    // pre-fill a single buffer of silence
    BYTE *pData;
    hr = pAudioRenderClient->GetBuffer(nFramesInBuffer, &pData);
    if (FAILED(hr)) {
        printf("IAudioRenderClient::GetBuffer failed on pre-fill: hr = 0x%08x\n", hr);
        pAudioClient->Stop();
        printf("TODO: unregister with MMCSS\n");
        CloseHandle(hFeedMe);
        pAudioRenderClient->Release();
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }

    // release the buffer with the silence flag
    hr = pAudioRenderClient->ReleaseBuffer(nFramesInBuffer, AUDCLNT_BUFFERFLAGS_SILENT);
    if (FAILED(hr)) {
        printf("IAudioRenderClient::ReleaseBuffer failed on pre-fill: hr = 0x%08x\n", hr);
        pAudioClient->Stop();
        printf("TODO: unregister with MMCSS\n");
        CloseHandle(hFeedMe);
        pAudioRenderClient->Release();
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }        

    // register with MMCSS
    DWORD nTaskIndex = 0;
    HANDLE hTask = AvSetMmThreadCharacteristics(L"Playback", &nTaskIndex);
    if (NULL == hTask) {
        DWORD dwErr = GetLastError();
        hr = HRESULT_FROM_WIN32(dwErr);
        printf("AvSetMmThreadCharacteristics failed: last error = %u\n", dwErr);
        pAudioRenderClient->Release();
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }    

    // call Start
    hr = pAudioClient->Start();
    if (FAILED(hr)) {
        printf("IAudioClient::Start failed: hr = 0x%08x\n", hr);
        printf("TODO: unregister with MMCSS\n");
        AvRevertMmThreadCharacteristics(hTask);
        pAudioRenderClient->Release();
        pAudioClient->Release();
        //CoUninitialize();
        return 0;
    }
    SetEvent(pArgs->hStartedEvent);

    HANDLE waitArray[2] = { pArgs->hStopEvent, hFeedMe };
    DWORD dwWaitResult;

    bool bDone = false;
    for (UINT32 nPasses = 0; !bDone; nPasses++) {
        dwWaitResult = WaitForMultipleObjects(
            ARRAYSIZE(waitArray), waitArray,
            FALSE, INFINITE
        );

        if (WAIT_OBJECT_0 == dwWaitResult) {
            printf("Received stop event after %u passes\n", nPasses);
            bDone = true;
            continue; // exits loop
        }

        if (WAIT_OBJECT_0 + 1 != dwWaitResult) {
            hr = E_UNEXPECTED;
            printf("Unexpected WaitForMultipleObjects return value %u on pass %u\n", dwWaitResult, nPasses);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            CloseHandle(hFeedMe);
            pAudioRenderClient->Release();
            pAudioClient->Release();
            //CoUninitialize();
            return 0;
        }

        // got "feed me" event - see how much padding there is
        //
        // padding is how much of the buffer is currently in use
        //
        // note in particular that event-driven (pull-mode) render should not
        // call GetCurrentPadding multiple times
        // in a single processing pass
        // this is in stark contrast to timer-driven (push-mode) render
        UINT32 nFramesOfPadding;
        hr = pAudioClient->GetCurrentPadding(&nFramesOfPadding);
        if (FAILED(hr)) {
            ShowOutput("IAudioClient::GetCurrentPadding failed on pass %u: hr = 0x%08x\n", nPasses, hr);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            CloseHandle(hFeedMe);
            pAudioRenderClient->Release();
            pAudioClient->Release();
            //CoUninitialize();
            return 0;
        }

        if (nFramesOfPadding == nFramesInBuffer) {
            hr = E_UNEXPECTED;
            ShowOutput("Got \"feed me\" event but IAudioClient::GetCurrentPadding reports buffer is full - glitch?\n"); 
			// he said he ran into ths at least once?
            /*pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            CloseHandle(hFeedMe);
            pAudioRenderClient->Release();
            pAudioClient->Release();
            //CoUninitialize();
            return 0; */
        }
    
        hr = pAudioRenderClient->GetBuffer(nFramesInBuffer - nFramesOfPadding, &pData);
        if (FAILED(hr)) {
            printf("IAudioRenderClient::GetBuffer failed on pass %u: hr = 0x%08x - glitch?\n", nPasses, hr);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            CloseHandle(hFeedMe);
            pAudioRenderClient->Release();
            pAudioClient->Release();
            //CoUninitialize();
            return 0;
        }

        // *** AT THIS POINT ***
        // If you wanted to render something besides silence,
        // you would fill the buffer pData
        // with (nFramesInBuffer - nFramesOfPadding) worth of audio data
        // this should be in the same wave format
        // that the stream was initialized with
        //
        // In particular, if you didn't want to use the mix format,
        // you would need to either ask for a different format in IAudioClient::Initialize
        // or do a format conversion
        //
        // If you do, then change the AUDCLNT_BUFFERFLAGS_SILENT flags value below to 0

        // release the buffer with the silence flag
        hr = pAudioRenderClient->ReleaseBuffer(nFramesInBuffer - nFramesOfPadding, AUDCLNT_BUFFERFLAGS_SILENT);
        if (FAILED(hr)) {
            printf("IAudioRenderClient::ReleaseBuffer failed on pass %u: hr = 0x%08x - glitch?\n", nPasses, hr);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            CloseHandle(hFeedMe);
            pAudioRenderClient->Release();
            pAudioClient->Release();
            //CoUninitialize();
            return 0;
        }        
    } // for each pass

    pAudioClient->Stop();
    AvRevertMmThreadCharacteristics(hTask);
    CloseHandle(hFeedMe);
    pAudioRenderClient->Release();
    pAudioClient->Release();
    //CoUninitialize();
    return 0;
}


================================================
FILE: source_code/acam/silence_control.cpp
================================================
#include "stdafx.h"
#include <stdio.h>
#include "silence.h"

IMMDevice *m_pMMSilenceDevice;

HANDLE hStartedEvent;
HANDLE hStopEvent;
HANDLE hThread;
DWORD WINAPI PlaySilenceThreadFunction(LPVOID pContext);
PlaySilenceThreadFunctionArguments threadArgs;

HRESULT start_silence_thread() {
    // create a "silence has started playing" event
    hStartedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (NULL == hStartedEvent) {
        printf("CreateEvent failed: last error is %u\n", GetLastError());
        return __LINE__;
    }

    // create a "stop playing silence now" event
    hStopEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    if (NULL == hStopEvent) {
        printf("CreateEvent failed: last error is %u\n", GetLastError());
        CloseHandle(hStartedEvent);
        return __LINE__;
    }
    HRESULT hr = get_default_device(&m_pMMSilenceDevice);
	 if (FAILED(hr)) {
        printf("get_def_device failed: hr = 0x%08x\n", hr);
        return __LINE__;
    }
    // create arguments for silence-playing thread

    threadArgs.hr = E_UNEXPECTED; // thread will overwrite this
    threadArgs.hStartedEvent = hStartedEvent;
    threadArgs.hStopEvent = hStopEvent;
    threadArgs.pMMDevice = m_pMMSilenceDevice;

    hThread = CreateThread(
        NULL, 0,
        PlaySilenceThreadFunction, &threadArgs,
        0, NULL
    );
    if (NULL == hThread) {
        printf("CreateThread failed: last error is %u\n", GetLastError());
        CloseHandle(hStopEvent);
        CloseHandle(hStartedEvent);
        return __LINE__;
    }

    // wait for either silence to start or the thread to end/abort unexpectedly :|
    HANDLE waitArray[2] = { hStartedEvent, hThread };
    DWORD dwWaitResult;
    dwWaitResult = WaitForMultipleObjects(
        ARRAYSIZE(waitArray), waitArray,
        FALSE, INFINITE
    );

    if (WAIT_OBJECT_0 + 1 == dwWaitResult) {
        printf("Thread aborted before starting to play silence: hr = 0x%08x\n", threadArgs.hr);
        CloseHandle(hStartedEvent);
        CloseHandle(hThread);
        CloseHandle(hStopEvent);
        return __LINE__;
    }

    if (WAIT_OBJECT_0 != dwWaitResult) {
        printf("Unexpected WaitForMultipleObjects return value %u: last error is %u\n", dwWaitResult, GetLastError());
        CloseHandle(hStartedEvent);
        CloseHandle(hThread);
        CloseHandle(hStopEvent);
        return __LINE__;
    }

    CloseHandle(hStartedEvent);
	return S_OK;
}

HRESULT join_silence_thread() {
	SetEvent(hStopEvent);
	WaitForSingleObject(hThread, INFINITE);

	// wait for the thread to terminate
	HANDLE rhHandles[1] = { hThread };

	DWORD exitCode;
	if (!GetExitCodeThread(hThread, &exitCode)) {
		printf("GetExitCodeThread failed: last error is %u\n", GetLastError());
		CloseHandle(hThread);
		CloseHandle(hStopEvent);
		return __LINE__;
	}

	if (0 != exitCode) {
		printf("Silence thread exit code is %u; expected 0\n", exitCode);
		CloseHandle(hThread);
		CloseHandle(hStopEvent);
		return __LINE__;
	}

	/*    if (S_OK != threadArgs.hr) { // didn't care enuf :|
	printf("Thread HRESULT is 0x%08x\n", threadArgs.hr);
	CloseHandle(hThread);
	CloseHandle(hStopEvent);
	return __LINE__;
	} */

	CloseHandle(hThread);
	CloseHandle(hStopEvent);
	ShowOutput("silence thread done success!");
	return S_OK;
}


================================================
FILE: source_code/acam/stdafx.cpp
================================================
// stdafx.cpp : source file that includes just the standard includes
// acam.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

// TODO: reference any additional headers you need in STDAFX.H
// and not in this file


================================================
FILE: source_code/acam/stdafx.h
================================================
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#include "targetver.h"

#define WIN32_LEAN_AND_MEAN             // Exclude rarely-used stuff from Windows headers
// Windows Header Files:
#include <windows.h>


================================================
FILE: source_code/acam/targetver.h
================================================
#pragma once

// Including SDKDDKVer.h defines the highest available Windows platform.

// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.

#include <SDKDDKVer.h>


================================================
FILE: source_code/acam/utilities.cpp
================================================
#include "stdafx.h"
#include <stdio.h>

/* unused ...
void logToFile(char *log_this) {
    FILE *f;
	f = fopen("g:\\yo2", "a");
	fprintf(f, log_this);
	fclose(f);
} */

void ShowOutput(const char *str, ...)
{
#ifdef _DEBUG  // avoid in release mode
  char buf[2048];
  va_list ptr;
  va_start(ptr,str);
  vsprintf_s(buf,str,ptr);
  OutputDebugStringA(buf);
  OutputDebugStringA("\n");
  //printf("%s\n", buf);
  //logToFile(buf);
  va_end(ptr);
#endif
}

HRESULT set_config_string_setting(LPCTSTR szValueName, wchar_t *szToThis) {

   HKEY hKey = NULL;
   LONG i;

    DWORD dwDisp = 0;
    LPDWORD lpdwDisp = &dwDisp;

    i = RegCreateKeyEx(HKEY_CURRENT_USER,
       L"SOFTWARE\\virtual_audio_capture", 0L, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | KEY_WOW64_32KEY, NULL, &hKey, lpdwDisp); // might fail in flash player...?

    if (i == ERROR_SUCCESS)
    {
		// bad for XP  ... = RegSetKeyValueA(hKey, NULL, szValueName, REG_SZ, ...
        i = RegSetValueEx(hKey, szValueName, 0, REG_SZ, (LPBYTE) szToThis, wcslen(szToThis)*2+1);

    } else {
       // failed to create key...
	}

	if(hKey)
	  RegCloseKey(hKey);
	return i;

}


================================================
FILE: source_code/acam_is_where_all_the_code_is
================================================


================================================
FILE: source_code/startup_debug_options
================================================
C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\graphedt
c:\dev\ruby\virtual-audio-output-sniffer\yo.grf

C:\installs\graphstudionext.exe

c:\dev\virtual-audio-capture-grabber-device\source_code\yo2.grf

C:\Program Files (x86)\VideoLAN\VLC\vlc.exe
dshow://  :dshow-vdev=none :dshow-adev="virtual-audio-capturer"  :dshow-caching=100

C:\Program Files (x86)\Adobe\Flash Media Live Encoder 3.2\FlashMediaLiveEncoder.exe

C:\Program Files (x86)\VideoLAN\VLC\vlc.exe 
dshow://  :dshow-vdev=none :dshow-adev="virtual-audio-capturer"  :dshow-caching=50
C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\graphedt.exe

c:\dev\ruby\sensible-cinema\vendor\cache\ffmpeg\ffmpeg.exe
-y -f dshow -i audio=virtual-audio-capturer -t 5 yo.wav

c:\vids\ffmpeg.exe
-f dshow  -i audio=virtual-audio-capturer -y yo.mp4

================================================
FILE: source_code/synth_deprecated/Synth.vcxproj
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Debug|x64">
      <Configuration>Debug</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|x64">
      <Configuration>Release</Configuration>
      <Platform>x64</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{BF20BC76-A330-4857-830B-80C85660478B}</ProjectGuid>
    <RootNamespace>Synth</RootNamespace>
    <Keyword>Win32Proj</Keyword>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
    <ConfigurationType>DynamicLibrary</ConfigurationType>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup>
    <_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</OutDir>
    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Debug\</IntDir>
    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</LinkIncremental>
    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</OutDir>
    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Release\</IntDir>
    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</LinkIncremental>
    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</OutDir>
    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Platform)\$(Configuration)\</IntDir>
    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</LinkIncremental>
    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</OutDir>
    <IntDir Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(Platform)\$(Configuration)\</IntDir>
    <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</LinkIncremental>
    <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">G:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses;$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(WindowsSdkDir)include;$(FrameworkSDKDir)\include;</IncludePath>
    <LibraryPath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(WindowsSdkDir)lib;$(FrameworkSDKDir)\lib;G:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Debug</LibraryPath>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <AdditionalIncludeDirectories>..\..\BaseClasses\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SYNTH_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MinimalRebuild>true</MinimalRebuild>
      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
      <CallingConvention>StdCall</CallingConvention>
    </ClCompile>
    <Link>
      <AdditionalDependencies>strmbasd.lib;winmm.lib;msvcrtd.lib;Msacm32.lib;comctl32.lib;%(AdditionalDependencies);Avrt.lib</AdditionalDependencies>
      <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
      <ModuleDefinitionFile>synth.def</ModuleDefinitionFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <SubSystem>Windows</SubSystem>
      <TargetMachine>MachineX86</TargetMachine>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <Optimization>MaxSpeed</Optimization>
      <AdditionalIncludeDirectories>..\..\BaseClasses\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SYNTH_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <CallingConvention>StdCall</CallingConvention>
    </ClCompile>
    <Link>
      <AdditionalDependencies>..\..\BaseClasses\Release\strmbase.lib;winmm.lib;msvcrt.lib;Msacm32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
      <ModuleDefinitionFile>synth.def</ModuleDefinitionFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <SubSystem>Windows</SubSystem>
      <OptimizeReferences>true</OptimizeReferences>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <TargetMachine>MachineX86</TargetMachine>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
    <Midl>
      <TargetEnvironment>X64</TargetEnvironment>
    </Midl>
    <ClCompile>
      <Optimization>Disabled</Optimization>
      <AdditionalIncludeDirectories>..\..\BaseClasses\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;SYNTH_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <MinimalRebuild>true</MinimalRebuild>
      <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <CallingConvention>StdCall</CallingConvention>
    </ClCompile>
    <Link>
      <AdditionalDependencies>strmbasd.lib;winmm.lib;msvcrtd.lib;Msacm32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories>..\..\BaseClasses\x64\Debug\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
      <ModuleDefinitionFile>synth.def</ModuleDefinitionFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <SubSystem>Windows</SubSystem>
      <TargetMachine>MachineX64</TargetMachine>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <Midl>
      <TargetEnvironment>X64</TargetEnvironment>
    </Midl>
    <ClCompile>
      <Optimization>MaxSpeed</Optimization>
      <AdditionalIncludeDirectories>..\..\BaseClasses\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;SYNTH_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <CallingConvention>StdCall</CallingConvention>
    </ClCompile>
    <Link>
      <AdditionalDependencies>strmbase.lib;winmm.lib;msvcrt.lib;Msacm32.lib;comctl32.lib;%(AdditionalDependencies)</AdditionalDependencies>
      <AdditionalLibraryDirectories>..\..\BaseClasses\x64\Release\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <IgnoreAllDefaultLibraries>true</IgnoreAllDefaultLibraries>
      <ModuleDefinitionFile>synth.def</ModuleDefinitionFile>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <SubSystem>Windows</SubSystem>
      <OptimizeReferences>true</OptimizeReferences>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <TargetMachine>MachineX64</TargetMachine>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="dynsrc.cpp" />
    <ClCompile Include="loopback-capture-helpers.cpp" />
    <ClCompile Include="loopback-capture.cpp" />
    <ClCompile Include="synth.cpp" />
    <ClCompile Include="synthprp.cpp" />
    <ClCompile Include="useless_synth.cpp" />
  </ItemGroup>
  <ItemGroup>
    <None Include="synth.def" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="dynsrc.h" />
    <ClInclude Include="isynth.h" />
    <ClInclude Include="resource.h" />
    <ClInclude Include="synth.h" />
    <ClInclude Include="synthprp.h" />
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="synth.rc" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>

================================================
FILE: source_code/synth_deprecated/Synth.vcxproj.filters
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="dynsrc.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="synth.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="synthprp.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="useless_synth.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="loopback-capture.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="loopback-capture-helpers.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <None Include="synth.def">
      <Filter>Source Files</Filter>
    </None>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="dynsrc.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="isynth.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="resource.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="synth.h">
      <Filter>Header Files</Filter>
    </ClInclude>
    <ClInclude Include="synthprp.h">
      <Filter>Header Files</Filter>
    </ClInclude>
  </ItemGroup>
  <ItemGroup>
    <ResourceCompile Include="synth.rc">
      <Filter>Resource Files</Filter>
    </ResourceCompile>
  </ItemGroup>
</Project>

================================================
FILE: source_code/synth_deprecated/Synth.vcxproj.user
================================================
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LocalDebuggerCommand>c:\Program Files\VideoLAN\vlc\vlc.exe</LocalDebuggerCommand>
    <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
  </PropertyGroup>
</Project>

================================================
FILE: source_code/synth_deprecated/dynsrc.cpp
================================================
//------------------------------------------------------------------------------
// File: DynSrc.cpp
//
// Desc: DirectShow sample code - implements CDynamicSource, which is a
//       Quartz source filter.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------


// I think this is not what I'm looking for, move along now...

// Locking Strategy.
//
// Hold the filter critical section (m_pFilter->pStateLock()) to serialise
// access to functions. Note that, in general, this lock may be held
// by a function when the worker thread may want to hold it. Therefore
// if you wish to access shared state from the worker thread you will
// need to add another critical section object. The execption is during
// the threads processing loop, when it is safe to get the filter critical
// section from within FillBuffer().

// I think we don't have to worry about this one...


#include <windows.h>
#include <streams.h>

#include "DynSrc.h"


CDynamicSource::CDynamicSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr)
    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
      m_iPins(0),
      m_paStreams(NULL),
      m_evFilterStoppingEvent(TRUE)
{
    ASSERT(phr);
    
    // Make sure the event was successfully created.
    if( NULL == (HANDLE)m_evFilterStoppingEvent ) {
        if (phr)
            *phr = E_FAIL;
    }
}


#ifdef UNICODE
CDynamicSource::CDynamicSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr)
    : CBaseFilter(pName, lpunk, &m_cStateLock, clsid),
      m_iPins(0),
      m_paStreams(NULL),
      m_evFilterStoppingEvent(TRUE)
{
    ASSERT(phr);

    // Make sure the event was successfully created.
    if( NULL == (HANDLE)m_evFilterStoppingEvent ) {
        if (phr)
            *phr = E_FAIL;
    }
}
#endif


//
// CDynamicSource::Destructor
//
CDynamicSource::~CDynamicSource()
{
    /*  Free our pins and pin array */
    while (m_iPins != 0) 
    {
        // deleting the pins causes them to be removed from the array...
        delete m_paStreams[m_iPins - 1];
    }

    ASSERT(m_paStreams == NULL);
}


//
//  Add a new pin
//
HRESULT CDynamicSource::AddPin(CDynamicSourceStream *pStream)
{
    // This function holds the filter state lock because
    // it changes the number of pins.  The number of pins
    // cannot be change while another thread is calling
    // IMediaFilter::Run(), IMediaFilter::Stop(), 
    // IMediaFilter::Pause() or IBaseFilter::FindPin().
    CAutoLock lock(&m_cStateLock);

    // This function holds the pin state lock because it
    // uses m_iPins and m_paStreams.
    CAutoLock alPinStateLock(&m_csPinStateLock);

    /*  Allocate space for this pin and the old ones */
    CDynamicSourceStream **paStreams = new CDynamicSourceStream *[m_iPins + 1];
    if (paStreams == NULL)
        return E_OUTOFMEMORY;

    if (m_paStreams != NULL) 
    {
        CopyMemory((PVOID)paStreams, (PVOID)m_paStreams,
                   m_iPins * sizeof(m_paStreams[0]));

        paStreams[m_iPins] = pStream;
        delete [] m_paStreams;
    }

    m_paStreams = paStreams;
    m_paStreams[m_iPins] = pStream;
    m_iPins++;

    return S_OK;
}


//
//  Remove a pin - pStream is NOT deleted
//
HRESULT CDynamicSource::RemovePin(CDynamicSourceStream *pStream)
{
    // This function holds the filter state lock because
    // it changes the number of pins.  The number of pins
    // cannot be change while another thread is calling
    // IMediaFilter::Run(), IMediaFilter::Stop(), 
    // IMediaFilter::Pause() or IBaseFilter::FindPin().
    CAutoLock lock(&m_cStateLock);    

    // This function holds the pin state lock because it
    // uses m_iPins and m_paStreams.
    CAutoLock alPinStateLock(&m_csPinStateLock);

    for(int i = 0; i < m_iPins; i++)
    {
        if(m_paStreams[i] == pStream)
        {
            if(m_iPins == 1)
            {
                delete [] m_paStreams;
                m_paStreams = NULL;
            }
            else
            {
                /*  no need to reallocate */
                while(++i < m_iPins)
                    m_paStreams[i - 1] = m_paStreams[i];
            }

            m_iPins--;
            return S_OK;
        }
    }

    return S_FALSE;
}


//
// FindPin
//
// Set *ppPin to the IPin* that has the id Id.
// or to NULL if the Id cannot be matched.
STDMETHODIMP CDynamicSource::FindPin(LPCWSTR Id, IPin **ppPin)
{
    CAutoLock alPinStateLock(&m_csPinStateLock);

    CheckPointer(ppPin,E_POINTER);
    ValidateReadWritePtr(ppPin,sizeof(IPin *));

    // The -1 undoes the +1 in QueryId and ensures that totally invalid
    // strings (for which WstrToInt delivers 0) give a deliver a NULL pin.
    int i = WstrToInt(Id) -1;

    *ppPin = GetPin(i);
    if (*ppPin!=NULL)
    {
        (*ppPin)->AddRef();
        return NOERROR;
    }

    return VFW_E_NOT_FOUND;
}


//
// FindPinNumber
//
// return the number of the pin with this IPin* or -1 if none
int CDynamicSource::FindPinNumber(IPin *iPin) 
{

    // This function holds the pin state lock because it
    // uses m_iPins and m_paStreams.
    CAutoLock alPinStateLock(&m_csPinStateLock);

    for (int i=0; i<m_iPins; ++i) 
    {
        if ((IPin *)(m_paStreams[i]) == iPin) 
        {
            return i;
        }
    }

    return -1;
}


//
// GetPinCount
//
// Returns the number of pins this filter has
int CDynamicSource::GetPinCount(void) 
{

    // This function holds the pin state lock because it
    // uses m_iPins.
    CAutoLock alPinStateLock(&m_csPinStateLock);
    return m_iPins;
}


//
// GetPin
//
// Return a non-addref'd pointer to pin n
// needed by CBaseFilter
CBasePin *CDynamicSource::GetPin(int n)
{
    // This function holds the pin state lock because it
    // uses m_iPins and m_paStreams.
    CAutoLock alPinStateLock(&m_csPinStateLock);

    // n must be in the range 0..m_iPins-1
    // if m_iPins>n  && n>=0 it follows that m_iPins>0
    // which is what used to be checked (i.e. checking that we have a pin)
    if((n >= 0) && (n < m_iPins))
    {
        ASSERT(m_paStreams[n]);
        return m_paStreams[n];
    }

    return NULL;
}


STDMETHODIMP CDynamicSource::Stop(void)
{
    m_evFilterStoppingEvent.Set();

    HRESULT hr = CBaseFilter::Stop();

    // The following code ensures that a pins thread will be destroyed even 
    // if the pin is disconnected when CBaseFilter::Stop() is called.
    int nCurrentPin;
    CDynamicSourceStream* pOutputPin;
    {
        // This code holds the pin state lock because it
        // does not want the number of pins to change 
        // while it executes.
        CAutoLock alPinStateLock(&m_csPinStateLock);

        for(nCurrentPin = 0; nCurrentPin < GetPinCount(); nCurrentPin++)
        {
            pOutputPin = (CDynamicSourceStream*)GetPin(nCurrentPin);
            if(pOutputPin->ThreadExists())
            {
                pOutputPin->DestroySourceThread();
            }
        }
    }

    if(FAILED(hr))
    {
        return hr;
    }

    return NOERROR;
}


STDMETHODIMP CDynamicSource::Pause(void)
{
    m_evFilterStoppingEvent.Reset();

    return CBaseFilter::Pause();
}


STDMETHODIMP CDynamicSource::JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName)
{
    CAutoLock lock(&m_cStateLock);

    HRESULT hr;
    int nCurrentPin;
    CDynamicSourceStream* pOutputPin;

    // The filter is joining the filter graph.
    if(NULL != pGraph)
    {
        IGraphConfig* pGraphConfig = NULL;

        hr = pGraph->QueryInterface(IID_IGraphConfig, (void**)&pGraphConfig);
        if(FAILED(hr))
        {
            return hr;
        }

        hr = CBaseFilter::JoinFilterGraph(pGraph, pName);
        if(FAILED(hr))
        {
            pGraphConfig->Release();
            return hr;
        }

        for(nCurrentPin = 0; nCurrentPin < GetPinCount(); nCurrentPin++)
        {
            pOutputPin = (CDynamicSourceStream*) GetPin(nCurrentPin);
            pOutputPin->SetConfigInfo(pGraphConfig, m_evFilterStoppingEvent);
        }

        pGraphConfig->Release();
    }
    else
    {
        hr = CBaseFilter::JoinFilterGraph(pGraph, pName);
        if(FAILED(hr))
        {
            return hr;
        }

        for(nCurrentPin = 0; nCurrentPin < GetPinCount(); nCurrentPin++)
        {
            pOutputPin = (CDynamicSourceStream*)GetPin(nCurrentPin);
            pOutputPin->SetConfigInfo(NULL, NULL);
        }
    }

    return S_OK;
}


// *
// * --- CDynamicSourceStream ----
// *

//
// Set Id to point to a CoTaskMemAlloc'd
STDMETHODIMP CDynamicSourceStream::QueryId(LPWSTR *pId)
{
    CheckPointer(pId,E_POINTER);
    ValidateReadWritePtr(pId,sizeof(LPWSTR));

    // We give the pins id's which are 1,2,...
    // FindPinNumber returns -1 for an invalid pin
    int i = 1+ m_pFilter->FindPinNumber(this);

    if(i<1) 
        return VFW_E_NOT_FOUND;

    *pId = (LPWSTR)CoTaskMemAlloc(4*sizeof(WCHAR));
    if(*pId==NULL)
    {
        return E_OUTOFMEMORY;
    }

    IntToWstr(i, *pId);
    return NOERROR;
}


//
// CDynamicSourceStream::Constructor
//
// increments the number of pins present on the filter
CDynamicSourceStream::CDynamicSourceStream(
    TCHAR *pObjectName,
    HRESULT *phr,
    CDynamicSource*ps,
    LPCWSTR pPinName)
    : CDynamicOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
      m_pFilter(ps),
      m_fReconnectOutputPin(false)
{
    ASSERT(phr);   
    *phr = m_pFilter->AddPin(this);
}


#ifdef UNICODE

CDynamicSourceStream::CDynamicSourceStream(
    char *pObjectName,
    HRESULT *phr,
    CDynamicSource*ps,
    LPCWSTR pPinName)
    : CDynamicOutputPin(pObjectName, ps, ps->pStateLock(), phr, pPinName),
      m_pFilter(ps),
      m_fReconnectOutputPin(false)
{
    ASSERT(phr);
    *phr = m_pFilter->AddPin(this);
}

#endif


//
// CDynamicSourceStream::Destructor
//
// Decrements the number of pins on this filter
CDynamicSourceStream::~CDynamicSourceStream(void)
{
    m_pFilter->RemovePin(this);
}


//
// CheckMediaType
//
// Do we support this type? Provides the default support for 1 type.
HRESULT CDynamicSourceStream::CheckMediaType(const CMediaType *pMediaType)
{
    CheckPointer(pMediaType,E_POINTER);
    CAutoLock lock(m_pFilter->pStateLock());

    CMediaType mt;
    GetMediaType(&mt);

    if(mt == *pMediaType)
    {
        return NOERROR;
    }

    return E_FAIL;
}


//
// GetMediaType
//
// By default we support only one type
// iPosition indexes are 0-n
HRESULT CDynamicSourceStream::GetMediaType(int iPosition, CMediaType *pMediaType)
{
    CAutoLock lock(m_pFilter->pStateLock());

    if(iPosition<0)
    {
        return E_INVALIDARG;
    }
    if(iPosition>0)
    {
        return VFW_S_NO_MORE_ITEMS;
    }

    return GetMediaType(pMediaType);
}


//
// Active
//
// The pin is active - start up the worker thread
HRESULT CDynamicSourceStream::Active(void)
{
    CAutoLock lock(m_pFilter->pStateLock());

    HRESULT hr;

    if(m_pFilter->IsActive())
    {
        return S_FALSE; // succeeded, but did not allocate resources (they already exist...)
    }

    // do nothing if not connected - its ok not to connect to
    // all pins of a source filter
    if(!IsConnected())
    {
        return NOERROR;
    }

    hr = CDynamicOutputPin::Active();
    if(FAILED(hr))
    {
        return hr;
    }

    ASSERT(!ThreadExists());

    // start the thread
    if(!Create())
    {
        return E_FAIL;
    }

    // Tell thread to initialize. If OnThreadCreate Fails, so does this.
    hr = Init();
    if(FAILED(hr))
        return hr;

    return Pause();
}


HRESULT CDynamicSourceStream::BreakConnect(void)
{
    HRESULT hr = CDynamicOutputPin::BreakConnect();
    if(FAILED(hr))
    {
        return hr;
    }

    m_fReconnectOutputPin = false;

    return S_OK;
}


HRESULT CDynamicSourceStream::DestroySourceThread(void)
{
    // The pin's thread cannot be destroyed if the thread does not exist.
    ASSERT(ThreadExists());

    HRESULT hr = Stop();
    if(FAILED(hr))
    {
        return hr;
    }

    hr = Exit();
    if(FAILED(hr))
    {
        return hr;
    }

    Close();    // Wait for the thread to exit, then tidy up.

    return NOERROR;
}


//
// ThreadProc
//
// When this returns the thread exits
// Return codes > 0 indicate an error occured
DWORD CDynamicSourceStream::ThreadProc(void)
{
    HRESULT hr;  // the return code from calls
    Command com;

    do
    {
        com = GetRequest();
        if(com != CMD_INIT)
        {
            DbgLog((LOG_ERROR, 1, TEXT("Thread expected init command")));
            Reply((DWORD) E_UNEXPECTED);
        }

    } while(com != CMD_INIT);

    DbgLog((LOG_TRACE, 1, TEXT("CDynamicSourceStream worker thread initializing")));

    hr = OnThreadCreate(); // perform set up tasks
    if(FAILED(hr))
    {
        DbgLog((LOG_ERROR, 1, TEXT("CDynamicSourceStream::OnThreadCreate failed. Aborting thread.")));

        OnThreadDestroy();
        Reply(hr);  // send failed return code from OnThreadCreate
        return 1;
    }

    // Initialisation suceeded
    Reply(NOERROR);

    Command cmd;
    do
    {
        cmd = GetRequest();

        switch(cmd)
        {
            case CMD_EXIT:
                Reply(NOERROR);
                break;

            case CMD_RUN:
                DbgLog((LOG_ERROR, 1, TEXT("CMD_RUN received before a CMD_PAUSE???")));
                // !!! fall through

            case CMD_PAUSE:
                Reply(NOERROR);
                DoBufferProcessingLoop();
                break;

            case CMD_STOP:
                Reply(NOERROR);
                break;

            default:
                DbgLog((LOG_ERROR, 1, TEXT("Unknown command %d received!"), cmd));
                Reply((DWORD) E_NOTIMPL);
                break;
        }

    } while(cmd != CMD_EXIT);

    hr = OnThreadDestroy(); // tidy up.
    if(FAILED(hr))
    {
        DbgLog((LOG_ERROR, 1, TEXT("CDynamicSourceStream::OnThreadDestroy failed. Exiting thread.")));
        return 1;
    }

    DbgLog((LOG_TRACE, 1, TEXT("CDynamicSourceStream worker thread exiting")));
    return 0;
}


//
// DoBufferProcessingLoop
//
// Grabs a buffer and calls the users processing function.
// Overridable, so that different delivery styles can be catered for.
HRESULT CDynamicSourceStream::DoBufferProcessingLoop(void)
{
    Command com;
    bool fOutputFormatChanged = false;

    OnThreadStartPlay();

    do
    {
        while(!CheckRequest(&com))
        {
            // CAutoUsingOutputPin::CAutoUsingOutputPin() only changes the value of hr
            // if an error occurs.
            HRESULT hr = S_OK;

            CAutoUsingOutputPin auopUsingOutputPin(this, &hr);
            if(FAILED(hr))
            {
                FatalError(hr);
                return hr;
            }

            if(m_fReconnectOutputPin)
            {
                hr = DynamicReconnect(NULL);

                m_fReconnectOutputPin = false;

                if(FAILED(hr))
                {
                    FatalError(hr);
                    return hr;
                }

                fOutputFormatChanged = true;
            }

            IMediaSample *pSample;

            hr = GetDeliveryBuffer(&pSample,NULL,NULL,0);
            if(FAILED(hr))
            {
                Sleep(1);
                continue;   // go round again. Perhaps the error will go away
                // or the allocator is decommited & we will be asked to
                // exit soon.
            }

            if(fOutputFormatChanged)
            {
                pSample->SetDiscontinuity(TRUE);
                fOutputFormatChanged = false;
            }

            // Virtual function user will override.
            hr = FillBuffer(pSample);

            if(hr == S_OK)
            {
                hr = Deliver(pSample);
                pSample->Release();

                // downstream filter returns S_FALSE if it wants us to
                // stop or an error if it's reporting an error.
                if(hr != S_OK)
                {
                    DbgLog((LOG_TRACE, 2, TEXT("Deliver() returned %08x; stopping"), hr));
                    return S_OK;
                }

            }
            else if(hr == S_FALSE)
            {
                // derived class wants us to stop pushing data
                pSample->Release();
                DeliverEndOfStream();
                return S_OK;
            }
            else
            {
                // derived class encountered an error
                pSample->Release();
                DbgLog((LOG_ERROR, 1, TEXT("Error %08lX from FillBuffer!!!"), hr));

                FatalError(hr);
                return hr;
            }
            // all paths release the sample
        }

        // For all commands sent to us there must be a Reply call!
        if(com == CMD_RUN || com == CMD_PAUSE)
        {
            Reply(NOERROR);
        }
        else if(com != CMD_STOP)
        {
            Reply((DWORD) E_UNEXPECTED);
            DbgLog((LOG_ERROR, 1, TEXT("Unexpected command!!!")));
        }
    } while(com != CMD_STOP);

    return S_FALSE;
}


void CDynamicSourceStream::FatalError(HRESULT hr)
{
    // Make sure the user is reporting a failure.
    ASSERT(FAILED(hr));

    m_bRunTimeError = TRUE;
    DeliverEndOfStream();
    m_pFilter->NotifyEvent(EC_ERRORABORT, hr, 0);
}


void CDynamicSourceStream::OutputPinNeedsToBeReconnected(void)
{
    m_fReconnectOutputPin = true;
}



================================================
FILE: source_code/synth_deprecated/dynsrc.h
================================================
//------------------------------------------------------------------------------
// File: DynSrc.h
//
// Desc: DirectShow sample code - defines classes to simplify creation of
//       ActiveX source filters that support continuous generation of data.
//       No support is provided for IMediaControl or IMediaPosition.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------


//
// Derive your source filter from CDynamicSource.
// During construction either:
//    Create some CDynamicSourceStream objects to manage your pins
//    Provide the user with a means of doing so eg, an IPersistFile interface.
//
// CDynamicSource provides:
//    IBaseFilter interface management
//    IMediaFilter interface management, via CBaseFilter
//    Pin counting for CBaseFilter
//
// Derive a class from CDynamicSourceStream to manage your output pin types
//  Implement GetMediaType/1 to return the type you support. If you support multiple
//   types then overide GetMediaType/3, CheckMediaType and GetMediaTypeCount.
//  Implement Fillbuffer() to put data into one buffer.
//
// CDynamicSourceStream provides:
//    IPin management via CDynamicOutputPin
//    Worker thread management

#ifndef __CDYNAMICSOURCE__
#define __CDYNAMICSOURCE__

class CDynamicSourceStream;  // The class that will handle each pin


//
// CDynamicSource
//
// Override construction to provide a means of creating
// CDynamicSourceStream derived objects - ie a way of creating pins.
class CDynamicSource: public CBaseFilter {
public:

    CDynamicSource(TCHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
#ifdef UNICODE
    CDynamicSource(CHAR *pName, LPUNKNOWN lpunk, CLSID clsid, HRESULT *phr);
#endif
    ~CDynamicSource();

    int       GetPinCount(void);
    CBasePin *GetPin(int n);

    // -- Utilities --

    CCritSec*   pStateLock(void) { return &m_cStateLock; }  // provide our critical section

    HRESULT     AddPin(CDynamicSourceStream *);
    HRESULT     RemovePin(CDynamicSourceStream *);

    STDMETHODIMP FindPin(
        LPCWSTR Id,
        IPin ** ppPin
    );

    int FindPinNumber(IPin *iPin);
    
    STDMETHODIMP JoinFilterGraph(IFilterGraph* pGraph, LPCWSTR pName);
    STDMETHODIMP Stop(void);
    STDMETHODIMP Pause(void);
    
protected:

    CAMEvent m_evFilterStoppingEvent;

    int m_iPins;    // The number of pins on this filter. Updated by 
                    // CDynamicSourceStream constructors & destructors.
                    
    CDynamicSourceStream **m_paStreams;   // the pins on this filter.

    // This lock must be held when m_paStreams or m_iPins
    // is being used.  The state lock (m_cStateLock) must 
    // also be held if the program wants to change the value
    // of m_paStreams or m_iPins.  Functions cannot acquire 
    // the state lock (m_cStateLock) after they acquire
    // m_csPinStateLock.  The program will deadlock if it
    // violates this rule.  Also the program may not acquire
    // m_csPinStateLock on the streaming thread.  If it does,
    // the program will deadlock.  The streaming thread calls
    // ThreadProc() and DoBufferProcessingLoop().
    CCritSec m_csPinStateLock;

    // This lock serializes accesses to the filter's state.
    // It also must be held when the program changes 
    // m_iPins's or m_paStreams's value.
    CCritSec m_cStateLock;

};


//
// CDynamicSourceStream
//
// Use this class to manage a stream of data that comes from a
// pin.
// Uses a worker thread to put data on the pin.
class CDynamicSourceStream : public CAMThread, public CDynamicOutputPin {
public:

    CDynamicSourceStream(TCHAR *pObjectName,
                         HRESULT *phr,
                         CDynamicSource*pms,
                         LPCWSTR pName);
#ifdef UNICODE
    CDynamicSourceStream(CHAR *pObjectName,
                         HRESULT *phr,
                         CDynamicSource*pms,
                         LPCWSTR pName);
#endif
    virtual ~CDynamicSourceStream(void);  // virtual destructor ensures derived 
                                          // class destructors are called too

    HRESULT DestroySourceThread(void);

protected:

    CDynamicSource*m_pFilter;             // The parent of this stream

    // *
    // * Data Source
    // *
    // * The following three functions: FillBuffer, OnThreadCreate/Destroy, are
    // * called from within the ThreadProc. They are used in the creation of
    // * the media samples this pin will provide
    // *

    // Override this to provide the worker thread a means
    // of processing a buffer
    virtual HRESULT FillBuffer(IMediaSample *pSamp) PURE;

    // Called as the thread is created/destroyed - use to perform
    // jobs such as start/stop streaming mode
    // If OnThreadCreate returns an error the thread will exit.
    virtual HRESULT OnThreadCreate(void) {return NOERROR;};
    virtual HRESULT OnThreadDestroy(void) {return NOERROR;};
    virtual HRESULT OnThreadStartPlay(void) {return NOERROR;};

    // *
    // * Worker Thread
    // *

    HRESULT Active(void);    // Starts up the worker thread

    HRESULT BreakConnect(void);

public:
    // thread commands
    enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT};

    HRESULT Init(void) { return CallWorker(CMD_INIT); }
    HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
    HRESULT Run(void) { return CallWorker(CMD_RUN); }
    HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
    HRESULT Stop(void) { return CallWorker(CMD_STOP); }

    void OutputPinNeedsToBeReconnected(void);

protected:
    Command GetRequest(void) { return (Command) CAMThread::GetRequest(); }
    BOOL    CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (DWORD *) pCom); }

    // override these if you want to add thread commands
    virtual DWORD ThreadProc(void);         // the thread function

    virtual HRESULT DoBufferProcessingLoop(void);    // the loop executed whilst running
    
    void FatalError(HRESULT hr);

    // *
    // * AM_MEDIA_TYPE support
    // *

    // If you support more than one media type then override these 2 functions
    virtual HRESULT CheckMediaType(const CMediaType *pMediaType);
    virtual HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);  // List pos. 0-n

    // If you support only one type then override this fn.
    // This will only be called by the default implementations
    // of CheckMediaType and GetMediaType(int, CMediaType*)
    // You must override this fn. or the above 2!
    virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}

    STDMETHODIMP QueryId(
        LPWSTR * Id
    );

    bool m_fReconnectOutputPin;
};
    
#endif // __CDYNAMICSOURCE__



================================================
FILE: source_code/synth_deprecated/isynth.h
================================================
//------------------------------------------------------------------------------
// File: ISynth.h
//
// Desc: DirectShow sample code - custom interface to allow the user to
//       adjust the frequency.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------


#ifndef __ISYNTH2__
#define __ISYNTH2__

#ifdef __cplusplus
extern "C" {
#endif


//
// ISynth2's GUID
//
// {00487A78-D875-44b0-ADBB-DECA9CDB51FC}
DEFINE_GUID(IID_ISynth2, 
0x487a78, 0xd875, 0x44b0, 0xad, 0xbb, 0xde, 0xca, 0x9c, 0xdb, 0x51, 0xfc);

enum SYNTH_OUTPUT_FORMAT
{
    SYNTH_OF_PCM,
    SYNTH_OF_MS_ADPCM
};

//
// ISynth2
//
DECLARE_INTERFACE_(ISynth2, IUnknown) {

    STDMETHOD(get_Frequency) (THIS_
                int *Frequency          /* [out] */    // the current frequency
             ) PURE;

    STDMETHOD(put_Frequency) (THIS_
                int    Frequency        /* [in] */    // Change to this frequency
             ) PURE;

    STDMETHOD(get_Waveform) (THIS_
                int *Waveform           /* [out] */    // the current Waveform
             ) PURE;

    STDMETHOD(put_Waveform) (THIS_
                int    Waveform         /* [in] */    // Change to this Waveform
             ) PURE;

    STDMETHOD(get_Channels) (THIS_
                int *Channels           /* [out] */   // the current Channels
             ) PURE;

    STDMETHOD(put_Channels) (THIS_
                int    Channels         /* [in] */    // Change to this Channels
             ) PURE;

    STDMETHOD(get_BitsPerSample) (THIS_
                int *BitsPerSample      /* [out] */   // the current BitsPerSample
             ) PURE;

    STDMETHOD(put_BitsPerSample) (THIS_
                int    BitsPerSample    /* [in] */    // Change to this BitsPerSample
             ) PURE;

    STDMETHOD(get_SamplesPerSec) (THIS_
                 int *SamplesPerSec     /* [out] */   // the current SamplesPerSec
             ) PURE;

    STDMETHOD(put_SamplesPerSec) (THIS_
                  int    SamplesPerSec  /* [in] */    // Change to this SamplesPerSec
             ) PURE;

    STDMETHOD(get_Amplitude) (THIS_
                  int *Amplitude        /* [out] */   // the current Amplitude
             ) PURE;

    STDMETHOD(put_Amplitude) (THIS_
                  int    Amplitude      /* [in] */    // Change to this Amplitude
              ) PURE;

    STDMETHOD(get_SweepRange) (THIS_
                  int *SweepStart,      /* [out] */
                  int *SweepEnd         /* [out] */
             ) PURE;

    STDMETHOD(put_SweepRange) (THIS_
                  int    SweepStart,    /* [in] */
                  int    SweepEnd       /* [in] */
             ) PURE;

    STDMETHOD(get_OutputFormat) (THIS_
                  SYNTH_OUTPUT_FORMAT *pOutputFormat /* [out] */
             ) PURE;

    STDMETHOD(put_OutputFormat) (THIS_
                  SYNTH_OUTPUT_FORMAT ofNewOutputFormat /* [out] */
             ) PURE;
    
};


#ifdef __cplusplus
}
#endif

#endif // __ISYNTH2__




================================================
FILE: source_code/synth_deprecated/loopback-capture-helpers.cpp
================================================

#include <windows.h>
#include <mmsystem.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <stdio.h>
#include <avrt.h>
#include <stdio.h>

HRESULT open_file(LPCWSTR szFileName, HMMIO *phFile) {
    MMIOINFO mi = {0};

    *phFile = mmioOpen(
        // some flags cause mmioOpen write to this buffer
        // but not any that we're using
        const_cast<LPWSTR>(szFileName),
        &mi,
        MMIO_WRITE | MMIO_CREATE
    );

    if (NULL == *phFile) {
        printf("mmioOpen(\"%ls\", ...) failed. wErrorRet == %u\n", szFileName, mi.wErrorRet);
        return E_FAIL;
    }

    return S_OK;
}


HRESULT get_default_device(IMMDevice **ppMMDevice) {
    HRESULT hr = S_OK;
    IMMDeviceEnumerator *pMMDeviceEnumerator;
    // activate a device enumerator
    hr = CoCreateInstance(
        __uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, 
        __uuidof(IMMDeviceEnumerator),
        (void**)&pMMDeviceEnumerator
    );
    if (FAILED(hr)) {
        printf("CoCreateInstance(IMMDeviceEnumerator) failed: hr = 0x%08x\n", hr);
        return hr;
    }

    // get the default render endpoint
    hr = pMMDeviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, ppMMDevice);
    pMMDeviceEnumerator->Release();
    if (FAILED(hr)) {
        printf("IMMDeviceEnumerator::GetDefaultAudioEndpoint failed: hr = 0x%08x\n", hr);
        return hr;
    }

    return S_OK;
}


================================================
FILE: source_code/synth_deprecated/loopback-capture.cpp
================================================
#include <windows.h>


#include <mmsystem.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <stdio.h>
#include <avrt.h>

HRESULT open_file(LPCWSTR szFileName, HMMIO *phFile);

HRESULT get_default_device(IMMDevice **ppMMDevice);

// size is size of the BYTE buffer...but...I guess...we just have to fill it all the way with data...I guess...
HRESULT LoopbackCapture(const WAVEFORMATEX& wfex, BYTE pBuf[], int iSize, WAVEFORMATEX* ifNotNullThenJustSetTypeOnly)
 {
	bool bInt16 = true; // makes it actually work, for some reason...

	UINT32 pnFrames = 0;

    HRESULT hr;
    IMMDevice *m_pMMDevice;
    hr = get_default_device(&m_pMMDevice); // so it can re-place our pointer...
    if (FAILED(hr)) {
        return hr;
    }

    // activate an (the default, for us) IAudioClient
    IAudioClient *pAudioClient;
    hr = m_pMMDevice->Activate(
        __uuidof(IAudioClient),
        CLSCTX_ALL, NULL,
        (void**)&pAudioClient
    );
    if (FAILED(hr)) {
        printf("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x", hr);
        return hr;
    }
    
    // get the default device periodicity
    REFERENCE_TIME hnsDefaultDevicePeriod;
    hr = pAudioClient->GetDevicePeriod(&hnsDefaultDevicePeriod, NULL);
    if (FAILED(hr)) {
        printf("IAudioClient::GetDevicePeriod failed: hr = 0x%08x\n", hr);
        pAudioClient->Release();
        return hr;
    }

    // get the default device format (incoming...)
    WAVEFORMATEX *pwfx; // incoming wave...
    hr = pAudioClient->GetMixFormat(&pwfx);
    if (FAILED(hr)) {
        printf("IAudioClient::GetMixFormat failed: hr = 0x%08x\n", hr);
        CoTaskMemFree(pwfx);
        pAudioClient->Release();
        return hr;
    }

    if (bInt16) {
        // coerce int-16 wave format
        // can do this in-place since we're not changing the size of the format
        // also, the engine will auto-convert from float to int for us
        switch (pwfx->wFormatTag) {
            case WAVE_FORMAT_IEEE_FLOAT:
                pwfx->wFormatTag = WAVE_FORMAT_PCM;
                pwfx->wBitsPerSample = 16;
                pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
                pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
                break;

            case WAVE_FORMAT_EXTENSIBLE:
                {
                    // naked scope for case-local variable
                    PWAVEFORMATEXTENSIBLE pEx = reinterpret_cast<PWAVEFORMATEXTENSIBLE>(pwfx);
                    if (IsEqualGUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, pEx->SubFormat)) {
						// WE GET HERE!
                        pEx->SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
                        pEx->Samples.wValidBitsPerSample = 16;
                        pwfx->wBitsPerSample = 16;
                        pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
                        pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;
                    } else {
                        printf("Don't know how to coerce mix format to int-16\n");
                        CoTaskMemFree(pwfx);
                        pAudioClient->Release();
                        return E_UNEXPECTED;
                    }
                }
                break;

            default:
                printf("Don't know how to coerce WAVEFORMATEX with wFormatTag = 0x%08x to int-16\n", pwfx->wFormatTag);
                CoTaskMemFree(pwfx);
                pAudioClient->Release();
                return E_UNEXPECTED;
        }
    }

	if(ifNotNullThenJustSetTypeOnly) {
		// pwfx is set at this point...
		WAVEFORMATEX* pwfex = ifNotNullThenJustSetTypeOnly;
		// copy them all out as the possible format...hmm...


		                pwfx->wFormatTag = WAVE_FORMAT_PCM;
                pwfx->wBitsPerSample = 16;
                pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
                pwfx->nAvgBytesPerSec = pwfx->nBlockAlign * pwfx->nSamplesPerSec;


		pwfex->wFormatTag = pwfx->wFormatTag;
		pwfex->nChannels = pwfx->nChannels;
        pwfex->nSamplesPerSec = pwfx->nSamplesPerSec;
        pwfex->wBitsPerSample = pwfx->wBitsPerSample;
        pwfex->nBlockAlign = pwfx->nBlockAlign;
        pwfex->nAvgBytesPerSec = pwfx->nAvgBytesPerSec;
        pwfex->cbSize = pwfx->cbSize;
		//FILE *fp = fopen("/normal2", "w"); // fails on me? maybe juts a VLC thing...
		//fprintf(fp, "hello world %d %d %d %d %d %d %d", pwfex->wFormatTag, pwfex->nChannels, 
		//	pwfex->nSamplesPerSec, pwfex->wBitsPerSample, pwfex->nBlockAlign, pwfex->nAvgBytesPerSec, pwfex->cbSize );
		//fclose(fp);
		// cleanup
		// I might be leaking here...
        m_pMMDevice->Release();
		return hr;
	}

    MMCKINFO ckRIFF = {0};
    MMCKINFO ckData = {0};

    // create a periodic waitable timer
	
    UINT32 nBlockAlign = pwfx->nBlockAlign;
    
    // call IAudioClient::Initialize
    // note that AUDCLNT_STREAMFLAGS_LOOPBACK and AUDCLNT_STREAMFLAGS_EVENTCALLBACK
    // do not work together...
    // the "data ready" event never gets set
    // so we're going to do a timer-driven loop...
    hr = pAudioClient->Initialize(
        AUDCLNT_SHAREMODE_SHARED,
        AUDCLNT_STREAMFLAGS_LOOPBACK,
        0, 0, pwfx, 0
    );
    if (FAILED(hr)) {
        printf("IAudioClient::Initialize failed: hr = 0x%08x\n", hr);
        pAudioClient->Release();
        return hr;
    }
    CoTaskMemFree(pwfx);

    // activate an IAudioCaptureClient
    IAudioCaptureClient *pAudioCaptureClient;
    hr = pAudioClient->GetService(
        __uuidof(IAudioCaptureClient),
        (void**)&pAudioCaptureClient
    );
    if (FAILED(hr)) {
        printf("IAudioClient::GetService(IAudioCaptureClient) failed: hr 0x%08x\n", hr);
        //CloseHandle(hWakeUp);
        pAudioClient->Release();
        return hr;
    }
    
    // register with MMCSS
    DWORD nTaskIndex = 0;
    HANDLE hTask = AvSetMmThreadCharacteristics(L"Capture", &nTaskIndex);
    if (NULL == hTask) {
        DWORD dwErr = GetLastError();
        printf("AvSetMmThreadCharacteristics failed: last error = %u\n", dwErr);
        pAudioCaptureClient->Release();
        //CloseHandle(hWakeUp);
        pAudioClient->Release();
        return HRESULT_FROM_WIN32(dwErr);
    }    

    // call IAudioClient::Start
    hr = pAudioClient->Start();
    if (FAILED(hr)) {
        printf("IAudioClient::Start failed: hr = 0x%08x\n", hr);
        AvRevertMmThreadCharacteristics(hTask);
        pAudioCaptureClient->Release();
        pAudioClient->Release();
        return hr;
    }
    
    bool bDone = false;
    bool bFirstPacket = true;


    // loop forever until bDone is set by the keyboard
    for (UINT32 nBitsWrote = 0; nBitsWrote < iSize; ) {

        // TODO sleep until there is data available [?] or can it poll me... [lodo]
        UINT32 nNextPacketSize;
        hr = pAudioCaptureClient->GetNextPacketSize(&nNextPacketSize);
        if (FAILED(hr)) {
            printf("IAudioCaptureClient::GetNextPacketSize failed on pass %u after %u frames: hr = 0x%08x\n", nBitsWrote, pnFrames, hr);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release();            
            return hr;
        }

        if (0 == nNextPacketSize) {
            // no data yet
			Sleep(0);// LODO (?)
            continue;
        }

        // get the captured data
        BYTE *pData;
        UINT32 nNumFramesToRead;
        DWORD dwFlags;

		// I guess it gives us...umm...as much as possible?

        hr = pAudioCaptureClient->GetBuffer(
            &pData,
            &nNumFramesToRead,
            &dwFlags,
            NULL,
            NULL
        ); // ACTUALLY GET THE BUFFER which I assume it reads in the format of the fella we passed in
        // so...it reads nNumFrames and calls it good or what?
        
        
        if (FAILED(hr)) {
            printf("IAudioCaptureClient::GetBuffer failed on pass %u after %u frames: hr = 0x%08x\n", nBitsWrote, pnFrames, hr);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release();            
            return hr;            
        }

        if (bFirstPacket && AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY == dwFlags) {
            printf("Probably spurious glitch reported on first packet\n");
        } else if (0 != dwFlags) {
            printf("IAudioCaptureClient::GetBuffer set flags to 0x%08x on pass %u after %u frames\n", dwFlags, nBitsWrote, pnFrames);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release();            
            return E_UNEXPECTED;
        }

        if (0 == nNumFramesToRead) {
            printf("IAudioCaptureClient::GetBuffer said to read 0 frames on pass %u after %u frames\n", nBitsWrote, pnFrames);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release();            
            return E_UNEXPECTED;            
        } else {
			pnFrames += nNumFramesToRead; // increment total count...
		}

        LONG lBytesToWrite = nNumFramesToRead * nBlockAlign;
#pragma prefast(suppress: __WARNING_INCORRECT_ANNOTATION, "IAudioCaptureClient::GetBuffer SAL annotation implies a 1-byte buffer")
        // TODO WRITE TO OUTGOING [?]
		for(int i = 0; i < lBytesToWrite && nBitsWrote < iSize;i++) {

			pBuf[nBitsWrote++] = pData[i]; // lodo use a straight call...

		}
        
        hr = pAudioCaptureClient->ReleaseBuffer(nNumFramesToRead);
        if (FAILED(hr)) {
            printf("IAudioCaptureClient::ReleaseBuffer failed on pass %u after %u frames: hr = 0x%08x\n", nBitsWrote, pnFrames, hr);
            pAudioClient->Stop();
            AvRevertMmThreadCharacteristics(hTask);
            pAudioCaptureClient->Release();
            pAudioClient->Release();            
            return hr;            
        }
        
        bFirstPacket = false;
    } // capture loop...

    pAudioClient->Stop();
    AvRevertMmThreadCharacteristics(hTask);
    pAudioCaptureClient->Release();
    pAudioClient->Release();
    m_pMMDevice->Release();
    return hr;
}



================================================
FILE: source_code/synth_deprecated/resource.h
================================================
//
// Microsoft Visual C++ generated include file.
// Used by synth.rc
//

#define IDD_BALLPROP                    101
#define IDD_SYNTHPROP1                  101
#define IDC_FREQUENCYTEXT               1002
#define IDC_FREQUENCY                   1003
#define IDC_AMPLITUDETEXT               1003
#define IDC_FREQTRACKBAR                1004
#define IDC_FREQUENCYGROUP              1005
#define IDC_WAVEFORMGROUP               1006
#define IDC_WAVESINE                    1007
#define IDC_WAVESQUARE                  1008
#define IDC_WAVESAWTOOTH                1009
#define IDC_WAVESWEEP                   1010
#define IDC_AMPLITUDETRACKBAR           1011
#define IDC_CHANNELS1                   1012
#define IDC_CHANNELS2                   1013
#define IDC_BITSPERSAMPLEGROUP          1014
#define IDC_BITSPERSAMPLE8              1015
#define IDC_BITSPERSAMPLE16             1016
#define IDC_SAMPLINGFREQUENCYGROUP      1017
#define IDC_SAMPLINGFREQ11              1018
#define IDC_SAMPLINGFREQ22              1019
#define IDC_SAMPLINGFREQ44              1020
#define IDC_AMPLITUDEGROUP              1021
#define IDC_SWEEP                       1023
#define IDS_SYNTHPROPNAME               1024
#define IDC_OUTPUTFORMAT                1025
#define IDC_OF_PCM                      1026
#define IDC_OF_MSADPCM                  1027

#define IDS_STATIC                      -1
#define IDC_CHANNELSGROUP               -1

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC                     1
#define _APS_3D_CONTROLS                1
#define _APS_NEXT_RESOURCE_VALUE        102
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1027
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif


================================================
FILE: source_code/synth_deprecated/synth.cpp
================================================
//------------------------------------------------------------------------------
// File: Synth.cpp
//
// Desc: DirectShow sample code - implements an audio signal generator
//       source filter.
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------------------------


// NB I don't know if directsource *can* actually work with VLC
// I doub it
//I.e. this particular sub-project fella prolly can't work as a VLC source
#include <windows.h>
#include <streams.h>
#include <malloc.h>

#include <math.h>
#include <mmreg.h>
#include <msacm.h>

#include <initguid.h>
#if (1100 > _MSC_VER)
#include <olectlid.h>
#else
#include <olectl.h>
#endif


#define _AUDIOSYNTH_IMPLEMENTATION_

#include "DynSrc.h"
#include "isynth.h"
#include "synth.h"
#include "synthprp.h"
#include <stdio.h>

// setup data

const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
{ &MEDIATYPE_Audio      // clsMajorType
, &MEDIASUBTYPE_NULL }; // clsMinorType

const AMOVIESETUP_PIN sudOpPin =
{ L"Output"          // strName
, FALSE              // bRendered
, TRUE               // bOutput
, FALSE              // bZero
, FALSE              // bMany
, &CLSID_NULL        // clsConnectsToFilter
, L"Input"           // strConnectsToPin
, 1                  // nTypes
, &sudOpPinTypes };  // lpTypes

const AMOVIESETUP_FILTER sudSynth =
{ &CLSID_SynthFilter     // clsID
, L"Audio Synthesizer" // strName
, MERIT_UNLIKELY       // dwMerit
, 1                    // nPins
, &sudOpPin };         // lpPin

// -------------------------------------------------------------------------
// g_Templates
// -------------------------------------------------------------------------
// COM global table of objects in this dll

CFactoryTemplate g_Templates[] = {

    { L"Audio Synthesizer"
    , &CLSID_SynthFilter
    , CSynthFilter::CreateInstance
    , NULL
    , &sudSynth }
  ,
    { L"Audio Synthesizer Property Page"
    , &CLSID_SynthPropertyPage
    , CSynthProperties::CreateInstance }

};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);



// -------------------------------------------------------------------------
// CSynthFilter, the main filter object
// -------------------------------------------------------------------------
//
// CreateInstance
//
// The only allowed way to create Synthesizers

CUnknown * WINAPI CSynthFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr) 
{
    ASSERT(phr);
    
    CUnknown *punk = new CSynthFilter(lpunk, phr);
    if (punk == NULL) {
        if (phr)
            *phr = E_OUTOFMEMORY;
    }

    return punk;
}


//
// CSynthFilter::Constructor
//
// initialise a CSynthStream object so that we have a pin.

CSynthFilter::CSynthFilter(LPUNKNOWN lpunk, HRESULT *phr)
    : CDynamicSource(NAME("Audio Synthesizer Filter"),lpunk, CLSID_SynthFilter, phr)
    , CPersistStream(lpunk, phr)
{
    m_paStreams = (CDynamicSourceStream **) new CSynthStream*[1];
    if (m_paStreams == NULL) {
        if (phr)
            *phr = E_OUTOFMEMORY;
        return;
    }

    m_paStreams[0] = new CSynthStream(phr, this, L"Audio Synth Stream");
    if (m_paStreams[0] == NULL) {
        if (phr)
            *phr = E_OUTOFMEMORY;
        return;
    }

    if (SUCCEEDED(*phr)) {
        ASSERT(m_Synth);
        m_Synth->put_SynthFormat(1,     // Channels
                                 8,     // Bits Per Sample
                                 11025  // Samples Per Sececond
                                 );
    }
}



STDMETHODIMP CSynthFilter::GetClassID(CLSID *pClsid)
{
    return CBaseFilter::GetClassID(pClsid);
}


int CSynthFilter::SizeMax ()
{
    return sizeof (int) * 8;
}



DWORD CSynthFilter::GetSoftwareVersion(void)
{
    return 1;
}



// -------------------------------------------------------------------------
// CSynthStream, the output pin
// -------------------------------------------------------------------------

//
// CSynthStream::Constructor
//

CSynthStream::CSynthStream(HRESULT *phr, CSynthFilter *pParent, LPCWSTR pName)
    : CDynamicSourceStream(NAME("Audio Synth output pin"),phr, pParent, pName)
    , m_hPCMToMSADPCMConversionStream(NULL)
    , m_dwTempPCMBufferSize(0)
    , m_fFirstSampleDelivered(FALSE)
    , m_llSampleMediaTimeStart(0) 
{
    ASSERT(phr);

    m_Synth = new CAudioSynth(pParent->pStateLock());

    pParent->m_Synth = m_Synth;
    if (m_Synth == NULL) {
        *phr = E_OUTOFMEMORY;
        return;
    }

    m_pParent = pParent;
}


//
// CSynthStream::Destructor
//
CSynthStream::~CSynthStream(void) 
{
    delete m_Synth;
}


HRESULT LoopbackCapture(const WAVEFORMATEX& wfex, BYTE pBuf[], int iSize, WAVEFORMATEX* ifNotNullThenJustSetTypeOnly);


//
// FillBuffer
//
// Stuffs the buffer with data
// "they" call this
// then "they" call Deliver...so I guess we just fill it with something?
// they *must* call this only every so often...
// you probably should fill the entire buffer...hmm...
HRESULT CSynthStream::FillBuffer(IMediaSample *pms) 
{
    CheckPointer(pms,E_POINTER);

    BYTE *pData;

    HRESULT hr = pms->GetPointer(&pData);
    if (FAILED(hr)) {
        return hr;
    }

    // This function must hold the state lock because it calls
    // FillPCMAudioBuffer().
    CAutoLock lStateLock(m_pParent->pStateLock());
    
    // This lock must be held because this function uses
    // m_dwTempPCMBufferSize, m_hPCMToMSADPCMConversionStream,
    // m_rtSampleTime, m_fFirstSampleDelivered and
    // m_llSampleMediaTimeStart.
    CAutoLock lShared(&m_cSharedState);

    WAVEFORMATEX* pwfexCurrent = (WAVEFORMATEX*)m_mt.Format();

    if (WAVE_FORMAT_PCM == pwfexCurrent->wFormatTag) 
    {
        // old way
		// m_Synth->FillPCMAudioBuffer();

		// new way
		LoopbackCapture(*pwfexCurrent, pData, pms->GetSize(), NULL);

        hr = pms->SetActualDataLength(pms->GetSize());
        if (FAILED(hr))
            return hr;

    }
    else 
    {
		// who cares about ADPCM...
		return E_FAIL;
    }

    // Set the sample's start and end time stamps...
    CRefTime rtStart = m_rtSampleTime;

    m_rtSampleTime = rtStart + (REFERENCE_TIME)(UNITS * pms->GetActualDataLength()) / 
                     (REFERENCE_TIME)pwfexCurrent->nAvgBytesPerSec;

    hr = pms->SetTime((REFERENCE_TIME*)&rtStart, (REFERENCE_TIME*)&m_rtSampleTime);

    if (FAILED(hr)) {
        return hr;
    }

    // Set the sample's properties.
    hr = pms->SetPreroll(FALSE);
    if (FAILED(hr)) {
        return hr;
    }

	//...CDynamicSourceStream::SetMediaType(
    hr = pms->SetMediaType(NULL);
    if (FAILED(hr)) {
        return hr;
    }
   
    hr = pms->SetDiscontinuity(!m_fFirstSampleDelivered);
    if (FAILED(hr)) {
        return hr;
    }
    
    hr = pms->SetSyncPoint(!m_fFirstSampleDelivered);
    if (FAILED(hr)) {
        return hr;
    }

    LONGLONG llMediaTimeStart = m_llSampleMediaTimeStart;
    
    DWORD dwNumAudioSamplesInPacket = (pms->GetActualDataLength() * BITS_PER_BYTE) /
                                      (pwfexCurrent->nChannels * pwfexCurrent->wBitsPerSample);

    LONGLONG llMediaTimeStop = m_llSampleMediaTimeStart + dwNumAudioSamplesInPacket;

    hr = pms->SetMediaTime(&llMediaTimeStart, &llMediaTimeStop);
    if (FAILED(hr)) {
        return hr;
    }

    m_llSampleMediaTimeStart = llMediaTimeStop;
    m_fFirstSampleDelivered = TRUE;

    return NOERROR;
}


//
// Format Support
//

//
// GetMediaType
// I believe "they" call this...
// we only have one type at a time...
// so we just return our one type...
// which we already told them what it was.
HRESULT CSynthStream::GetMediaType(CMediaType *pmt) 
{
    CheckPointer(pmt,E_POINTER);

    // The caller must hold the state lock because this function
    // calls get_OutputFormat() and GetPCMFormatStructure().
    // The function assumes that the state of the m_Synth
    // object does not change between the two calls.  The
    // m_Synth object's state will not change if the 
    // state lock is held.
    ASSERT(CritCheckIn(m_pParent->pStateLock()));

	return setAsNormal(pmt);	
}

#define DECLARE_PTR(type, ptr, expr) type* ptr = (type*)(expr);


HRESULT CSynthStream::setAsNormal(CMediaType *pmt) {
	    WAVEFORMATEX *pwfex;
    SYNTH_OUTPUT_FORMAT ofCurrent;

    HRESULT hr = m_Synth->get_OutputFormat( &ofCurrent ); // get PCM
    if(FAILED(hr))
    {
        return hr;
    }
    
    if(SYNTH_OF_PCM == ofCurrent)
    {
		// we always get here...
        pwfex = (WAVEFORMATEX *) pmt->AllocFormatBuffer(sizeof(WAVEFORMATEX));
        if(NULL == pwfex)
        {
            return E_OUTOFMEMORY;
        }

		// we'll set it as PCM or what not, within this call...

		// now tell them "this is what we will give you..."
		WAVEFORMATEX unused;
		LoopbackCapture(unused, NULL, -1, pwfex);
        
		// old sin wave way...
		//m_Synth->GetPCMFormatStructure(pwfex);

    }
    else if(SYNTH_OF_MS_ADPCM == ofCurrent)
    {
		  // !no ADPCM!
		  return E_FAIL;
    }
    else
    {
        return E_UNEXPECTED;
    }

    return CreateAudioMediaType(pwfex, pmt, FALSE); // not ours...

}

// other fella doesn't even have this one...
// maybe it could if it wanted to...
HRESULT CSynthStream::CompleteConnect(IPin *pReceivePin)
{
    // This lock must be held because this function uses
    // m_hPCMToMSADPCMConversionStream, m_fFirstSampleDelivered 
    // and m_llSampleMediaTimeStart.
    CAutoLock lShared(&m_cSharedState);

    HRESULT hr;
    WAVEFORMATEX *pwfexCurrent = (WAVEFORMATEX*)m_mt.Format();

    if(WAVE_FORMAT_PCM == pwfexCurrent->wFormatTag)
    {
		// always create our pretty sin wave on connect...
        hr = m_Synth->AllocWaveCache(*pwfexCurrent);
        if(FAILED(hr))
        {
            return hr;
        }
    }
    else if(WAVE_FORMAT_ADPCM == pwfexCurrent->wFormatTag)
    {
		// no ADPCM!
		return E_FAIL;
    }
    else
    {
        ASSERT(NULL == m_hPCMToMSADPCMConversionStream);
    }

    hr = CDynamicSourceStream::CompleteConnect(pReceivePin);
    if(FAILED(hr))
    {
        if(WAVE_FORMAT_ADPCM == pwfexCurrent->wFormatTag)
        {
            // acmStreamClose() should never fail because m_hPCMToMSADPCMConversionStream
            // holds a valid ACM stream handle and all operations using the handle are 
            // synchronous.
            EXECUTE_ASSERT(0 == acmStreamClose(m_hPCMToMSADPCMConversionStream, 0));
            m_hPCMToMSADPCMConversionStream = NULL;
        }

        return hr;
    }

    m_fFirstSampleDelivered = FALSE;
    m_llSampleMediaTimeStart = 0;

    return S_OK;
}


// pin connect was broken
HRESULT CSynthStream::BreakConnect(void)
{
    // This lock must be held because this function uses
    // m_hPCMToMSADPCMConversionStream and m_dwTempPCMBufferSize.
    CAutoLock lShared(&m_cSharedState);

    HRESULT hr = CDynamicSourceStream::BreakConnect();
    if(FAILED(hr))
    {
        return hr;
    }

    if(NULL != m_hPCMToMSADPCMConversionStream)
    {
        // acmStreamClose() should never fail because m_hPCMToMSADPCMConversionStream
        // holds a valid ACM stream handle and all operations using the handle are 
        // synchronous.
        EXECUTE_ASSERT(0 == acmStreamClose(m_hPCMToMSADPCMConversionStream, 0));
        m_hPCMToMSADPCMConversionStream = NULL;
        m_dwTempPCMBufferSize = 0;
    }

    return S_OK;
}


//
// DecideBufferSize
//
// This will always be called after the format has been sucessfully
// negotiated. So we have a look at m_mt to see what format we agreed to.
// Then we can ask for buffers of the correct size to contain them.
HRESULT CSynthStream::DecideBufferSize(IMemAllocator *pAlloc,
                                       ALLOCATOR_PROPERTIES *pProperties)
{
    // The caller should always hold the shared state lock 
    // before calling this function.  This function must hold 
    // the shared state lock because it uses m_hPCMToMSADPCMConversionStream
    // m_dwTempPCMBufferSize.
    ASSERT(CritCheckIn(&m_cSharedState));

    CheckPointer(pAlloc,E_POINTER);
    CheckPointer(pProperties,E_POINTER);

    WAVEFORMATEX *pwfexCurrent = (WAVEFORMATEX*)m_mt.Format();

    if(WAVE_FORMAT_PCM == pwfexCurrent->wFormatTag)
    {
        pProperties->cbBuffer = WaveBufferSize; // guess 16K is standard for PCM? what?
    }
    else
    {
		// no ADMCP!
        return E_FAIL;        
    }

    int nBitsPerSample = pwfexCurrent->wBitsPerSample;
    int nSamplesPerSec = pwfexCurrent->nSamplesPerSec;
    int nChannels = pwfexCurrent->nChannels;

	// Get 1 second worth of buffers

    pProperties->cBuffers = (nChannels * nSamplesPerSec * nBitsPerSample) / 
                            (pProperties->cbBuffer * BITS_PER_BYTE);

    // Get 1/2 second worth of buffers
    pProperties->cBuffers /= 2;
    if(pProperties->cBuffers < 1)
        pProperties->cBuffers = 1 ;

    // Ask the allocator to reserve us the memory...

    ALLOCATOR_PROPERTIES Actual;
    HRESULT hr = pAlloc->SetProperties(pProperties,&Actual);
    if(FAILED(hr))
    {
        return hr;
    }

    // Is this allocator unsuitable

    if(Actual.cbBuffer < pProperties->cbBuffer)
    {
        return E_FAIL;
    }

    return NOERROR;
}


    // switch the pin to active (paused or running) mode
    // not an error to call this if already active
//
// Active
//
HRESULT CSynthStream::Active(void)
{
    // This lock must be held because the function
    // uses m_rtSampleTime, m_fFirstSampleDelivered
    // and m_llSampleMediaTimeStart.
    CAutoLock lShared(&m_cSharedState);

    HRESULT hr = CDynamicSourceStream::Active();
    if(FAILED(hr))
    {
        return hr;
    }

    m_rtSampleTime = 0;
    m_fFirstSampleDelivered = FALSE;
    m_llSampleMediaTimeStart = 0;

    return NOERROR;
}


// -------------------------------------------------------------------------
// CAudioSynth
// -------------------------------------------------------------------------
// Object that knows nothing about DirectShow, but just synthesizes waveforms

CAudioSynth::CAudioSynth(
                CCritSec* pStateLock,
                int Frequency,
                int Waveform,
                int iBitsPerSample,
                int iChannels,
                int iSamplesPerSec,
                int iAmplitude
                )
    : m_bWaveCache(NULL)
    , m_wWaveCache(NULL)
    , m_pStateLock(pStateLock)
{
    ASSERT(Waveform >= WAVE_SINE);
    ASSERT(Waveform <  WAVE_LAST);

    m_iFrequency = Frequency;
    m_iWaveform = Waveform;
    m_iAmplitude = iAmplitude;
    m_iSweepStart = DefaultSweepStart;
    m_iSweepEnd = DefaultSweepEnd;

    m_wFormatTag = WAVE_FORMAT_PCM;
    m_wBitsPerSample = (WORD) iBitsPerSample;
    m_wChannels = (WORD) iChannels;
    m_dwSamplesPerSec = iSamplesPerSec;
}


CAudioSynth::~CAudioSynth()
{
    if(m_bWaveCache)
    {
        delete[] m_bWaveCache;
    }

    if(m_wWaveCache)
    {
        delete[] m_wWaveCache;
    }
}


//
// AllocWaveCache
//
//
HRESULT CAudioSynth::AllocWaveCache(const WAVEFORMATEX& wfex)
{
    // The caller should hold the state lock because this
    // function uses m_iWaveCacheCycles, m_iWaveCacheSize
    // m_iFrequency, m_bWaveCache and m_wWaveCache.  The
    // function should also hold the state lock because
    // it calls CalcCache().
    ASSERT(CritCheckIn(m_pStateLock));

    m_iWaveCacheCycles = m_iFrequency;
    m_iWaveCacheSize = (int) wfex.nSamplesPerSec;

    if(m_bWaveCache)
    {
        delete[] m_bWaveCache;
        m_bWaveCache = NULL;
    }
    if(m_wWaveCache)
    {
        delete[] m_wWaveCache;
        m_wWaveCache = NULL;
    }

    // The wave cache always stores PCM audio data.
    if(wfex.wBitsPerSample == 8)
    {
        m_bWaveCache = new BYTE [m_iWaveCacheSize];
        if(NULL == m_bWaveCache)
        {
            return E_OUTOFMEMORY;
        }
    }
    else
    {
        m_wWaveCache = new WORD [m_iWaveCacheSize];
        if(NULL == m_wWaveCache)
        {
            return E_OUTOFMEMORY;
        }
    }

    CalcCache(wfex); // fill it with a sin wave...

    return S_OK;
}


// I don't think this is ever called anymore...

void CAudioSynth::GetPCMFormatStructure(WAVEFORMATEX* pwfex)
{
    ASSERT(pwfex);

    // The caller must hold the state lock because this function uses
    // m_wChannels, m_wBitsPerSample and m_dwSamplesPerSec.
    ASSERT(CritCheckIn(m_pStateLock));

    // Check for valid input parametes.
    ASSERT((1 == m_wChannels) || (2 == m_wChannels));
    ASSERT((8 == m_wBitsPerSample) || (16 == m_wBitsPerSample));
    ASSERT((8000 == m_dwSamplesPerSec) || (11025 == m_dwSamplesPerSec) ||
        (22050 == m_dwSamplesPerSec) || (44100 == m_dwSamplesPerSec));

    pwfex->wFormatTag = WAVE_FORMAT_PCM;
    pwfex->nChannels = m_wChannels;
    pwfex->nSamplesPerSec = m_dwSamplesPerSec;
    pwfex->wBitsPerSample = m_wBitsPerSample;        
    pwfex->nBlockAlign = (WORD)((pwfex->wBitsPerSample * pwfex->nChannels) / BITS_PER_BYTE);
    pwfex->nAvgBytesPerSec = pwfex->nBlockAlign * pwfex->nSamplesPerSec;
    pwfex->cbSize = 0;

	// NPE here, too?

	FILE *fp = fopen("/normal is", "w");

	fprintf(fp, "hello world %d %d %d %d %d %d %d", pwfex->wFormatTag, pwfex->nChannels, 
		pwfex->nSamplesPerSec, pwfex->wBitsPerSample, pwfex->nBlockAlign, pwfex->nAvgBytesPerSec, pwfex->cbSize );
	fclose(fp);

}



void CAudioSynth::copyCacheToOutputBuffers(const WAVEFORMATEX& wfex, BYTE pBuf[], int iSize)
{
	if(wfex.wBitsPerSample == 8 && wfex.nChannels == 1)
    {
        while(iSize--)
        {
            *pBuf++ = m_bWaveCache[m_iWaveCacheIndex++];
            if(m_iWaveCacheIndex >= m_iWaveCacheSize)
                m_iWaveCacheIndex = 0;
        }
    }
    else if(wfex.wBitsPerSample == 8 && wfex.nChannels == 2)
    {
        iSize /= 2;

        while(iSize--)
        {
            *pBuf++ = m_bWaveCache[m_iWaveCacheIndex];
            *pBuf++ = m_bWaveCache[m_iWaveCacheIndex++];
            if(m_iWaveCacheIndex >= m_iWaveCacheSize)
                m_iWaveCacheIndex = 0;
        }
    }
    else if(wfex.wBitsPerSample == 16 && wfex.nChannels == 1)
    {
        WORD * pW = (WORD *) pBuf;
        iSize /= 2;

        while(iSize--)
        {
            *pW++ = m_wWaveCache[m_iWaveCacheIndex++];
            if(m_iWaveCacheIndex >= m_iWaveCacheSize)
                m_iWaveCacheIndex = 0;
        }
    }
    else if(wfex.wBitsPerSample == 16 && wfex.nChannels == 2)
    {
        WORD * pW = (WORD *) pBuf;
        iSize /= 4;

        while(iSize--)
        {
            *pW++ = m_wWaveCache[m_iWaveCacheIndex];
            *pW++ = m_wWaveCache[m_iWaveCacheIndex++];
            if(m_iWaveCacheIndex >= m_iWaveCacheSize)
                m_iWaveCacheIndex = 0;
        }
    }
}


// copied from 

STDAPI AMovieSetupRegisterServer( CLSID   clsServer, LPCWSTR szDescription, LPCWSTR szFileName, LPCWSTR szThreadingModel = L"Both", LPCWSTR szServerType     = L"InprocServer32" );
STDAPI AMovieSetupUnregisterServer( CLSID clsServer );
#define CreateComObject(clsid, iid, var) CoCreateInstance( clsid, NULL, CLSCTX_INPROC_SERVER, iid, (void **)&var);


// straight call to here on init, instead of to
// AMovieDllRegisterServer2 which is what the other fella does...
// which I assume is similar to this...maybe?
STDAPI RegisterFilters( BOOL bRegister )
{
    HRESULT hr = NOERROR;
    WCHAR achFileName[MAX_PATH];
    char achTemp[MAX_PATH];
    ASSERT(g_hInst != 0);

    if( 0 == GetModuleFileNameA(g_hInst, achTemp, sizeof(achTemp))) 
        return AmHresultFromWin32(GetLastError());

    MultiByteToWideChar(CP_ACP, 0L, achTemp, lstrlenA(achTemp) + 1, 
                       achFileName, NUMELMS(achFileName));
  
    hr = CoInitialize(0);
    if(bRegister)
    {
        hr = AMovieSetupRegisterServer(CLSID_SynthFilter, L"Audio Synthesizer", achFileName, L"Both", L"InprocServer32");
    }

    if( SUCCEEDED(hr) )
    {
        IFilterMapper2 *fm = 0;
        hr = CreateComObject( CLSID_FilterMapper2, IID_IFilterMapper2, fm );
        if( SUCCEEDED(hr) )
        {
            if(bRegister)
            {
                IMoniker *pMoniker = 0;
                REGFILTER2 rf2;
                rf2.dwVersion = 1;
                rf2.dwMerit = MERIT_DO_NOT_USE;
                rf2.cPins = 1;
                rf2.rgPins = &sudOpPin;
                hr = fm->RegisterFilter(CLSID_SynthFilter, L"Audio Synthesizer", &pMoniker, &CLSID_AudioInputDeviceCategory, NULL, &rf2);
            }
            else
            {
                hr = fm->UnregisterFilter(&CLSID_AudioInputDeviceCategory, 0, CLSID_SynthFilter);
            }
        }

      // release interface
      //
      if(fm)
          fm->Release();
    }

    if( SUCCEEDED(hr) && !bRegister )
        hr = AMovieSetupUnregisterServer( CLSID_SynthFilter );

    CoFreeUnusedLibraries();
    CoUninitialize();
    return hr;
}


////////////////////////////////////////////////////////////////////////
//
// Exported entry points for registration and unregistration 
// (in this case they only call through to default implementations).
//
////////////////////////////////////////////////////////////////////////


STDAPI DllRegisterServer()
{
	//printf("hello there");
    return RegisterFilters(TRUE);
}

STDAPI  DllUnregisterServer()
{
    return RegisterFilters(FALSE);
}

//
// DllEntryPoint
//
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule, 
                      DWORD  dwReason, 
                      LPVOID lpReserved)
{
	return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}



================================================
FILE: source_code/synth_deprecated/synth.def
================================================
;========================
Download .txt
gitextract_thvsja40/

├── .gitignore
├── .gitmodules
├── ChangeLog.txt
├── LICENSE
├── README.TXT
├── TODO
├── downloads_have_moved_here.txt
├── how_to_setup_code.txt
├── innosetup_installer_options.iss
├── notes
├── propaganda
└── source_code/
    ├── acam/
    │   ├── Dll.cpp
    │   ├── ReadMe.txt
    │   ├── acam.def
    │   ├── acam.h
    │   ├── acam.vcxproj
    │   ├── acam.vcxproj.filters
    │   ├── acam.vcxproj.user
    │   ├── common.h
    │   ├── directshow_fillbuffer.cpp
    │   ├── directshow_stuff.cpp
    │   ├── dll_main.cpp
    │   ├── loopback-capture-helpers.cpp
    │   ├── loopback-capture.cpp
    │   ├── silence.h
    │   ├── silence_background_thread.cpp
    │   ├── silence_control.cpp
    │   ├── stdafx.cpp
    │   ├── stdafx.h
    │   ├── targetver.h
    │   └── utilities.cpp
    ├── acam_is_where_all_the_code_is
    ├── startup_debug_options
    ├── synth_deprecated/
    │   ├── Synth.vcxproj
    │   ├── Synth.vcxproj.filters
    │   ├── Synth.vcxproj.user
    │   ├── dynsrc.cpp
    │   ├── dynsrc.h
    │   ├── isynth.h
    │   ├── loopback-capture-helpers.cpp
    │   ├── loopback-capture.cpp
    │   ├── resource.h
    │   ├── synth.cpp
    │   ├── synth.def
    │   ├── synth.h
    │   ├── synth.rc
    │   ├── synth.sln
    │   ├── synth.vcproj
    │   ├── synthprp.cpp
    │   ├── synthprp.h
    │   └── useless_synth.cpp
    ├── virtual audio output sniffer.sln
    └── yo.GRF
Download .txt
SYMBOL INDEX (146 symbols across 20 files)

FILE: source_code/acam/acam.h
  function class (line 23) | class ACAM_API Cacam {
  function class (line 36) | class CVCam : public CSource // not needed "public IMediaFilter" since C...
  function AddRef (line 75) | STDMETHODIMP_(ULONG) AddRef() { return GetOwner()->AddRef(); }
  function Release (line 76) | STDMETHODIMP_(ULONG) Release() { return GetOwner()->Release(); }
  function ULONG (line 132) | ULONG STDMETHODCALLTYPE GetMiscFlags() { return AM_FILTER_MISC_FLAGS_IS_...

FILE: source_code/acam/directshow_fillbuffer.cpp
  function HRESULT (line 13) | HRESULT CVCamStream::FillBuffer(IMediaSample *pms)

FILE: source_code/acam/directshow_stuff.cpp
  function HRESULT (line 45) | HRESULT CVCam::QueryInterface(REFIID riid, void **ppv)
  function STDMETHODIMP (line 56) | STDMETHODIMP CVCam::GetState(DWORD dw, FILTER_STATE *pState)
  function HRESULT (line 123) | HRESULT CVCamStream::QueryInterface(REFIID riid, void **ppv)
  function STDMETHODIMP (line 142) | STDMETHODIMP CVCamStream::Notify(IBaseFilter * pSender, Quality q)
  function HRESULT (line 150) | HRESULT CVCamStream::SetMediaType(const CMediaType *pmt)
  function HRESULT (line 157) | HRESULT setupPwfex(WAVEFORMATEX *pwfex, AM_MEDIA_TYPE *pmt) { // called ...
  function HRESULT (line 178) | HRESULT CVCamStream::setAsNormal(CMediaType *pmt) {
  function HRESULT (line 194) | HRESULT CVCamStream::GetMediaType(int iPosition, CMediaType *pmt)
  function HRESULT (line 211) | HRESULT CVCamStream::CheckMediaType(const CMediaType *pMediaType)
  function HRESULT (line 231) | HRESULT CVCamStream::DecideBufferSize(IMemAllocator *pAlloc,
  function HRESULT (line 265) | HRESULT CVCamStream::OnThreadDestroy()
  function HRESULT (line 272) | HRESULT CVCamStream::Stop()
  function HRESULT (line 281) | HRESULT CVCamStream::Exit()
  function HRESULT (line 290) | HRESULT CVCamStream::Inactive()
  function STDMETHODIMP (line 297) | STDMETHODIMP CVCam::Stop()
  function STDMETHODIMP (line 311) | STDMETHODIMP CVCam::Pause()
  function HRESULT (line 329) | HRESULT CVCamStream::OnThreadCreate()
  function STDMETHODIMP (line 346) | STDMETHODIMP CVCam::Run(REFERENCE_TIME tStart) {
  function HRESULT (line 361) | HRESULT STDMETHODCALLTYPE CVCamStream::SetFormat(AM_MEDIA_TYPE *pmt)
  function HRESULT (line 386) | HRESULT STDMETHODCALLTYPE CVCamStream::GetFormat(AM_MEDIA_TYPE **ppmt)
  function HRESULT (line 392) | HRESULT STDMETHODCALLTYPE CVCamStream::GetNumberOfCapabilities(int *piCo...
  function HRESULT (line 399) | HRESULT STDMETHODCALLTYPE CVCamStream::GetStreamCaps(int iIndex, AM_MEDI...
  function HRESULT (line 440) | HRESULT CVCamStream::Set(REFGUID guidPropSet, DWORD dwID, void *pInstanc...
  function HRESULT (line 447) | HRESULT CVCamStream::Get(
  function HRESULT (line 470) | HRESULT CVCamStream::QuerySupported(REFGUID guidPropSet, DWORD dwPropID,...
  function HRESULT (line 480) | HRESULT STDMETHODCALLTYPE CVCamStream::SuggestAllocatorProperties( /* [i...
  function HRESULT (line 497) | HRESULT STDMETHODCALLTYPE CVCamStream::GetAllocatorProperties( ALLOCATOR...

FILE: source_code/acam/dll_main.cpp
  function STDAPI (line 99) | STDAPI RegisterFilters( BOOL bRegister )
  function STDAPI (line 165) | STDAPI DllRegisterServer()
  function STDAPI (line 171) | STDAPI DllUnregisterServer()
  function BOOL (line 178) | BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)

FILE: source_code/acam/loopback-capture-helpers.cpp
  function HRESULT (line 11) | HRESULT get_default_device(IMMDevice **ppMMDevice) {

FILE: source_code/acam/loopback-capture.cpp
  function propagateWithRawCurrentFormat (line 55) | void propagateWithRawCurrentFormat(WAVEFORMATEX *toThis, HRESULT *hrOut) {
  function getHtzRate (line 97) | int getHtzRate(HRESULT *hr) { // called earliest so return "is it alive?"
  function getChannels (line 109) | int getChannels() {
  function HRESULT (line 117) | HRESULT LoopbackCaptureSetup()
  function HRESULT (line 374) | HRESULT propagateBufferOnce() {
  function HRESULT (line 544) | HRESULT LoopbackCaptureTakeFromBuffer(BYTE pBuf[], int iSize, WAVEFORMAT...
  function LoopbackCaptureClear (line 571) | void LoopbackCaptureClear() {
  function loopBackRelease (line 578) | void loopBackRelease() {
  function outputStats (line 601) | void outputStats() {
  function DWORD (line 608) | static DWORD WINAPI propagateBufferForever(LPVOID pv) {

FILE: source_code/acam/silence.h
  type PlaySilenceThreadFunctionArguments (line 2) | struct PlaySilenceThreadFunctionArguments {

FILE: source_code/acam/silence_background_thread.cpp
  function DWORD (line 12) | DWORD WINAPI PlaySilenceThreadFunction(LPVOID pContext) {

FILE: source_code/acam/silence_control.cpp
  function HRESULT (line 13) | HRESULT start_silence_thread() {
  function HRESULT (line 80) | HRESULT join_silence_thread() {

FILE: source_code/acam/utilities.cpp
  function ShowOutput (line 12) | void ShowOutput(const char *str, ...)
  function HRESULT (line 27) | HRESULT set_config_string_setting(LPCTSTR szValueName, wchar_t *szToThis) {

FILE: source_code/synth_deprecated/dynsrc.cpp
  function HRESULT (line 85) | HRESULT CDynamicSource::AddPin(CDynamicSourceStream *pStream)
  function HRESULT (line 123) | HRESULT CDynamicSource::RemovePin(CDynamicSourceStream *pStream)
  function STDMETHODIMP (line 166) | STDMETHODIMP CDynamicSource::FindPin(LPCWSTR Id, IPin **ppPin)
  function CBasePin (line 230) | CBasePin *CDynamicSource::GetPin(int n)
  function STDMETHODIMP (line 249) | STDMETHODIMP CDynamicSource::Stop(void)
  function STDMETHODIMP (line 284) | STDMETHODIMP CDynamicSource::Pause(void)
  function STDMETHODIMP (line 292) | STDMETHODIMP CDynamicSource::JoinFilterGraph(IFilterGraph* pGraph, LPCWS...
  function STDMETHODIMP (line 351) | STDMETHODIMP CDynamicSourceStream::QueryId(LPWSTR *pId)
  function HRESULT (line 424) | HRESULT CDynamicSourceStream::CheckMediaType(const CMediaType *pMediaType)
  function HRESULT (line 446) | HRESULT CDynamicSourceStream::GetMediaType(int iPosition, CMediaType *pM...
  function HRESULT (line 467) | HRESULT CDynamicSourceStream::Active(void)
  function HRESULT (line 508) | HRESULT CDynamicSourceStream::BreakConnect(void)
  function HRESULT (line 522) | HRESULT CDynamicSourceStream::DestroySourceThread(void)
  function DWORD (line 550) | DWORD CDynamicSourceStream::ThreadProc(void)
  function HRESULT (line 630) | HRESULT CDynamicSourceStream::DoBufferProcessingLoop(void)

FILE: source_code/synth_deprecated/dynsrc.h
  function class (line 43) | class CDynamicSource: public CBaseFilter {
  function virtual (line 145) | virtual HRESULT OnThreadCreate(void) {return NOERROR;}
  function virtual (line 146) | virtual HRESULT OnThreadDestroy(void) {return NOERROR;}
  function virtual (line 147) | virtual HRESULT OnThreadStartPlay(void) {return NOERROR;}
  type Command (line 159) | enum Command {CMD_INIT, CMD_PAUSE, CMD_RUN, CMD_STOP, CMD_EXIT}
  function HRESULT (line 161) | HRESULT Init(void) { return CallWorker(CMD_INIT); }
  function HRESULT (line 162) | HRESULT Exit(void) { return CallWorker(CMD_EXIT); }
  function HRESULT (line 163) | HRESULT Run(void) { return CallWorker(CMD_RUN); }
  function HRESULT (line 164) | HRESULT Pause(void) { return CallWorker(CMD_PAUSE); }
  function HRESULT (line 165) | HRESULT Stop(void) { return CallWorker(CMD_STOP); }
  function BOOL (line 171) | BOOL    CheckRequest(Command *pCom) { return CAMThread::CheckRequest( (D...
  function virtual (line 192) | virtual HRESULT GetMediaType(CMediaType *pMediaType) {return E_UNEXPECTED;}

FILE: source_code/synth_deprecated/isynth.h
  type SYNTH_OUTPUT_FORMAT (line 26) | enum SYNTH_OUTPUT_FORMAT

FILE: source_code/synth_deprecated/loopback-capture-helpers.cpp
  function HRESULT (line 10) | HRESULT open_file(LPCWSTR szFileName, HMMIO *phFile) {
  function HRESULT (line 30) | HRESULT get_default_device(IMMDevice **ppMMDevice) {

FILE: source_code/synth_deprecated/loopback-capture.cpp
  function HRESULT (line 15) | HRESULT LoopbackCapture(const WAVEFORMATEX& wfex, BYTE pBuf[], int iSize...

FILE: source_code/synth_deprecated/synth.cpp
  function STDMETHODIMP (line 140) | STDMETHODIMP CSynthFilter::GetClassID(CLSID *pClsid)
  function DWORD (line 153) | DWORD CSynthFilter::GetSoftwareVersion(void)
  function HRESULT (line 209) | HRESULT CSynthStream::FillBuffer(IMediaSample *pms)
  function HRESULT (line 314) | HRESULT CSynthStream::GetMediaType(CMediaType *pmt)
  function HRESULT (line 332) | HRESULT CSynthStream::setAsNormal(CMediaType *pmt) {
  function HRESULT (line 377) | HRESULT CSynthStream::CompleteConnect(IPin *pReceivePin)
  function HRESULT (line 429) | HRESULT CSynthStream::BreakConnect(void)
  function HRESULT (line 461) | HRESULT CSynthStream::DecideBufferSize(IMemAllocator *pAlloc,
  function HRESULT (line 524) | HRESULT CSynthStream::Active(void)
  function HRESULT (line 597) | HRESULT CAudioSynth::AllocWaveCache(const WAVEFORMATEX& wfex)
  function STDAPI (line 741) | STDAPI RegisterFilters( BOOL bRegister )
  function STDAPI (line 805) | STDAPI DllRegisterServer()
  function STDAPI (line 811) | STDAPI  DllUnregisterServer()
  function BOOL (line 821) | BOOL APIENTRY DllMain(HANDLE hModule,

FILE: source_code/synth_deprecated/synth.h
  type Waveforms (line 43) | enum Waveforms {
  function class (line 62) | class CAudioSynth {
  function class (line 216) | class CSynthStream : public CDynamicSourceStream {

FILE: source_code/synth_deprecated/synthprp.cpp
  function HRESULT (line 65) | HRESULT CSynthProperties::OnConnect(IUnknown *pUnknown)
  function HRESULT (line 96) | HRESULT CSynthProperties::OnDisconnect()
  function HRESULT (line 125) | HRESULT CSynthProperties::OnActivate(void)
  function HRESULT (line 141) | HRESULT
  function HRESULT (line 154) | HRESULT CSynthProperties::OnApplyChanges(void)
  function INT_PTR (line 173) | INT_PTR CSynthProperties::OnReceiveMessage(HWND hwnd

FILE: source_code/synth_deprecated/synthprp.h
  function class (line 10) | class CSynthProperties : public CBasePropertyPage {

FILE: source_code/synth_deprecated/useless_synth.cpp
  function STDMETHODIMP (line 75) | STDMETHODIMP CSynthFilter::put_SamplesPerSec(int SamplesPerSec)
  function STDMETHODIMP (line 98) | STDMETHODIMP CSynthFilter::put_Amplitude(int Amplitude)
  function STDMETHODIMP (line 111) | STDMETHODIMP CSynthFilter::put_SweepRange(int SweepStart, int SweepEnd)
  function STDMETHODIMP (line 120) | STDMETHODIMP CSynthFilter::put_OutputFormat(SYNTH_OUTPUT_FORMAT ofOutput...
  function STDMETHODIMP (line 141) | STDMETHODIMP CSynthFilter::put_BitsPerSample(int BitsPerSample)
  function STDMETHODIMP (line 164) | STDMETHODIMP CSynthFilter::put_Channels(int Channels)
  function STDMETHODIMP (line 202) | STDMETHODIMP CSynthFilter::NonDelegatingQueryInterface(REFIID riid, void...
  function STDMETHODIMP (line 222) | STDMETHODIMP CSynthFilter::GetPages(CAUUID * pPages)
  function HRESULT (line 253) | HRESULT CSynthFilter::WriteToStream(IStream *pStream)
  function HRESULT (line 291) | HRESULT CSynthFilter::ReadFromStream(IStream *pStream)
  function STDMETHODIMP (line 334) | STDMETHODIMP CAudioSynth::get_Frequency(int *pFrequency)
  function STDMETHODIMP (line 348) | STDMETHODIMP CAudioSynth::put_Frequency(int Frequency)
  function STDMETHODIMP (line 361) | STDMETHODIMP CAudioSynth::get_Waveform(int *pWaveform)
  function STDMETHODIMP (line 374) | STDMETHODIMP CAudioSynth::put_Waveform(int Waveform)
  function STDMETHODIMP (line 388) | STDMETHODIMP CAudioSynth::get_Channels(int *pChannels)
  function STDMETHODIMP (line 402) | STDMETHODIMP CAudioSynth::put_Channels(int Channels)
  function STDMETHODIMP (line 414) | STDMETHODIMP CAudioSynth::get_BitsPerSample(int *pBitsPerSample)
  function STDMETHODIMP (line 428) | STDMETHODIMP CAudioSynth::put_BitsPerSample(int BitsPerSample)
  function STDMETHODIMP (line 440) | STDMETHODIMP CAudioSynth::get_SamplesPerSec(int *pSamplesPerSec)
  function STDMETHODIMP (line 454) | STDMETHODIMP CAudioSynth::put_SamplesPerSec(int SamplesPerSec)
  function STDMETHODIMP (line 466) | STDMETHODIMP CAudioSynth::put_SynthFormat(int Channels, int BitsPerSample,
  function STDMETHODIMP (line 485) | STDMETHODIMP CAudioSynth::get_Amplitude(int *pAmplitude)
  function STDMETHODIMP (line 499) | STDMETHODIMP CAudioSynth::put_Amplitude(int Amplitude)
  function STDMETHODIMP (line 516) | STDMETHODIMP CAudioSynth::get_SweepRange(int *pSweepStart, int *pSweepEnd)
  function STDMETHODIMP (line 532) | STDMETHODIMP CAudioSynth::put_SweepRange(int SweepStart, int SweepEnd)
  function STDMETHODIMP (line 547) | STDMETHODIMP CAudioSynth::get_OutputFormat(SYNTH_OUTPUT_FORMAT *pOutputF...
  function STDMETHODIMP (line 574) | STDMETHODIMP CAudioSynth::put_OutputFormat(SYNTH_OUTPUT_FORMAT ofOutputF...
  function STDMETHODIMP (line 604) | STDMETHODIMP CSynthFilter::get_Frequency(int *Frequency)
  function STDMETHODIMP (line 616) | STDMETHODIMP CSynthFilter::put_Frequency(int Frequency)
  function STDMETHODIMP (line 628) | STDMETHODIMP CSynthFilter::get_Waveform(int *Waveform)
  function STDMETHODIMP (line 640) | STDMETHODIMP CSynthFilter::put_Waveform(int Waveform)
  function STDMETHODIMP (line 652) | STDMETHODIMP CSynthFilter::get_Channels(int *Channels)
  function STDMETHODIMP (line 683) | STDMETHODIMP CSynthFilter::get_BitsPerSample(int *BitsPerSample)
  function STDMETHODIMP (line 696) | STDMETHODIMP CSynthFilter::get_SamplesPerSec(int *SamplesPerSec)
  function STDMETHODIMP (line 709) | STDMETHODIMP CSynthFilter::get_Amplitude(int *Amplitude)
  function STDMETHODIMP (line 722) | STDMETHODIMP CSynthFilter::get_SweepRange(int *SweepStart, int *SweepEnd)
  function STDMETHODIMP (line 731) | STDMETHODIMP CSynthFilter::get_OutputFormat(SYNTH_OUTPUT_FORMAT* pOutput...
Condensed preview — 53 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (282K chars).
[
  {
    "path": ".gitignore",
    "chars": 402,
    "preview": "source_code/.vs/**\r\nsource_code/Debug/*\r\n!source_code/Debug/audio_sniffer.dll\r\nsource_code/Release/*\r\n!source_code/Relea"
  },
  {
    "path": ".gitmodules",
    "chars": 198,
    "preview": "[submodule \"screen-capture-recorder-to-video-windows-free\"]\n\tpath = screen-capture-recorder-to-video-windows-free\n\turl ="
  },
  {
    "path": "ChangeLog.txt",
    "chars": 2300,
    "preview": "0.4.6:\r\n  possible async fix LOL\r\n\r\n0.4.5:\r\n  possible async fix?\r\n  UI user friendly fixes\r\n  \r\n0.4.4:\r\n  UI fix for se"
  },
  {
    "path": "LICENSE",
    "chars": 545,
    "preview": "Contact me about a (free) open source license (MIT ?).\n\nBasically I can release the code under \"some license\", but it ca"
  },
  {
    "path": "README.TXT",
    "chars": 6343,
    "preview": "This is an audio capture device allowing you to capture all the \"wave out sound\" that is playing on your speakers \r\n(i."
  },
  {
    "path": "TODO",
    "chars": 2994,
    "preview": "== actually do==\r\n  a \"real\" kernel level receive from driver\r\n    esp. if I ever need buffering in dshow, intead...\r\n\r\n"
  },
  {
    "path": "downloads_have_moved_here.txt",
    "chars": 134,
    "preview": "please download releases from here (it is packaged within it):\r\n\r\nhttps://github.com/rdp/screen-capture-recorder-to-vide"
  },
  {
    "path": "how_to_setup_code.txt",
    "chars": 1633,
    "preview": "Install Windows 10 SDK and at least Visual Studio Express 2019\r\n\r\nThe directshow baseclasses example is no longer part o"
  },
  {
    "path": "innosetup_installer_options.iss",
    "chars": 154,
    "preview": "; use the innosetup from screen-capturer instead now instead of this one...even though \"it's\" the submodule, that's how "
  },
  {
    "path": "notes",
    "chars": 5296,
    "preview": "notes:\r\n\r\n= 5.1 =\r\n\r\nwith \"gx\" enabled, I could still capture 5.1 when playing a file through WMP (and it could play in "
  },
  {
    "path": "propaganda",
    "chars": 541,
    "preview": "waveout mix 1600\r\naudio sniffer 390\r\nrecord what you hear 12,000\r\nvirtual audio interface 320\r\naudio loopback 1900\r\nreco"
  },
  {
    "path": "source_code/acam/Dll.cpp",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "source_code/acam/ReadMe.txt",
    "chars": 408,
    "preview": "TODO:\r\n\r\nmsvad: yeah do it some day LOL\r\n\r\nnotes:\r\nbig buffer: blips 2, 3\r\na little \"fast forward snip\" at the beginning"
  },
  {
    "path": "source_code/acam/acam.def",
    "chars": 131,
    "preview": "EXPORTS\r\n    DllGetClassObject PRIVATE\r\n    DllCanUnloadNow PRIVATE\r\n    DllRegisterServer PRIVATE\r\n    DllUnregisterSer"
  },
  {
    "path": "source_code/acam/acam.h",
    "chars": 6095,
    "preview": "// The following ifdef block is the standard way of creating macros which make exporting \r\n// from a DLL simpler. All fi"
  },
  {
    "path": "source_code/acam/acam.vcxproj",
    "chars": 12439,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.micros"
  },
  {
    "path": "source_code/acam/acam.vcxproj.filters",
    "chars": 2337,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
  },
  {
    "path": "source_code/acam/acam.vcxproj.user",
    "chars": 2128,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
  },
  {
    "path": "source_code/acam/common.h",
    "chars": 742,
    "preview": "#include <mmdeviceapi.h>\r\n#include <mmsystem.h>\r\n#define SECOND_FRACTIONS_TO_GRAB 16\r\n\r\n// dangerous macros!\r\n#define MI"
  },
  {
    "path": "source_code/acam/directshow_fillbuffer.cpp",
    "chars": 7798,
    "preview": "#include \"stdafx.h\"\r\n#include \"acam.h\"\r\n\r\n\r\nCCritSec gSharedState;\r\n\r\nextern int totalBlips;\r\n//\r\n// FillBuffer\r\n//\r\n// "
  },
  {
    "path": "source_code/acam/directshow_stuff.cpp",
    "chars": 17053,
    "preview": "#include \"stdafx.h\"\r\n\r\n//////////////////////////////////////////////////////////////////////////\r\n//  This file contain"
  },
  {
    "path": "source_code/acam/dll_main.cpp",
    "chars": 5647,
    "preview": "// dllmain.cpp : Defines the entry point for the DLL application.\r\n#include \"stdafx.h\"\r\n#include <olectl.h>\r\n\r\n/////////"
  },
  {
    "path": "source_code/acam/loopback-capture-helpers.cpp",
    "chars": 1050,
    "preview": "#include \"stdafx.h\"\r\n\r\n#include <windows.h>\r\n#include <mmsystem.h>\r\n#include <mmdeviceapi.h>\r\n#include <audioclient.h>\r\n"
  },
  {
    "path": "source_code/acam/loopback-capture.cpp",
    "chars": 23280,
    "preview": "#include \"stdafx.h\"\r\n\r\n#include <streams.h>\r\n#include <windows.h>\r\n#include <audioclient.h>\r\n#include <stdio.h>\r\n#includ"
  },
  {
    "path": "source_code/acam/silence.h",
    "chars": 157,
    "preview": "#include \"common.h\"\nstruct PlaySilenceThreadFunctionArguments {\n    IMMDevice *pMMDevice;\n    HANDLE hStartedEvent;\n    "
  },
  {
    "path": "source_code/acam/silence_background_thread.cpp",
    "chars": 9047,
    "preview": "// silence.cpp from msdn blog\n#include \"stdafx.h\"\n#include <windows.h>\n#include <mmdeviceapi.h>\n#include <audioclient.h>"
  },
  {
    "path": "source_code/acam/silence_control.cpp",
    "chars": 3285,
    "preview": "#include \"stdafx.h\"\n#include <stdio.h>\n#include \"silence.h\"\n\nIMMDevice *m_pMMSilenceDevice;\n\nHANDLE hStartedEvent;\nHANDL"
  },
  {
    "path": "source_code/acam/stdafx.cpp",
    "chars": 291,
    "preview": "// stdafx.cpp : source file that includes just the standard includes\r\n// acam.pch will be the pre-compiled header\r\n// st"
  },
  {
    "path": "source_code/acam/stdafx.h",
    "chars": 347,
    "preview": "// stdafx.h : include file for standard system include files,\r\n// or project specific include files that are used freque"
  },
  {
    "path": "source_code/acam/targetver.h",
    "chars": 314,
    "preview": "#pragma once\r\n\r\n// Including SDKDDKVer.h defines the highest available Windows platform.\r\n\r\n// If you wish to build your"
  },
  {
    "path": "source_code/acam/utilities.cpp",
    "chars": 1190,
    "preview": "#include \"stdafx.h\"\r\n#include <stdio.h>\r\n\r\n/* unused ...\r\nvoid logToFile(char *log_this) {\r\n    FILE *f;\r\n\tf = fopen(\"g:"
  },
  {
    "path": "source_code/acam_is_where_all_the_code_is",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "source_code/startup_debug_options",
    "chars": 816,
    "preview": "C:\\Program Files\\Microsoft SDKs\\Windows\\v7.1\\Bin\\graphedt\r\nc:\\dev\\ruby\\virtual-audio-output-sniffer\\yo.grf\r\n\r\nC:\\install"
  },
  {
    "path": "source_code/synth_deprecated/Synth.vcxproj",
    "chars": 11560,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project DefaultTargets=\"Build\" ToolsVersion=\"4.0\" xmlns=\"http://schemas.micros"
  },
  {
    "path": "source_code/synth_deprecated/Synth.vcxproj.filters",
    "chars": 2179,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
  },
  {
    "path": "source_code/synth_deprecated/Synth.vcxproj.user",
    "chars": 385,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbui"
  },
  {
    "path": "source_code/synth_deprecated/dynsrc.cpp",
    "chars": 18267,
    "preview": "//------------------------------------------------------------------------------\r\n// File: DynSrc.cpp\r\n//\r\n// Desc: Dire"
  },
  {
    "path": "source_code/synth_deprecated/dynsrc.h",
    "chars": 6987,
    "preview": "//------------------------------------------------------------------------------\r\n// File: DynSrc.h\r\n//\r\n// Desc: Direct"
  },
  {
    "path": "source_code/synth_deprecated/isynth.h",
    "chars": 3174,
    "preview": "//------------------------------------------------------------------------------\r\n// File: ISynth.h\r\n//\r\n// Desc: Direct"
  },
  {
    "path": "source_code/synth_deprecated/loopback-capture-helpers.cpp",
    "chars": 1445,
    "preview": "\r\n#include <windows.h>\r\n#include <mmsystem.h>\r\n#include <mmdeviceapi.h>\r\n#include <audioclient.h>\r\n#include <stdio.h>\r\n#"
  },
  {
    "path": "source_code/synth_deprecated/loopback-capture.cpp",
    "chars": 10666,
    "preview": "#include <windows.h>\r\n\r\n\r\n#include <mmsystem.h>\r\n#include <mmdeviceapi.h>\r\n#include <audioclient.h>\r\n#include <stdio.h>\r"
  },
  {
    "path": "source_code/synth_deprecated/resource.h",
    "chars": 1848,
    "preview": "//\r\n// Microsoft Visual C++ generated include file.\r\n// Used by synth.rc\r\n//\r\n\r\n#define IDD_BALLPROP                    "
  },
  {
    "path": "source_code/synth_deprecated/synth.cpp",
    "chars": 22333,
    "preview": "//------------------------------------------------------------------------------\r\n// File: Synth.cpp\r\n//\r\n// Desc: Direc"
  },
  {
    "path": "source_code/synth_deprecated/synth.def",
    "chars": 495,
    "preview": ";===========================================================================\r\n;  Copyright (c) 1992-2002  Microsoft Corp"
  },
  {
    "path": "source_code/synth_deprecated/synth.h",
    "chars": 9561,
    "preview": "//------------------------------------------------------------------------------\r\n// File: Synth.h\r\n//\r\n// Desc: DirectS"
  },
  {
    "path": "source_code/synth_deprecated/synth.rc",
    "chars": 4530,
    "preview": "//==========================================================================;\r\n//\r\n//  THIS CODE AND INFORMATION IS PROV"
  },
  {
    "path": "source_code/synth_deprecated/synth.sln",
    "chars": 1233,
    "preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 11.00\r\n# Visual C++ Express 2010\r\nProject(\"{8BC9CEB8-8B4A-11D0-"
  },
  {
    "path": "source_code/synth_deprecated/synth.vcproj",
    "chars": 8574,
    "preview": "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\r\n<VisualStudioProject\r\n\tProjectType=\"Visual C++\"\r\n\tVersion=\"8.00\"\r\n\tName=\""
  },
  {
    "path": "source_code/synth_deprecated/synthprp.cpp",
    "chars": 15344,
    "preview": "//------------------------------------------------------------------------------\r\n// File: SynthPrp.cpp\r\n//\r\n// Desc: Di"
  },
  {
    "path": "source_code/synth_deprecated/synthprp.h",
    "chars": 2152,
    "preview": "//------------------------------------------------------------------------------\r\n// File: SynthPrp.h\r\n//\r\n// Desc: Dire"
  },
  {
    "path": "source_code/synth_deprecated/useless_synth.cpp",
    "chars": 21269,
    "preview": "\r\n\r\n#include <windows.h>\r\n#include <streams.h>\r\n\r\n#include <math.h>\r\n#include <mmreg.h>\r\n#include <msacm.h>\r\n\r\n#include "
  },
  {
    "path": "source_code/virtual audio output sniffer.sln",
    "chars": 1245,
    "preview": "\r\nMicrosoft Visual Studio Solution File, Format Version 11.00\r\n# Visual C++ Express 2010\r\nProject(\"{8BC9CEB8-8B4A-11D0-"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the rdp/virtual-audio-capture-grabber-device GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 53 files (252.3 KB), approximately 67.2k tokens, and a symbol index with 146 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!