I am a Software Development Engineer in Test working for the Windows Sound team. You can contact me via email: mateer at microsoft dot com
Friend key: 28904932216450_59cd9d55374be03d8167d37c8ff4196b
In a previous post I showed how to play silence to a given audio device and hinted at a possible application.
Attached to this post is a sample WASAPI loopback capture app - amd64, x86 and source included. This allows you to record the sound that is coming out of your speakers:
>loopback-capture -?loopback-capture -?loopback-capture --list-devicesloopback-capture [--device "Device long name"] [--file "file name"] [--int-16] -? prints this message. --list-devices displays the long names of all active playback devices. --device captures from the specified device (default if omitted) --file saves the output to a file (loopback-capture.wav if omitted)) --int-16 attempts to coerce data to 16-bit integer format
There are a couple of oddities for WASAPI loopback capture. One is that "event mode" doesn't work for loopback capture; you can call pAudioClient->Initialize(... AUDCLNT_STREAMFLAGS_LOOPBACK | AUDCLNT_STREAMFLAGS_EVENTCALLBACK, ... ), you can call pAudioClient->SetEventHandle(...), and everything will succeed... but the "data is ready" event will never fire. So this app creates its own waitable timer.
Another oddity is that WASAPI will only push data down to the render endpoint when there are active streams. When nothing is playing, there is nothing to capture.
For example, play a song, and then run loopback-capture. While loopback-capture is running, stop the song, and then start it again. You'll get this output when you start it back up:
>loopback-capturePress Enter to quit...IAudioCaptureClient::GetBuffer set flags to 0x00000001 on pass 5381 after 1088829 framesThread HRESULT is 0x8000ffff
The flag in question is AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY. When the song stopped, no more data was available to capture. Eventually the song started up again, and WASAPI dutifully reported that there was a glitch detected. This app stops on glitches.
There are a couple of other possible ways to handle this. One way is to ignore glitches; then if you stop a song, wait a few seconds, and start it again, then the recorded signal will omit the wait and abut the two "audio is playing" portions.
But my particular favorite way of handling this is to run silence.exe. That way there are never any "nothing is playing" glitches, because there's always something playing.
EDIT 11/23/2009: Updated loopback-capture.exe to ignore the glitch flag on the first packet, since Windows 7 sets it. Also improved the interaction between the capture thread bailing out and the user pressing Enter to finish.
Attached to this post is a sample WASAPI exclusive-mode event-driven playback app, including amd64 and x86 binaries, source, and a modification of the ac3.wav Dolby Digital test tone to include a "fact" chunk.
>play-exclusive.exe -?play-exclusive.exe -?play-exclusive.exe --list-devicesplay-exclusive.exe [--device "Device long name"] --file "WAV file name" -? prints this message. --list-devices displays the long names of all active playback devices. Plays the given file to the given device in WASAPI exclusive mode.If no device is specified, plays to the default console device.
>play-exclusive.exe -?play-exclusive.exe -?play-exclusive.exe --list-devicesplay-exclusive.exe [--device "Device long name"] --file "WAV file name"
-? prints this message. --list-devices displays the long names of all active playback devices.
Plays the given file to the given device in WASAPI exclusive mode.If no device is specified, plays to the default console device.
On the particular system I used to test this, these are the devices I have:
>play-exclusive.exe --list-devicesActive render endpoints found: 3 Digital Audio (S/PDIF) (2- High Definition Audio Device) Speakers (2- High Definition Audio Device) Sceptre (High Definition Audio Device)
And this is the output I get when I play the attached ac3.wav test tones to the Sceptre HDMI output:
>play-exclusive --device "Sceptre (High Definition Audio Device)" --file ac3.wavOpening .wav file "ac3.wav"...The default period for this device is 30000 hundred-nanoseconds, or 144 frames.Buffer size not aligned - doing the alignment dance.Trying again with periodicity of 33333 hundred-nanoseconds, or 160 frames.We ended up with a period of 33333 hns or 160 frames.Successfully played all 460800 frames.
A word on the "alignment dance" highlighted above... first, this scene from The Pacifier. (Vin Diesel is so coordinated.)
The Pacifier: The Peter Panda dance
Here's the source for the dance (in play.cpp in the attached.)
// call IAudioClient::Initialize the first time// this may very well fail// if the device period is unalignedhr = pAudioClient->Initialize( AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, hnsPeriod, hnsPeriod, pWfx, NULL);// if you get a compilation error on AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED,// uncomment the #define below//#define AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED AUDCLNT_ERR(0x019)if (AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED == hr) { // if the buffer size was not aligned, need to do the alignment dance printf("Buffer size not aligned - doing the alignment dance.\n"); // get the buffer size, which will be aligned hr = pAudioClient->GetBufferSize(&nFramesInBuffer); if (FAILED(hr)) { printf("IAudioClient::GetBufferSize failed: hr = 0x%08x\n", hr); return hr; } // throw away this IAudioClient pAudioClient->Release(); // calculate the new aligned periodicity hnsPeriod = // hns = (REFERENCE_TIME)( 10000.0 * // (hns / ms) * 1000 * // (ms / s) * nFramesInBuffer / // frames / pWfx->nSamplesPerSec // (frames / s) + 0.5 // rounding ); // activate a new IAudioClient hr = pMMDevice->Activate( __uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient ); if (FAILED(hr)) { printf("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x\n", hr); return hr; } // try initialize again printf("Trying again with periodicity of %I64u hundred-nanoseconds, or %u frames.\n", hnsPeriod, nFramesInBuffer); hr = pAudioClient->Initialize( AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, hnsPeriod, hnsPeriod, pWfx, NULL ); if (FAILED(hr)) { printf("IAudioClient::Initialize failed, even with an aligned buffer: hr = 0x%08x\n", hr); pAudioClient->Release(); return hr; }} else if (FAILED(hr)) { printf("IAudioClient::Initialize failed: hr = 0x%08x\n", hr); pAudioClient->Release(); return hr;} // OK, IAudioClient::Initialize succeeded// let's see what buffer size we actually ended up withhr = pAudioClient->GetBufferSize(&nFramesInBuffer);if (FAILED(hr)) { printf("IAudioClient::GetBufferSize failed: hr = 0x%08x\n", hr); pAudioClient->Release(); return hr;} // calculate the new periodhnsPeriod = // hns = (REFERENCE_TIME)( 10000.0 * // (hns / ms) * 1000 * // (ms / s) * nFramesInBuffer / // frames / pWfx->nSamplesPerSec // (frames / s) + 0.5 // rounding );
// call IAudioClient::Initialize the first time// this may very well fail// if the device period is unalignedhr = pAudioClient->Initialize( AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, hnsPeriod, hnsPeriod, pWfx, NULL);// if you get a compilation error on AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED,// uncomment the #define below//#define AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED AUDCLNT_ERR(0x019)if (AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED == hr) { // if the buffer size was not aligned, need to do the alignment dance printf("Buffer size not aligned - doing the alignment dance.\n"); // get the buffer size, which will be aligned hr = pAudioClient->GetBufferSize(&nFramesInBuffer); if (FAILED(hr)) { printf("IAudioClient::GetBufferSize failed: hr = 0x%08x\n", hr); return hr; } // throw away this IAudioClient pAudioClient->Release();
// calculate the new aligned periodicity hnsPeriod = // hns = (REFERENCE_TIME)( 10000.0 * // (hns / ms) * 1000 * // (ms / s) * nFramesInBuffer / // frames / pWfx->nSamplesPerSec // (frames / s) + 0.5 // rounding );
// activate a new IAudioClient hr = pMMDevice->Activate( __uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient ); if (FAILED(hr)) { printf("IMMDevice::Activate(IAudioClient) failed: hr = 0x%08x\n", hr); return hr; }
// try initialize again printf("Trying again with periodicity of %I64u hundred-nanoseconds, or %u frames.\n", hnsPeriod, nFramesInBuffer); hr = pAudioClient->Initialize( AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, hnsPeriod, hnsPeriod, pWfx, NULL );
if (FAILED(hr)) { printf("IAudioClient::Initialize failed, even with an aligned buffer: hr = 0x%08x\n", hr); pAudioClient->Release(); return hr; }} else if (FAILED(hr)) { printf("IAudioClient::Initialize failed: hr = 0x%08x\n", hr); pAudioClient->Release(); return hr;}
// OK, IAudioClient::Initialize succeeded// let's see what buffer size we actually ended up withhr = pAudioClient->GetBufferSize(&nFramesInBuffer);if (FAILED(hr)) { printf("IAudioClient::GetBufferSize failed: hr = 0x%08x\n", hr); pAudioClient->Release(); return hr;}
// calculate the new periodhnsPeriod = // hns = (REFERENCE_TIME)( 10000.0 * // (hns / ms) * 1000 * // (ms / s) * nFramesInBuffer / // frames / pWfx->nSamplesPerSec // (frames / s) + 0.5 // rounding );
Note the new HRESULT.
HD Audio works on a 128-byte aligned buffer size. This dance ensures that the HD Audio driver is being fed data in chunks of 128 bytes. It is somewhat complicated by the fact that IAudioClient::Initialize takes a parameter of hundred-nano-seconds, but IAudioClient::GetBufferSize sets a parameter of frames.
Last time we examined the "Disney princess" status of Belle from Beauty and the Beast. This time I attempt to give an exhaustive list of all Disney princesses together with a very short summary of their status.
Methodology - I started with Disney's own "50 animated features" list as present on the Tangled DVD. To this I added the list of Pixar and (somewhat more controversially) Studio Ghibli movies released under the Disney name.
1 Nausicaä of the Valley of Wind is technically not a Studio Ghibli film as the studio was not founded until after the film was released. 2 In The Black Cauldron, Taran is not yet aware that he is a prince. 3 In The Little Mermaid, Ursula briefly has a claim to being a queen. Her relationship to Triton is never made clear; if she is his ex-wife, Ariel and her sisters are potentially her daughters. 4 In The Little Mermaid, Triton is briefly incapacitated. His eldest daughter thus has a brief claim to being Queen. 5 In Beauty and the Beast, Belle's princess status hinges on whether she is married to the Beast. 6 In Aladdin, Aladdin spends a fair amount of time transformed into a prince, though it is not clear where his principality lies. 7 In Aladdin, Jafar is briefly Sultan and attempts to woo Jasmine, though there is no reciprocity in their relationship. 8 In The Lion King it is perhaps best not to inquire too closely into the precise nature of the familial relationships between members of the pride in question. 9 The Lion King ends with a shot of Simba and Nala's cub being presented, but it is not clear whether the cub is male or female; in sequels it is made clear that the cub is a girl and her name is Kiara.
Be vewy vewy quiet - we'we hunting wabbits. -- Elmer Fudd
Attached is a mini-app I've written to play silence to any given playback device using WASAPI event-driven (pull) mode. Source, x86 binary, and amd64 binary are attached.
Usage statement:
>silence -?silencesilence -?silence --list-devicessilence --device "Device long name" With no arguments, plays silence to the default audio device. -? prints this message. --list-devices displays the long names of all active playback devices. --device plays silence to the specified device.
>silence --list-devicesActive render endpoints found: 2 Speakers (USB Audio Device) Headphones (High Definition Audio Device)
>silence --device "Headphones (High Definition Audio Device)"Press Enter to quit...Received stop event after 488 passes
While it's playing it shows up in the Volume Mixer:
Why would I write such a thing?
Well, there is the pedagogical exercise of writing a WASAPI event-driven render loop.
But there is also a practical application of an active silence stream, having to do with loopback capture. More on this in a future post...
EDIT: 7/30/2009 - fixed bug where I was treating the GetCurrentPadding value as the amount of free space in the buffer when in fact it's the amount of used space.
While I was at it, added an icon and exited immediately on errors rather than waiting for the caller to hit Enter.
As preparation for moving one of my machines from Vista to Windows 7, I'm compiling a list of all the little tweaks I like to make to machines that I use a lot:
Boot from the Windows DVD. Delete all partitions; make each hard drive one big partition. (Hmm... apparently Windows 7 really wants a second 100 MB partition. Do the partition dance to force it into installing on a single partition.)
In the "password hint" box, type a misleading hint.
In "Help protect your computer and improve Windows automatically", choose "Ask me later."
Once I'm in, create a new limited user (not a member of the Administrators group) and use that as my primary account.
Control Panel | Hardware and Sound | Mouse Pointers | Enable pointer shadow (uncheck) Pointer Options Enhance pointer precision (uncheck) Hide pointer while typing (uncheck)
Right-click taskbar | Properties | Taskbar Use small icons (check) Taskbar location on screen (change to "Right") Taskbar buttons (change to "Never combine") Notification area | Customize Turn system icons on or off Clock | Off (select) Volume | Off (select) Network | Off (select) ... turn everything off, except sometimes. (for example, I might leave Power on for a laptop.) Always show all icons and notifications on the taskbar (check) Use Aero Peek to preview the desktop (uncheck)
Windows Explorer | Organize Layout | Details pane (uncheck) Folder and search options | View | Advanced settings Always show icons, never thumbnails (check) Always show menus (check) Display file icon on thumbnails (uncheck) Display file size information in folder tips (uncheck) Display the full path in the title bar (Classic theme only) (check) Hidden files and folders | Show hidden files, folders, and drives (select) Hide empty drives in the Computer folder (uncheck) Hide extensions for known file types (uncheck) Hide protected operating system files (Recommended) (uncheck, Yes I'm sure) Show pop-up description for folder and desktop items (uncheck)
Control Panel | System and Security | Windows Update | Change settings Download updates but let me choose whether to install them (select) Allow all users to install updates on this computer (check)
Elevated command prompt | gpedit.msc | Local Computer Policy User Configuration | Administrative Templates | Windows Components Windows Explorer | Turn off numerical sorting in Windows Explorer (enable) Computer Configuration | Administrative Templates System Power Management | Video and Display Settings Turn Off Adaptive Display Timeout (Plugged In) (enable) Turn Off Adaptive Display Timeout (On Battery) (enable) Windows Components | Windows Update Do not display 'Install Updates and Shut Down' ... (enable) Do not adjust default option to 'Install Updates and Shut Down' ... (enable)
Control Panel | View by: Small icons (select) AutoPlay | Use AutoPlay for all media and devices (uncheck) Indexing Options | Modify | Show all locations Offline Files (uncheck) C:\Users (uncheck) C:\ProgramData\Microsoft\Windows\Start Menu (uncheck) Troubleshooting | Change settings | Computer Maintenance | Off (select) Windows Defender | Tools Automatic scanning | Automatically scan my computer (uncheck) Real-time protection | Use real-time protection (recommended) (uncheck) Administrator | Use this program (uncheck)
Right-click Start Menu | Properties Customize Computer | Don't display this item (select) Connect To (uncheck) Control Panel | Don't display this item (select) Default Programs (uncheck) Devices and Printers (uncheck) Documents | Don't display this item (select) Enable context menus and dragging and dropping (uncheck) Games | Don't display this item (select) Help (uncheck) Highlight newly installed programs (uncheck) Music | Don't display this item (select) Open submenus when I pause on them with the mouse pointer (uncheck) Personal folder | Don't display this item (select) Pictures | Don't display this item (select) Search other files and libraries | Don't search (select) Search programs and Control Panel (uncheck) Use large icons (uncheck) Number of recent programs to display (set to 20 to make the menu bigger) Number of recent items to display in Jump Lists (set to 20 to make the menu bigger) Store and display recently opened programs in the Start menu (uncheck) Store and display recently opened items in the Start menu and the taskbar (uncheck)
Right-click everything that is pinned to the taskbar Unpin this program from taskbar
Right-click Recycle Bin | Properties For each hard drive in turn (select) Don't move files to the Recycle Bin. Remove files immediately... (select)
Control Panel | Appearance and Personalization Personalization | Change desktop icons | Recycle Bin (uncheck) Change desktop background Picture Location: Solid Colors (select, choose black)
Control Panel | User Accounts | Change your account picture Browse for more pictures
Control Panel | Ease of access Change how your mouse works Mouse pointers | Regular Black (select) Prevent windows from being automatically arranged when moved to the edge of the screen (check) Change how your keyboard works Set up Sticky Keys | Turn on Sticky Keys when SHIFT is pressed five times (uncheck) Optimize visual display Turn off all unnecessary animations (when possible) (check)
Make a folder on the desktop named "_" Open the following folders simultaneously _ C:\ProgramData\Microsoft\Windows\Start Menu C:\Users\%username%\AppData\Roaming\Microsoft\Windows\Start Menu Copy various shortcuts from Start Menu over to _ Notepad Paint Command Prompt Calculator ... whatever else strikes my fancy ... as I install programs, consider adding them here if I use them a lot
Right-click the taskbar | Toolbars | New toolbar... | Desktop | _ (Select Folder) Right-click the taskbar | Lock the taskbar (uncheck) Drag the thumb of the _ toolbar to the top of the taskbar Right-click _ Show Text (uncheck) Show title (uncheck) View | Small Icons (check) Drag the taskbar to be a tiny bit wider so three small icons fit side-by-side Drag the view-active-tasks part of the taskbar to be big Right-click the taskbar | Lock the taskbar (check)
Make a 1-pixel-by-1-pixel black .jpg and set it as the LogonUI background
I'm sure I'm forgetting some other things. I'll add them later when I run into them.
I could probably make a series out of this. Possible candidates for future posts: "Tweaks I make every time I install Office", "Tweaks I make every time I install Firefox"...
Command Prompt | Alt-Space | Defaults | QuickEdit Mode (check)
Recently I was musing on Order vs. Chaos and toying with my Rubik's Cube. I wondered, as a simple exercise, whether it would be possible to strongly unsolve the cube. Obviously there is a single way to put the cube into a state of greatest possible order... and a multitude of ways to put it into a state of moderate to severe chaos... but is there a "most chaotic" state?
Well, I mused, the "greatest possible order" state is achieved by bringing all the orange squares together... and all the blue squares together... and, in general, all the squares of any given color together. How homogenous... or xenophobic. Ew.
Might it not be interesting to intermingle the colors to as great an extent as possible? Can I put the cube in a state where no two orange squares are adjacent... and no two blue squares are adjacent... and, in general, no two adjacent squares are the same color?
Of course, I responded. In fact, I already know how to do that... I learned that trick before I even learned the Restore Order solution.
Twelve turns later, I had a solution to the Adjacent Squares Are Different problem.
Exercise: what are the twelve turns?
Well, that was quick.
But I wanted more.
Yeah, OK, no two adjacent squares are the same color, by the usual definition of adjacency (the squares share a common border.) But this is still a fairly homogenous solution... each face (of nine squares) still consists of only two colors, and there's a very high incidence of diagonally-touching squares of the same color. Can't we diversify this even more?
That took me a couple of days. But here's the solution I came up with:
Note that, as desired, no two adjacent squares are the same color... even if you consider squares that touch only at a corner to be adjacent... even if that corner lies on an edge, and the two squares in question lie on different faces of the cube.
The method to achieving the solution was simple in the sense that it only requires two moves (starting from a solved cube) but is probably far from optimal in the "total number of turns" sense.
There are two independent steps which can be done in either order:
Each requires knowledge of a single move and a fair amount of courage.
First, some syntax.
Hold the cube facing you. I will name the six faces of the cube:
Each face has a local definition of "clockwise"... this is the direction a clock painted on the face would turn.
Cubelet syntax
Move syntax: a letter means turn that face clockwise by 90 degrees. A letter with a subscripted -1 means turn it counterclockwise by 90 degrees. So a move "turn the Fore face clockwise, then turn the Left face counterclockwise, then turn the Top face counterclockwise" would be written:
F L-1 T-1
Start from a solved cube.
Flip the orientation of all twelve of the "edge pieces"
Pick your favorite color - say, red - and have that be the top face.
The following move flips the orientation of the LT and TH edge pieces, and also disturbs the orientation of some corner pieces:
L-1 T-1 L-1 L-1F-1 L-1 F-1 F-1T-1 F-1 T-1 T-1
All twelve of the edge pieces are now flipped. The corner pieces are still in their original positions, though they may be oriented incorrectly. That's OK.
Reposition all eight corner pieces to the opposite corner
The following move repositions FLT to TLH, TLH to TRH, and TRH to FLT:
L-1 T R T-1 L T R-1 T-1
As a convenience, the following mirror-image move repositions FRT to TRH, TRH to TLH, and TLH to FRT:
R T-1 L-1 TR-1 T-1 L T
Strictly speaking, you can get away with only memorizing one of these moves - each move is equivalent to holding the cube in a different position and executing the other move twice.
Pick three faces that share a common corner - say, the faces whose center cubes are red, white, and blue. Position the cube so it is balancing on that corner. Note that the corner cubelets now occupy four distinct strata:
This part of unsolving the cube is completed in four distinct phases:
EDIT January 16 2012: Thanks to Dustin for pointing out that the diagram above shows some reds touching diagonally (near the topmost corner.) After some analysis I believe this is just due to an error on my part in making the image; specifically, the top corner is green-yellow-red, but so is the corner in the top left. Also, the green-yellow-orange corner is missing.
Both of these can be explained by changing the red in the top corner to orange. Updated image:
Source and binaries (amd64 and x86) attached.
Pseudocode:
CoCreateInstance(..., &pMMDeviceEnumerator); pMMDeviceEnumerator->EnumAudioEndpoints(..., &pMMDeviceCollection); for (each device in the collection) { pMMDevice->OpenPropertyStore(..., &pPropertyStore); for (each property in the store) { log the property } }
Output on my system:
>audioendpoints.exe ID: {0.0.0.00000000}.{6d531641-b3e3-43c5-ba56-ba165b4a9bb6} State: 4 (DEVICE_STATE_NOTPRESENT) -- Properties (18) -- {b3f8fa53-0004-438e-9003-51a46e139bfc},15: VT_BLOB of size 16 db 07 06 00 03 00 01 00 17 00 3a 00 2d 00 26 03 DEVPKEY_Device_DeviceDesc: VT_LPWSTR Internal AUX Jack {b3f8fa53-0004-438e-9003-51a46e139bfc},6: VT_LPWSTR High Definition Audio Device {b3f8fa53-0004-438e-9003-51a46e139bfc},2: VT_LPWSTR {1}.HDAUDIO\FUNC_01&VEN_8384&DEV_7690&SUBSYS_102801BD&REV_1022\4&33D044FE&0&0001 {83da6326-97a6-4088-9453-a1923f573b29},3: VT_LPWSTR hdaudio.inf:Microsoft.ntamd64:HdAudModel:6.1.7600.16385::hdaudio\func_01 DEVPKEY_Device_BaseContainerId: VT_CLSID {00000000-0000-0000-ffff-ffffffffffff} DEVPKEY_Device_ContainerId: VT_CLSID {00000000-0000-0000-ffff-ffffffffffff} DEVPKEY_Device_EnumeratorName: VT_LPWSTR HDAUDIO {b3f8fa53-0004-438e-9003-51a46e139bfc},1: VT_BLOB of size 72 a8 7f a4 d5 98 6d d1 11 a2 1a 00 a0 c9 22 31 96 9c ac 97 dc ec dd 59 4d b6 50 3b 8b a6 7b c2 a1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e0 cc 13 de 04 83 e9 4e ba ce 48 24 21 4e 3e a5 00 00 02 00 01 00 00 00 PKEY_AudioEndpoint_FormFactor: VT_UI4 10 PKEY_AudioEndpoint_JackSubType: VT_LPWSTR {6994AD04-93EF-11D0-A3CC-00A0C9223196} DEVPKEY_DeviceClass_IconPath: VT_LPWSTR %windir%\system32\mmres.dll,-3018 {840b8171-b0ad-410f-8581-cccc0382cfef},0: VT_BLOB of size 300 01 00 00 00 28 01 00 00 00 00 01 00 7b 00 32 00 7d 00 2e 00 5c 00 5c 00 3f 00 5c 00 68 00 64 00 61 00 75 00 64 00 69 00 6f 00 23 00 66 00 75 00 6e 00 63 00 5f 00 30 00 31 00 26 00 76 00 65 00 6e 00 5f 00 38 00 33 00 38 00 34 00 26 00 64 00 65 00 76 00 5f 00 37 00 36 00 39 00 30 00 26 00 73 00 75 00 62 00 73 00 79 00 73 00 5f 00 31 00 30 00 32 00 38 00 30 00 31 00 62 00 64 00 26 00 72 00 65 00 76 00 5f 00 31 00 30 00 32 00 32 00 23 00 34 00 26 00 33 00 33 00 64 00 30 00 34 00 34 00 66 00 65 00 26 00 30 00 26 00 30 00 30 00 30 00 31 00 23 00 7b 00 36 00 39 00 39 00 34 00 61 00 64 00 30 00 34 00 2d 00 39 00 33 00 65 00 66 00 2d 00 31 00 31 00 64 00 30 00 2d 00 61 00 33 00 63 00 63 00 2d 00 30 00 30 00 61 00 30 00 63 00 39 00 32 00 32 00 33 00 31 00 39 00 36 00 7d 00 5c 00 65 00 6d 00 69 00 63 00 69 00 6e 00 74 00 6f 00 70 00 6f 00 2f 00 30 00 30 00 30 00 31 00 30 00 30 00 30 00 30 00 00 00 PKEY_AudioEndpoint_Association: VT_LPWSTR {00000000-0000-0000-0000-000000000000} PKEY_AudioEndpoint_Supports_EventDriven_Mode: VT_UI4 1 DEVPKEY_Device_FriendlyName: VT_LPWSTR Internal AUX Jack (High Definition Audio Device) DEVPKEY_DeviceInterface_FriendlyName: VT_LPWSTR High Definition Audio Device PKEY_AudioEndpoint_GUID: VT_LPWSTR {6D531641-B3E3-43C5-BA56-BA165B4A9BB6} ID: {0.0.0.00000000}.{ca9fa848-1e60-401c-81e6-323546335d0a} State: 1 (DEVICE_STATE_ACTIVE) -- Properties (26) -- {b3f8fa53-0004-438e-9003-51a46e139bfc},15: VT_BLOB of size 16 da 07 0a 00 04 00 1c 00 16 00 3a 00 3a 00 d1 00 DEVPKEY_Device_DeviceDesc: VT_LPWSTR Speakers {b3f8fa53-0004-438e-9003-51a46e139bfc},6: VT_LPWSTR High Definition Audio Device {b3f8fa53-0004-438e-9003-51a46e139bfc},2: VT_LPWSTR {1}.HDAUDIO\FUNC_01&VEN_8384&DEV_7690&SUBSYS_102801BD&REV_1022\4&33D044FE&0&0001 {83da6326-97a6-4088-9453-a1923f573b29},3: VT_LPWSTR hdaudio.inf:Microsoft.ntamd64:HdAudModel:6.1.7600.16385::hdaudio\func_01 DEVPKEY_Device_BaseContainerId: VT_CLSID {00000000-0000-0000-ffff-ffffffffffff} DEVPKEY_Device_ContainerId: VT_CLSID {00000000-0000-0000-ffff-ffffffffffff} DEVPKEY_Device_EnumeratorName: VT_LPWSTR HDAUDIO {b3f8fa53-0004-438e-9003-51a46e139bfc},1: VT_BLOB of size 72 a8 7f a4 d5 98 6d d1 11 a2 1a 00 a0 c9 22 31 96 9c ac 97 dc ec dd 59 4d b6 50 3b 8b a6 7b c2 a1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e0 cc 13 de 04 83 e9 4e ba ce 48 24 21 4e 3e a5 00 00 02 00 01 00 00 00 PKEY_AudioEndpoint_FormFactor: VT_UI4 1 PKEY_AudioEndpoint_JackSubType: VT_LPWSTR {DFF21CE1-F70F-11D0-B917-00A0C9223196} DEVPKEY_DeviceClass_IconPath: VT_LPWSTR %windir%\system32\mmres.dll,-3010 {840b8171-b0ad-410f-8581-cccc0382cfef},0: VT_BLOB of size 324 01 00 00 00 40 01 00 00 00 00 01 00 7b 00 32 00 7d 00 2e 00 5c 00 5c 00 3f 00 5c 00 68 00 64 00 61 00 75 00 64 00 69 00 6f 00 23 00 66 00 75 00 6e 00 63 00 5f 00 30 00 31 00 26 00 76 00 65 00 6e 00 5f 00 38 00 33 00 38 00 34 00 26 00 64 00 65 00 76 00 5f 00 37 00 36 00 39 00 30 00 26 00 73 00 75 00 62 00 73 00 79 00 73 00 5f 00 31 00 30 00 32 00 38 00 30 00 31 00 62 00 64 00 26 00 72 00 65 00 76 00 5f 00 31 00 30 00 32 00 32 00 23 00 34 00 26 00 33 00 33 00 64 00 30 00 34 00 34 00 66 00 65 00 26 00 30 00 26 00 30 00 30 00 30 00 31 00 23 00 7b 00 36 00 39 00 39 00 34 00 61 00 64 00 30 00 34 00 2d 00 39 00 33 00 65 00 66 00 2d 00 31 00 31 00 64 00 30 00 2d 00 61 00 33 00 63 00 63 00 2d 00 30 00 30 00 61 00 30 00 63 00 39 00 32 00 32 00 33 00 31 00 39 00 36 00 7d 00 5c 00 65 00 73 00 6c 00 61 00 76 00 65 00 64 00 68 00 70 00 73 00 70 00 65 00 61 00 6b 00 65 00 72 00 74 00 6f 00 70 00 6f 00 2f 00 30 00 30 00 30 00 31 00 30 00 30 00 30 00 31 00 00 00 00 00 00 00 PKEY_AudioEndpoint_Association: VT_LPWSTR {00000000-0000-0000-0000-000000000000} PKEY_AudioEndpoint_Supports_EventDriven_Mode: VT_UI4 1 {9a82a7db-3ebb-41b4-83ba-18b7311718fc},1: VT_UI4 65536 {233164c8-1b2c-4c7d-bc68-b671687a2567},1: VT_LPWSTR {2}.\\?\hdaudio#func_01&ven_8384&dev_7690&subsys_102801bd&rev_1022#4&33d044fe&0&0001#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\eslavedhpspeakerwave {5a9125b7-f367-4924-ace2-0803a4a3a471},0: VT_UI4 1610652916 {5a9125b7-f367-4924-ace2-0803a4a3a471},2: VT_UI4 1610644836 {b3f8fa53-0004-438e-9003-51a46e139bfc},0: VT_UI4 1 PKEY_AudioEngine_DeviceFormat: VT_BLOB of size 40 fe ff 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 16 00 10 00 03 00 00 00 01 00 00 00 00 00 10 00 80 00 00 aa 00 38 9b 71 {e4870e26-3cc5-4cd2-ba46-ca0a9a70ed04},0: VT_BLOB of size 40 fe ff 02 00 44 ac 00 00 20 62 05 00 08 00 20 00 16 00 20 00 03 00 00 00 03 00 00 00 00 00 10 00 80 00 00 aa 00 38 9b 71 {e4870e26-3cc5-4cd2-ba46-ca0a9a70ed04},1: VT_BLOB of size 8 d3 8c 01 00 00 00 00 00 DEVPKEY_Device_FriendlyName: VT_LPWSTR Speakers (High Definition Audio Device) DEVPKEY_DeviceInterface_FriendlyName: VT_LPWSTR High Definition Audio Device PKEY_AudioEndpoint_GUID: VT_LPWSTR {CA9FA848-1E60-401C-81E6-323546335D0A} ID: {0.0.1.00000000}.{4f5e42d9-227f-43ff-bf5b-a1ce5d0324cf} State: 8 (DEVICE_STATE_UNPLUGGED) -- Properties (28) -- {b3f8fa53-0004-438e-9003-51a46e139bfc},15: VT_BLOB of size 16 da 07 0a 00 04 00 1c 00 16 00 3a 00 3a 00 0f 01 DEVPKEY_Device_DeviceDesc: VT_LPWSTR Microphone {b3f8fa53-0004-438e-9003-51a46e139bfc},6: VT_LPWSTR High Definition Audio Device {b3f8fa53-0004-438e-9003-51a46e139bfc},2: VT_LPWSTR {1}.HDAUDIO\FUNC_01&VEN_8384&DEV_7690&SUBSYS_102801BD&REV_1022\4&33D044FE&0&0001 {83da6326-97a6-4088-9453-a1923f573b29},3: VT_LPWSTR hdaudio.inf:Microsoft.ntamd64:HdAudModel:6.1.7600.16385::hdaudio\func_01 DEVPKEY_Device_BaseContainerId: VT_CLSID {00000000-0000-0000-ffff-ffffffffffff} DEVPKEY_Device_ContainerId: VT_CLSID {00000000-0000-0000-ffff-ffffffffffff} DEVPKEY_Device_EnumeratorName: VT_LPWSTR HDAUDIO {b3f8fa53-0004-438e-9003-51a46e139bfc},1: VT_BLOB of size 72 a8 7f a4 d5 98 6d d1 11 a2 1a 00 a0 c9 22 31 96 9c ac 97 dc ec dd 59 4d b6 50 3b 8b a6 7b c2 a1 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 e0 cc 13 de 04 83 e9 4e ba ce 48 24 21 4e 3e a5 00 00 02 00 01 00 00 00 PKEY_AudioEndpoint_FormFactor: VT_UI4 4 PKEY_AudioEndpoint_JackSubType: VT_LPWSTR {DFF21BE1-F70F-11D0-B917-00A0C9223196} DEVPKEY_DeviceClass_IconPath: VT_LPWSTR %windir%\system32\mmres.dll,-3014 {840b8171-b0ad-410f-8581-cccc0382cfef},0: VT_BLOB of size 300 01 00 00 00 28 01 00 00 00 00 01 00 7b 00 32 00 7d 00 2e 00 5c 00 5c 00 3f 00 5c 00 68 00 64 00 61 00 75 00 64 00 69 00 6f 00 23 00 66 00 75 00 6e 00 63 00 5f 00 30 00 31 00 26 00 76 00 65 00 6e 00 5f 00 38 00 33 00 38 00 34 00 26 00 64 00 65 00 76 00 5f 00 37 00 36 00 39 00 30 00 26 00 73 00 75 00 62 00 73 00 79 00 73 00 5f 00 31 00 30 00 32 00 38 00 30 00 31 00 62 00 64 00 26 00 72 00 65 00 76 00 5f 00 31 00 30 00 32 00 32 00 23 00 34 00 26 00 33 00 33 00 64 00 30 00 34 00 34 00 66 00 65 00 26 00 30 00 26 00 30 00 30 00 30 00 31 00 23 00 7b 00 36 00 39 00 39 00 34 00 61 00 64 00 30 00 34 00 2d 00 39 00 33 00 65 00 66 00 2d 00 31 00 31 00 64 00 30 00 2d 00 61 00 33 00 63 00 63 00 2d 00 30 00 30 00 61 00 30 00 63 00 39 00 32 00 32 00 33 00 31 00 39 00 36 00 7d 00 5c 00 65 00 6d 00 69 00 63 00 69 00 6e 00 74 00 6f 00 70 00 6f 00 2f 00 30 00 30 00 30 00 31 00 30 00 30 00 30 00 31 00 00 00 PKEY_AudioEndpoint_Association: VT_LPWSTR {00000000-0000-0000-0000-000000000000} PKEY_AudioEndpoint_Supports_EventDriven_Mode: VT_UI4 1 {24dbb0fc-9311-4b3d-9cf0-18ff155639d4},3: VT_BOOL 0xffffffff {24dbb0fc-9311-4b3d-9cf0-18ff155639d4},4: VT_BOOL 0xffffffff {9a82a7db-3ebb-41b4-83ba-18b7311718fc},1: VT_UI4 65536 {233164c8-1b2c-4c7d-bc68-b671687a2567},1: VT_LPWSTR {2}.\\?\hdaudio#func_01&ven_8384&dev_7690&subsys_102801bd&rev_1022#4&33d044fe&0&0001#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\emicinwave {5a9125b7-f367-4924-ace2-0803a4a3a471},0: VT_UI4 1610712932 {5a9125b7-f367-4924-ace2-0803a4a3a471},2: VT_UI4 1610708836 {b3f8fa53-0004-438e-9003-51a46e139bfc},0: VT_UI4 3 PKEY_AudioEngine_DeviceFormat: VT_BLOB of size 40 fe ff 02 00 44 ac 00 00 10 b1 02 00 04 00 10 00 16 00 10 00 03 00 00 00 01 00 00 00 00 00 10 00 80 00 00 aa 00 38 9b 71 {e4870e26-3cc5-4cd2-ba46-ca0a9a70ed04},0: VT_BLOB of size 40 fe ff 02 00 44 ac 00 00 20 62 05 00 08 00 20 00 16 00 20 00 03 00 00 00 03 00 00 00 00 00 10 00 80 00 00 aa 00 38 9b 71 {e4870e26-3cc5-4cd2-ba46-ca0a9a70ed04},1: VT_BLOB of size 8 d3 8c 01 00 00 00 00 00 DEVPKEY_Device_FriendlyName: VT_LPWSTR Microphone (High Definition Audio Device) DEVPKEY_DeviceInterface_FriendlyName: VT_LPWSTR High Definition Audio Device PKEY_AudioEndpoint_GUID: VT_LPWSTR {4F5E42D9-227F-43FF-BF5B-A1CE5D0324CF} ID: {0.0.1.00000000}.{6712184b-f8f0-474d-ad36-808cc90a7cfd} State: 4 (DEVICE_STATE_NOTPRESENT) -- Properties (29) -- {b3f8fa53-0004-438e-9003-51a46e139bfc},15: VT_BLOB of size 16 db 07 03 00 01 00 15 00 10 00 3b 00 21 00 f4 00 DEVPKEY_Device_DeviceDesc: VT_LPWSTR Microphone Array {b3f8fa53-0004-438e-9003-51a46e139bfc},6: VT_LPWSTR Microphone Array {b3f8fa53-0004-438e-9003-51a46e139bfc},2: VT_LPWSTR {1}.USB\VID_045E&PID_FFF0&MI_01\6&1474EDB6&0&0001 {83da6326-97a6-4088-9453-a1923f573b29},3: VT_LPWSTR wdma_usb.inf:Microsoft.ntamd64:USBAudio:6.1.7600.16385:usb\class_01 DEVPKEY_Device_BaseContainerId: VT_CLSID {9132f6ea-a152-5472-8685-61c0d297a30b} DEVPKEY_Device_ContainerId: VT_CLSID {9132f6ea-a152-5472-8685-61c0d297a30b} DEVPKEY_Device_EnumeratorName: VT_LPWSTR USB {b3f8fa53-0004-438e-9003-51a46e139bfc},1: VT_BLOB of size 72 30 f1 1c 4e 79 16 3b 46 a7 2f a5 bf 64 c8 6e ba 4e 5a cd ab 63 c2 3b 46 a7 2f a5 bf 64 c8 6e ba f0 75 12 8f e9 26 64 42 ba 4d 39 ff f0 1d 94 aa a6 54 57 fc f8 2d 3b 46 a7 2f a5 bf 64 c8 6e ba 02 00 00 00 09 00 00 00 PKEY_AudioEndpoint_FormFactor: VT_UI4 4 PKEY_AudioEndpoint_JackSubType: VT_LPWSTR {DFF21BE5-F70F-11D0-B917-00A0C9223196} DEVPKEY_DeviceClass_IconPath: VT_LPWSTR %windir%\system32\mmres.dll,-3020 {840b8171-b0ad-410f-8581-cccc0382cfef},0: VT_BLOB of size 236 01 00 00 00 e8 00 00 00 00 00 01 00 7b 00 32 00 7d 00 2e 00 5c 00 5c 00 3f 00 5c 00 75 00 73 00 62 00 23 00 76 00 69 00 64 00 5f 00 30 00 34 00 35 00 65 00 26 00 70 00 69 00 64 00 5f 00 66 00 66 00 66 00 30 00 26 00 6d 00 69 00 5f 00 30 00 31 00 23 00 36 00 26 00 31 00 34 00 37 00 34 00 65 00 64 00 62 00 36 00 26 00 30 00 26 00 30 00 30 00 30 00 31 00 23 00 7b 00 36 00 39 00 39 00 34 00 61 00 64 00 30 00 34 00 2d 00 39 00 33 00 65 00 66 00 2d 00 31 00 31 00 64 00 30 00 2d 00 61 00 33 00 63 00 63 00 2d 00 30 00 30 00 61 00 30 00 63 00 39 00 32 00 32 00 33 00 31 00 39 00 36 00 7d 00 5c 00 67 00 6c 00 6f 00 62 00 61 00 6c 00 2f 00 30 00 30 00 30 00 31 00 30 00 30 00 30 00 31 00 00 00 00 00 00 00 00 00 PKEY_AudioEndpoint_Association: VT_LPWSTR {00000000-0000-0000-0000-000000000000} PKEY_AudioEndpoint_Supports_EventDriven_Mode: VT_UI4 1 {24dbb0fc-9311-4b3d-9cf0-18ff155639d4},3: VT_BOOL 0x0 {24dbb0fc-9311-4b3d-9cf0-18ff155639d4},4: VT_BOOL 0xffffffff {9a82a7db-3ebb-41b4-83ba-18b7311718fc},1: VT_UI4 65536 {233164c8-1b2c-4c7d-bc68-b671687a2567},1: VT_LPWSTR {2}.\\?\usb#vid_045e&pid_fff0&mi_01#6&1474edb6&0&0001#{6994ad04-93ef-11d0-a3cc-00a0c9223196}\global {5a9125b7-f367-4924-ace2-0803a4a3a471},0: VT_UI4 1610713736 {5a9125b7-f367-4924-ace2-0803a4a3a471},2: VT_UI4 1610709736 {b3f8fa53-0004-438e-9003-51a46e139bfc},0: VT_UI4 3 PKEY_AudioEngine_DeviceFormat: VT_BLOB of size 40 fe ff 04 00 80 3e 00 00 00 f4 01 00 08 00 10 00 16 00 10 00 00 00 00 00 01 00 00 00 00 00 10 00 80 00 00 aa 00 38 9b 71 {e4870e26-3cc5-4cd2-ba46-ca0a9a70ed04},0: VT_BLOB of size 40 fe ff 04 00 80 3e 00 00 00 e8 03 00 10 00 20 00 16 00 20 00 00 00 00 00 03 00 00 00 00 00 10 00 80 00 00 aa 00 38 9b 71 {e4870e26-3cc5-4cd2-ba46-ca0a9a70ed04},1: VT_BLOB of size 8 a0 86 01 00 00 00 00 00 {9855c4cd-df8c-449c-a181-8191b68bd06c},0: VT_BLOB of size 16 00 00 f0 41 00 00 f0 41 00 00 f0 41 00 00 f0 41 DEVPKEY_Device_FriendlyName: VT_LPWSTR Microphone Array (Microphone Array) DEVPKEY_DeviceInterface_FriendlyName: VT_LPWSTR Microphone Array PKEY_AudioEndpoint_GUID: VT_LPWSTR {6712184B-F8F0-474D-AD36-808CC90A7CFD}
The unrecognized properties could be private properties used by the OS, or by the audio driver, or they might be defined in some public header that I didn't bother to scour.
UPDATE 2011-09-09: added WAVEFORMATEX logging for properties known to be audio formats.
In the first Matrix movie there's a very interesting character called Cypher. If you go along with the theory that the Matrix series is a rough retelling of the story of Christ, Cypher is the closest analog to Judas Iscariot, who is one of the earliest very-interesting-characters.
Unfortunately I personally found that the actor kind of got in the way of the character sometimes.
For example, in his scene with Neo, Cypher has this line
The image translators work for the construct program - but there's way too much information to decode the Matrix.
The actor delivers this line in such a way (the image translators work for the construct program) as to imply that there are these thingies called "image translators", and this other thingy called a "construct program". Furthermore, these "image translator" thingies are currently in the employ of the "construct program". The "construct program" is apparently a very nasty beast with close ties to the machine Gestapo. Therefore, if we were so foolish as to attempt to recruit the talents of the "image translators", the "construct program" would find out, and then we'd be in big trouble.
It follows then, as the night the day, that we are thrown on our own, limited, resources... and what with piloting the ship and arranging the menu and what-not, decoding the matrix (being a substantial task) is rather low on the priority list.
Sigh.
This would be an interesting reading, filled with wonderful foreshadowings of the inevitable discovery of Zion by the machines, except for one thing.
It is already firmly established that the "construct program" is the Holodeck-like-thing that the crew of the Nebuchadnezzar use to equip themselves with simulated equipment (and simulated skills) for use in the simulated reality of the Matrix. So the above reading is, of course, nonsense. The correct implication of the line is:
There are these thingies called "image translators." We throw bits of code at them and they translate them into electrical stimuluses that our brain interprets as images. They can handle such-and-such amount of code.
The construct program is under our control, and we scale back the amount of code it generates to what our image translators can handle. That is why when you enter the construct program you can "see" your residual self-image and whatnot.
However, the Matrix is not under our control, so we can't scale the amount of code it generates. It so happens that the Matrix generates an awful lot of code, which overpowers our image translators... which is why these monitors just show a bunch of greenish symbols instead of pretty girls with hair of various colors.
A delivery that gets this across would be more like
The image translators work - for the construct program - but there's way too much information to decode the Matrix.
If you've bowled, you know the arrangement of the bowling pins forms a triangle.
(Image courtesy of the International Pumpkin Federation.)
If you've played eight-ball, you know the arrangement of the fifteen billiard balls forms a triangle.
Ten, fifteen... what other numbers form a triangle? The common arrangement of nine-ball and ninepins doesn't count because it's a diamond, not a triangle.
You can start with ten and add five balls to make a triangle of fifteen... then add six more to make a triangle of 21... then seven more to make a triangle of 28... and so on, with this sequence:
..., 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105, 120, 136, 153, 171, 190, 210, 231...
Start looking for patterns. What do you see? Nothing jumps out right away. Are there any primes? Ones that end in 0, 2, 4, 6, or 8 are obviously even and therefore not primes... ones that end in 5 are divisible by 5 and therefore not primes... the remaining ones fall due to specific cases (21 = 3 x 7; 91 = 7 x 13; 153 = 3 x 3 x 17; 171 = 3 x 3 x 19; 231 = 3 x 7 x 11...)
In fact, gosh darn it, it seems like none of these numbers are prime, no matter how far we extend that "..." on the right! Can this be a coincidence?
A few mental coruscations later I have an idea that it is not a coincidence... that triangular numbers, by there very nature, cannot be prime. In fact I'm even willing to call it a "proof." Here it is.
"Theorem": there are no triangular primes.
First we need to generate a formula for the triangular numbers. Note that if you take an n x (n + 1) rectangle and draw a zig-zag line like so, you get two triangles.
Each of these triangles is composed of n diagonals, the shortest of which is 1, and the longest of which is n. That is to say, each of the triangles is composed of tn squares. So we know that the total number of squares in the rectangle is 2tn.
But we also know that the total number of squares is the base times the height, or n(n + 1). This gives us 2tn = n(n + 1), or tn = n(n + 1)/2.
The next part of the "proof" breaks down into case analysis. n can be odd (as in the diagram, where n is 5) or even.
Case where n is even:
n is an even positive number. Therefore n/2 is a positive number (maybe odd, maybe even; doesn't matter.) tn can be written as (n/2)(n + 1), and is therefore not prime, since it has at least four factors: 1, n/2, n + 1, and tn.
Case where n is odd:
n is an odd positive number. Therefore n + 1 is an even positive number. Therefore (n + 1)/2 is a positive number (maybe odd, maybe even; doesn't matter.) tn can be written as (n)([n + 1]/2), and is therefore not prime, since it has at least four factors: 1, n, (n + 1)/2, and tn.
Note that the "proof" that tn is not prime inevitably concludes in a stronger result - that tn has at least four factors... not only is tn not prime, it can't even have as few as three factors. (Some numbers with three factors: 4, 9, 25, 49...)
Exercise: what kind of numbers have exactly three factors?
A beautiful proof. Perhaps the two cases can be elegantly folded together to normalize it a bit better. That is not a serious problem.
There is a serious problem.
The proof of our result is doomed.
Why?
Because the result does not hold! There is a triangular prime.
Exercise: find a triangular prime.
After having recovered from the shocking revelation that, our beautiful proof to the contrary, a triangular prime is so rude as to exist, a little self-examination is in order. What is wrong with the proof? This... and not the existence of triangular primes... is the lesson to be learned: that beauty is not always truth.
I stumbled on hmlee's algorithm chart quite by chance. A lot of good questions in there.
Question 53 caught my eye as a mathematician.
Q53: Say you have three integers between 0 - 9. You have the equation: A! + B! + C! = ABC (where ABS is a three digit numbers, not A * B * C). Find A, B, and C that satisfies this equation.
Interesting. But I'd like to modify the question a little.
Q53': Say you have three integers between 0 - 9. You have the equation: A! + B! + C! = A * B * C.Find A, B, and C that satisfies this equation.
Astute readers will notice that A, B, and C are interchangeable. Nonetheless there is a unique solution (modulo swapping A, B, and C.)
I'm much less interested in the answer to this question (I know the answer) than I am in the quality of the program used to find the answer. (I tried finding the answer by hunt-and-peck, then gave up and wrote a program - I find the program to be more interesting than the answer.) Try to find the solution as efficiently as possible (without cheating.)
I'll post my program later.
If you see a fact, try to see it as intuitively as possible.
I suspect that the following even more general problem has the same unique solution, which would be very interesting indeed. This is the kind of thing where programs fail, and the mathematical mind becomes necessary again:
Q53'': Say you have three integers that are >= 0. You have the equation: A! + B! + C! = A * B * C. Find A, B, and C that satisfies this equation.
I'm a casual reader of Randall Munroe's xkcd web comic. I'm partial especially to the artistic episodes.
I was reading the "How it Works" episode, reproduced here:
Fine, a noble sentiment (women in the hard sciences are unfairly targeted) and well executed.
As is my wont, I then went for the extra bit of juiciness to the episode by hovering over the image, and what do I find?
It's pi plus C, of course.
... OK, fine. A good reference to an in-joke in the mathematical community. Well done.
... except I can't stomach the idea of "π plus a constant." It just doesn't sit right. And there's something wrong about the equation on the board. It's missing something... else.
The equation as it appears on the board:
... and the suggested improvement:
Yeah. I still don't buy it.
Under the premise that the best way to spoil a good joke is to analyze it, let's see if we can figure out what our characters are trying to do with this integral, shall we?
Well, there are integrals and integrals. There are at least three common uses of integrals:
The "plus a constant" comment applies exclusively to the first use. The function y = x2 is analytic everywhere and so is not likely to be interesting for a contour integral. But the second use seems to be very appropriate to this "integral equals a constant" equation:
The first thing to do is find the antiderivative. This can occasionally be very difficult, but in this case we have a textbook function which is the first recipe anyone memorizes:
The above formula holds for all p except for p = -1. That one's a little tricky because the denominator above would be 0. For completeness, here's the case with p = -1:
A little faith is required if you haven't seen the derivation, but it works out. (This is as good a definition as any of ln x, FWIW.)
Indeed, the antiderivative is a whole family of functions which differ only by a constant. But if we're going to evaluate it at certain limits, we need to (eventually) know what the limits are. Let's call them a and b for now:
(Note in particular that the evaluation doesn't depend on which of the family of functions we chose... C cancels out. This is my problem with the comment.)
Setting p = 2 we still have a single equation in two unknowns (a and b). Still need more information.
Well, let's think about it for a minute. Many functions have "natural" points of evaluation. For x2 this is 0. For 1/x it's 1. What if we set a = 0? The natural-ness of 0 as a base point of evaluation is made clear from a graph of y = x2:
If we set p = 2 and a = 0, then the equation above reduces to the solvable problem:
The solution is now trivial:
So we can complete the original blackboard equation as follows:
or in fuller generality as
for any a.
(I'm sticking with the a = 0 solution, myself.)
The dice game Yahtzee takes thirteen turns. Each turn involves rolling a set of five dice (with two possible rerolls, the player having the option to reroll only a subset of the dice), then marking one of thirteen boxes and scoring points according to whether the numbers on the dice meet the rules of the box. After each box is marked, the game is over.
The thirteen boxes and their rules are:
There are two bonuses possible:
So a perfect Yahtzee game looks like this. On the first turn...
... then on the following turns, in no particular order (but see below:)
Now we look at the bonuses and add it all up:
So a perfect score in Yahtzee is 1480 or 1505.
Well...
... not quite. There's another rule about Yahtzees (the "Joker" rule) which I didn't tell you about yet, because it's kind of complicated. If...
... you can score this roll in any unchecked box and it automatically meets the scoring criterion (wow!) So you would get 30 points in SMALL STRAIGHT or 40 points in LARGE STRAIGHT. (Or 25 points in FULL HOUSE.)1
This gives an additional 70 or 95 points, bring the total to 1575. (It also creates additional order dependencies; the boxes for FULL HOUSE, SMALL STRAIGHT, and LARGE STRAIGHT must be checked after the ONES through SIXES box for the corresponding number is checked.)
1 Does five-of-a-kind count as a full house? I'm not sure. Mathematically it would make sense. It turns out not to matter for this calculation because of the Joker rule, but it may matter in an actual game. The official rules say "Score in this box only if the dice show three of one number and two of another", so I guess not, but I would be comfortable adopting a "house rule" which allowed a Yahtzee to count as a "native" full house. Normally a house rule should be agreed upon by all players before the start of the game, but I'm pretty sure it would be possible to convince the other players to let you score your (3 3 3 3 3) in FULL HOUSE while YAHTZEE was still open. ("You want to throw away 25 points? Really? Um, go right ahead...")
2 The lowest possible Yahtzee score is 5: get (1 1 1 1 1) and score it in Chance, then get zeros in all the other boxes.
As a tester on Windows 8 I install Windows on my dev machine very frequently.
I use F12 to boot from the network into WinPE, then I run a .bat file which looks something like this:
@echo offsetlocal enabledelayedexpansionset PASSWORD_ADMIN=(redacted)set PASSWORD_MATEER=(redacted)set LICENSE_KEY=(redacted)set FANCYLANG=qps-plocmdel unattend-processed.xmlfor /f "usebackq delims=" %%l in (`type unattend-template.xml`) do ( set line=%%l set line=!line:#PASSWORD_ADMIN#=%PASSWORD_ADMIN%! set line=!line:#PASSWORD_MATEER#=%PASSWORD_MATEER%! set line=!line:#LICENSE_KEY#=%LICENSE_KEY%! set line=!line:#FANCY_LANG#=%FANCY_LANG%! echo !line! >> unattend-processed.xml)setup.exe /unattend:unattend-processed.xml
This takes my template unattend.xml file, injects various parameters, and calls setup.exe.
The template unattend.xml follows in all of its glory. We'll take a closer look at some of the things in future posts.
<?xml version="1.0" encoding="utf-8"?><unattend xmlns="urn:schemas-microsoft-com:unattend"> <settings pass="windowsPE"> <component name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <UserData> <ProductKey> <WillShowUI>OnError</WillShowUI> <Key>#LICENSE_KEY#</Key> </ProductKey> <AcceptEula>true</AcceptEula> <FullName>Matthew van Eerde</FullName> <Organization>Microsoft</Organization> </UserData> <DiskConfiguration> <Disk wcm:action="add"> <CreatePartitions> <CreatePartition wcm:action="add"> <Order>1</Order> <Extend>true</Extend> <Type>Primary</Type> </CreatePartition> </CreatePartitions> <WillWipeDisk>true</WillWipeDisk> <DiskID>0</DiskID> </Disk> </DiskConfiguration> <ImageInstall> <OSImage> <WillShowUI>OnError</WillShowUI> <InstallToAvailablePartition>true</InstallToAvailablePartition> </OSImage> </ImageInstall> </component> <component name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SetupUILanguage> <UILanguage>#FANCY_LANG#</UILanguage> </SetupUILanguage> <InputLocale>0409:00000409</InputLocale> <UserLocale>en-US</UserLocale> <SystemLocale>en-US</SystemLocale> <UILanguage>#FANCY_LANG#</UILanguage> </component> </settings> <settings pass="specialize"> <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Identification> <Credentials> <Domain>redmond.corp.microsoft.com</Domain> <Password>#PASSWORD_MATEER#</Password> <Username>MatEer</Username> </Credentials> <JoinDomain>ntdev.corp.microsoft.com</JoinDomain> </Identification> </component> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <ComputerName>MATEER-Q</ComputerName> <RegisteredOwner>Matthew van Eerde</RegisteredOwner> <RegisteredOrganization>Microsoft</RegisteredOrganization> </component> <component name="Microsoft-Windows-TerminalServices-LocalSessionManager" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <fDenyTSConnections>false</fDenyTSConnections> </component> <component name="Networking-MPSSVC-Svc" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <FirewallGroups> <FirewallGroup wcm:action="add" wcm:keyValue="RemoteDesktop"> <Active>true</Active> <Profile>all</Profile> <Group>@FirewallAPI.dll,-28752</Group> </FirewallGroup> </FirewallGroups> </component> </settings> <settings pass="oobeSystem"> <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <OOBE> <HideEULAPage>true</HideEULAPage> <NetworkLocation>Work</NetworkLocation> <ProtectYourPC>3</ProtectYourPC> <HideOnlineAccountScreens>true</HideOnlineAccountScreens> <HideLocalAccountScreen>true</HideLocalAccountScreen> <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE> </OOBE> <UserAccounts> <LocalAccounts> <LocalAccount wcm:action="add"> <Password> <Value>#PASSWORD_ADMIN#</Value> <PlainText>true</PlainText> </Password> <Name>Admin</Name> <Group>Administrators</Group> </LocalAccount> </LocalAccounts> <DomainAccounts> <DomainAccountList wcm:action="add"> <Domain>redmond.corp.microsoft.com</Domain> <DomainAccount wcm:action="add"> <Group>RemoteDesktopUsers</Group> <Name>MatEer</Name> </DomainAccount> </DomainAccountList> </DomainAccounts> </UserAccounts> <TimeZone>Pacific Standard Time</TimeZone> <AutoLogon> <Password> <Value>#PASSWORD_MATEER#</Value> <PlainText>true</PlainText> </Password> <Domain>redmond.corp.microsoft.com</Domain> <Enabled>true</Enabled> <LogonCount>1</LogonCount> <Username>MatEer</Username> </AutoLogon> </component> </settings></unattend>
vbBretty on the audio forums asked how to tell if a given audio output and a given audio input were on the same physical audio card.
I found the exercise interesting enough to share here:
There's a bug that got away from me in Windows 7's HD Audio class driver (hdaudio.sys.)
Before I explain the bug, a few caveats:
If you're using Vista, there's no problem. This only affects Windows 7.
If you use the third-party audio driver, there's no problem. This only affects the Microsoft HD Audio class driver (hdaudio.sys.)
If your recording devices (mic and line in) are independent (can capture from both at the same time) or muxed (can capture from one or the other but not from their sum) then you're fine; this only affects mixed capture (can capture from one, from the other, or from their sum, but not from both sides of the mix independently.)
If either of your recording devices doesn't support jack presence detection then you're fine; this only affects mixed capture where both sides of the mix support jack presence detection.
Here's the bug.
Here's a sample state diagram assuming a mixed Mic and Line In (click to view full-size:)
Workarounds:
Install the third-party audio driver instead of the HD Audio class driver.
Use audio extension cables to fool the jack presence detection hardware into thinking something is always plugged in.
Back in Windows 7 I did a fair amount of UI testing for the Sound team.
One of the problems with testing UI is it gives you an unconscious attention to detail that's difficult to unlearn.
For example, this Outlook bug didn't bother me before... but now it does.
Exercise: what is the bug?
Answer next week.
EDIT 4/19/201: Answer.
What happens if Double Jeopardy ends and all contestants are in the red (or have no money?)
Do they skip Final Jeopardy and pick three new people for the next show?
Found this in a code review.
Well, in all candor, I didn't find it; our automated code review tool found it. But I'm taking credit for it because I read the output of the automated code review tool. :-)
Code rewritten because I'm too lazy to look it up.
// macros.h#define ENSURE_EQUAL(x, y) if (x != y) { bail(); }
// implementation.cpp...hr = foo();ENSURE_EQUAL( foo_supported() ? S_OK : E_FOO_NOT_SUPPORTED, hr );...
This shows how to call waveInGetNumDevs, waveInGetDevCaps, waveOutGetNumDevs, and waveOutGetDevCaps.
// main.cpp
#include <windows.h>#include <mmsystem.h>#include <stdio.h>
#define LOG(format, ...) wprintf(format L"\n", __VA_ARGS__)
int _cdecl wmain() {
UINT devs = waveInGetNumDevs(); LOG(L"waveIn devices: %u", devs); for (UINT dev = 0; dev < devs; dev++) { WAVEINCAPS caps = {}; MMRESULT mmr = waveInGetDevCaps(dev, &caps, sizeof(caps)); if (MMSYSERR_NOERROR != mmr) { LOG(L"waveInGetDevCaps failed: mmr = 0x%08x", mmr); return mmr; } LOG( L"-- waveIn device #%u --\n" L"Manufacturer ID: %u\n" L"Product ID: %u\n" L"Version: %u.%u\n" L"Product Name: %s\n" L"Formats: 0x%x\n" L"Channels: %u\n" L"Reserved: %u\n" , dev, caps.wMid, caps.wPid, caps.vDriverVersion / 256, caps.vDriverVersion % 256, caps.szPname, caps.dwFormats, caps.wChannels, caps.wReserved1 ); }
devs = waveOutGetNumDevs(); LOG(L"waveOut devices: %u", devs); for (UINT dev = 0; dev < devs; dev++) { WAVEOUTCAPS caps = {}; MMRESULT mmr = waveOutGetDevCaps(dev, &caps, sizeof(caps)); if (MMSYSERR_NOERROR != mmr) { LOG(L"waveOutGetDevCaps failed: mmr = 0x%08x", mmr); return mmr; } LOG( L"-- waveOut device #%u --\n" L"Manufacturer ID: %u\n" L"Product ID: %u\n" L"Version: %u.%u\n" L"Product Name: %s\n" L"Formats: 0x%x\n" L"Channels: %u\n" L"Reserved: %u\n" L"Support: 0x%x\n" L"%s%s%s%s%s" , dev, caps.wMid, caps.wPid, caps.vDriverVersion / 256, caps.vDriverVersion % 256, caps.szPname, caps.dwFormats, caps.wChannels, caps.wReserved1, caps.dwSupport, ((caps.dwSupport & WAVECAPS_LRVOLUME) ? L"\tWAVECAPS_LRVOLUME\n" : L""), ((caps.dwSupport & WAVECAPS_PITCH) ? L"\tWAVECAPS_PITCH\n" : L""), ((caps.dwSupport & WAVECAPS_PLAYBACKRATE) ? L"\tWAVECAPS_PLAYBACKRATE\n" : L""), ((caps.dwSupport & WAVECAPS_VOLUME) ? L"\tWAVECAPS_VOLUME\n" : L""), ((caps.dwSupport & WAVECAPS_SAMPLEACCURATE) ? L"\tWAVECAPS_SAMPLEACCURATE\n" : L"") ); }
return 0;}
On my system this outputs:
waveIn devices: 3-- waveIn device #0 --Manufacturer ID: 1Product ID: 65535Version: 0.0Product Name: Microphone (High Definition AudFormats: 0xfffffChannels: 2Reserved: 0
-- waveIn device #1 --Manufacturer ID: 1Product ID: 65535Version: 0.0Product Name: Digital Audio (S/PDIF) (High DeFormats: 0xfffffChannels: 2Reserved: 0
-- waveIn device #2 --Manufacturer ID: 1Product ID: 65535Version: 0.0Product Name: CD Audio (High Definition AudioFormats: 0xfffffChannels: 2Reserved: 0
waveOut devices: 2-- waveOut device #0 --Manufacturer ID: 1Product ID: 65535Version: 0.0Product Name: Headphones (High Definition AudFormats: 0xfffffChannels: 2Reserved: 0Support: 0x2e WAVECAPS_LRVOLUME WAVECAPS_PLAYBACKRATE WAVECAPS_VOLUME WAVECAPS_SAMPLEACCURATE
-- waveOut device #1 --Manufacturer ID: 1Product ID: 65535Version: 0.0Product Name: Digital Audio (S/PDIF) (High DeFormats: 0xfffffChannels: 2Reserved: 0Support: 0x2e WAVECAPS_LRVOLUME WAVECAPS_PLAYBACKRATE WAVECAPS_VOLUME WAVECAPS_SAMPLEACCURATE
Source and binaries attached.
The Windows Vista volume mixer shows a peak meter for the device. In Windows 7 we added a peak meter for each application.
The audio interface for both is IAudioMeterInformation; I've used this before in my post about the linearity of Windows volume APIs. This post showed how an application can get the peak meter reading for the device meter.
In Windows 7 we also added APIs to allow applications to get a list of audio sessions. I wrote up a quick app which shows how to get a list of all audio sessions, filter it down to the active ones (sessions which have an active audio client), and then get a peak meter reading.
>meters.exe{0.0.0.00000000}.{c05f2f54-7294-422a-bb0d-8d690c365b73}|#%b{917F8618-9C57-4720-9B7C-88CA45FC983B}: 0.215705Active sessions: 1
{0.0.0.00000000}.{c05f2f54-7294-422a-bb0d-8d690c365b73}|#%b{917F8618-9C57-4720-9B7C-88CA45FC983B} is the session identifier, which should be considered opaque. 0.215705 is the value of the peak meter, ranging from 0 to 1 linearly in amplitude. If you are populating a visual peak meter with this information, you will need to apply a curve.
Source and binaries attached. Pseudocode follows:
CoCreate(IMMDeviceEnumerator);IMMDeviceEnumerator::GetDefaultAudioEndpoint;IMMDevice::Activate(IAudioSessionManager2);IAudioSessionManager2::GetSessionEnumerator;for (each session) { IAudioSessionEnumerator::GetSession IAudioSessionControl::GetState if the state is anything but "active", skip to the next session QI IAudioSessionControl to IAudioSessionControl2 IAudioSessionControl2::GetSessionIdentifier QI IAudioSessionControl to IAudioMeterInformation IAudioMeterInformation::GetPeakValue Log the session identifier and the peak value}
Last time I wrote about how to query audio endpoint properties.
This time, a few words about WAVEFORMATEX structures. WAVEFORMATEX is a variable-sized structure - it can be as small as a PCMWAVEFORMAT or larger than a WAVEFORMATEXTENSIBLE.
If the wFormatTag member (the first field) is WAVE_FORMAT_PCM, then you should assume that it is a PCMWAVEFORMAT. In particular you should not touch the cbSize field since that may not be memory you own!
If wFormatTag is anything else, you can look at the cbSize to see how much bigger than a WAVEFORMATEX the structure is. For example, if the wFormatTag is WAVE_FORMAT_EXTENSIBLE, you have the right to expect that cbSize be at least sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX).
I updated the attachment to the post linked above. Here's the new output:
PKEY_AudioEngine_DeviceFormat VT_BLOB of size 40 WAVEFORMATEXTENSIBLE Format ( wFormatTag: 65534 (WAVE_FORMAT_EXTENSIBLE) nChannels: 4 nSamplesPerSec: 16000 nAvgBytesPerSec: 128000 nBlockAlign: 8 wBitsPerSample: 16 cbSize: 22 ) Samples ( wValidBitsPerSample / wSamplesPerBlock / wReserved: 16 ) dwChannelMask: 0x0 SubFormat: {00000001-0000-0010-8000-00AA00389B71} (KSDATAFORMAT_SUBTYPE_PCM)
And here's the code that produces it:
HRESULT LogWaveFormat(LPCWAVEFORMATEX pWfx, UINT nBytes) { if (NULL == pWfx) { ERR(L"LogWaveFormat called with a NULL pointer"); return E_POINTER; } if (nBytes < sizeof(PCMWAVEFORMAT)) { ERR(L"Wave format is only %u bytes, smaller even than a PCMWAVEFORMAT (%Iu bytes)", nBytes, sizeof(PCMWAVEFORMAT)); return E_INVALIDARG; } else if (nBytes == sizeof(PCMWAVEFORMAT)) { const PCMWAVEFORMAT *pPcm = reinterpret_cast<const PCMWAVEFORMAT *>(pWfx); // PCMWAVEFORMAT must have a wFormatTag of WAVE_FORMAT_PCM if (WAVE_FORMAT_PCM != pPcm->wf.wFormatTag) { ERR(L"PCMWAVEFORMAT has invalid format tag %u (expected %u)", pPcm->wf.wFormatTag, WAVE_FORMAT_PCM); return E_INVALIDARG; } LOG( L" PCMWAVEFORMAT\n" L" wf.wFormatTag: %u (%s)\n" L" wf.nChannels: %u\n" L" wf.nSamplesPerSec: %u\n" L" wf.nAvgBytesPerSec: %u\n" L" wf.nBlockAlign: %u\n" L" wBitsPerSample: %u", pPcm->wf.wFormatTag, StringFromWaveFormatTag(pPcm->wf.wFormatTag), pPcm->wf.nChannels, pPcm->wf.nSamplesPerSec, pPcm->wf.nAvgBytesPerSec, pPcm->wf.nBlockAlign, pPcm->wBitsPerSample ); return S_OK; } else if (nBytes < sizeof(WAVEFORMATEX)) { ERR( L"Wave format is %u bytes, " L"bigger than a PCMWAVEFORMAT (%Iu bytes) " L"but smaller than a WAVEFORMATEX (%Iu bytes)", nBytes, sizeof(PCMWAVEFORMAT), sizeof(WAVEFORMATEX) ); return E_INVALIDARG; } else if (nBytes != sizeof(WAVEFORMATEX) + pWfx->cbSize) { ERR( L"Wave format takes up %u bytes " L"but sizeof(WAVEFORMATEX) + pWfx->cbSize is %Iu bytes", nBytes, sizeof(WAVEFORMATEX) + pWfx->cbSize ); return E_INVALIDARG; } else { // nBytes matches cbSize switch (pWfx->wFormatTag) { case WAVE_FORMAT_EXTENSIBLE: { if (pWfx->cbSize < sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { ERR( L"cbSize for a WAVE_FORMAT_EXTENSIBLE format must be at least " L"sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX) (%Iu), " L"not %u", sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX), pWfx->cbSize ); return E_INVALIDARG; } const WAVEFORMATEXTENSIBLE *pWfxExt = reinterpret_cast<const WAVEFORMATEXTENSIBLE *>(pWfx); LOG( L" WAVEFORMATEXTENSIBLE\n" L" Format (\n" L" wFormatTag: %u (%s)\n" L" nChannels: %u\n" L" nSamplesPerSec: %u\n" L" nAvgBytesPerSec: %u\n" L" nBlockAlign: %u\n" L" wBitsPerSample: %u\n" L" cbSize: %u\n" L" )\n" L" Samples (\n" L" wValidBitsPerSample / wSamplesPerBlock / wReserved: %u\n" L" )\n" L" dwChannelMask: 0x%x\n" L" SubFormat: {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X} (%s)", pWfxExt->Format.wFormatTag, StringFromWaveFormatTag(pWfxExt->Format.wFormatTag), pWfxExt->Format.nChannels, pWfxExt->Format.nSamplesPerSec, pWfxExt->Format.nAvgBytesPerSec, pWfxExt->Format.nBlockAlign, pWfxExt->Format.wBitsPerSample, pWfxExt->Format.cbSize, pWfxExt->Samples.wValidBitsPerSample, pWfxExt->dwChannelMask, pWfxExt->SubFormat.Data1, pWfxExt->SubFormat.Data2, pWfxExt->SubFormat.Data3, pWfxExt->SubFormat.Data4[0], pWfxExt->SubFormat.Data4[1], pWfxExt->SubFormat.Data4[2], pWfxExt->SubFormat.Data4[3], pWfxExt->SubFormat.Data4[4], pWfxExt->SubFormat.Data4[5], pWfxExt->SubFormat.Data4[6], pWfxExt->SubFormat.Data4[7], StringFromSubFormat(pWfxExt->SubFormat) ); if (pWfx->cbSize > sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) { LOG(L" Trailing bytes:\n"); return LogBytes( reinterpret_cast<const BYTE *>(pWfx) + sizeof(WAVEFORMATEXTENSIBLE), pWfx->cbSize - (sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX)) ); } return S_OK; } case WAVE_FORMAT_PCM: if (pWfx->cbSize > 0) { ERR(L"cbSize for a WAVE_FORMAT_PCM format must be 0, not %u", pWfx->cbSize); return E_INVALIDARG; } // intentionally fall through default: LOG( L" WAVEFORMATEX\n" L" wFormatTag: %u (%s)\n" L" nChannels: %u\n" L" nSamplesPerSec: %u\n" L" nAvgBytesPerSec: %u\n" L" nBlockAlign: %u\n" L" wBitsPerSample: %u\n" L" cbSize: %u", pWfx->wFormatTag, StringFromWaveFormatTag(pWfx->wFormatTag), pWfx->nChannels, pWfx->nSamplesPerSec, pWfx->nAvgBytesPerSec, pWfx->nBlockAlign, pWfx->wBitsPerSample, pWfx->cbSize ); if (pWfx->cbSize > 0) { LOG(L" Trailing bytes:"); return LogBytes(reinterpret_cast<const BYTE *>(pWfx) + sizeof(WAVEFORMATEX), pWfx->cbSize); } return S_OK; } }}
Warning: trigonometry ahead.
Last time we looked at how to downmix a stereo signal to mono (M = L/2 + R/2). The resulting M signal can only be as powerful as the L and R signals if they are perfectly correlated (L = R); if the L and R signals are uncorrelated (no relationship between L and R), the resulting M signal is only half as powerful; and if the L and R signals are anticorrelated (L = -R), the resulting M signal vanishes.
This time I want to look more closely at what happens to M as {L, R} varies from correlated via uncorrelated to anticorrelated. In particular I'll take L and R to be full-scale sine waves of equal frequency and offset by a constant phase: {L, R} = {sin θ, sin(θ - φ)}. We'll see what happens to IM / IL as a function of φ.
Recall from before that the intensity of a signal s(t) over a time interval (a, b) is defined as
where the dc value is
Our downmixed signal is defined as
So our dc is zero (note that I am taking (a, b) to be a single period:)
A refresher on the angle-sum identities, which I will use without proof:
We know from before that IL = IR = sqrt(1/2) = 0.707.... Let's calculate IM as a function of φ:
Nice and simple.
Are we done? No.
When you see a fact, try to see it as intuitively as possible -- Pólya
OK, let's graph this.
That looks suspiciously like a cosine in absolute value. In particular, after messing around with a graphing calculator, it looks like:
Is this in fact a trigonometric identity? Let's see...
Much nicer and simpler. So why didn't our original derivation land us here?
Let's go back to our original graph and shift our frame of reference forward by φ/2. Instead of {L, R} = {sin θ, sin(θ - φ)} we get {L, R} = {sin(θ + φ/2), sin(θ - φ/2)}. Solving for IM now gives:
This result is much easier to digest. The sqrt(1/2) is the intensity of the pre-mixed signal; the loss of intensity due to the downmixing, then, is |cos(φ/2)|.
Disclaimer: I don't work on the Office team.
Word has a smart quotes feature where it will automagically transform
straight "double quotes," 'single quotes,' and greengrocer's apostrophes
into
curly “double quotes,” ‘single quotes,’ and greengrocer’s apostrophes
as you type. You send a Unicode Character 'APOSTROPHE' (U+0027) to Word, and Word turns it into a Unicode Character 'LEFT SINGLE QUOTATION MARK' (U+2018) or a Unicode Character 'RIGHT SINGLE QUOTATION MARK' (U+2019) as appropriate. If you type it at the beginning of a word, it's an opening-single-quote; if you type it in the middle of a word, it's an apostrophe; if you type it at the end, it's either an apostrophe or a closing-single-quote, but both are the same character, so it doesn't matter.
Right?
Usually.
The apostrophe is occasionally used at the beginning of a word, to mark elided letters. Word has trouble with this.
‘Twas brillig, and the slithy toves did gyre and gimbol in the wabe.
-- Jabberwocky
I want to give the Word folks credit here. A common use of an apostrophe at the beginning of a word is to abbreviate a year. Word gets this right (I'm using Word 2010 with default settings:)
Check it out: a ’57 Chevy!
But Word also gets it wrong when you want to single-quote a clause that begins with a number:
“They were singing ’99 bottles of beer on the wall’.”
Also, if you pluralize the date, Word gets suckered:
’10 models on sale! Check out the new ‘11s!
Little nifties, from the ‘50s, innocent and sweet;Sexy ladies from the ‘80s, who are indiscreet -- 42nd Street
For those times when Word gets it wrong, here's how to fix it.
If you want to type a word that starts with an apostrophe:
If you want to use an opening single quote with a sentence that starts with a number:
That "Undo" tip is actually a fairly powerful curative against all sorts of Word voodoo.
Last time I showed how to enumerate Media Foundation transforms. This time, DirectShow filters. Source and binaries attached.
In pseudocode:
GUID directshow_categories[] = { ... }; // static listICreateDevEnum = CoCreate(...);for (each category in directshow_categories) { display the category name and GUID IEnumMoniker = ICreateDevEnum::CreateClassEnumerator(category); for (each IMoniker that IEnumMoniker finds) { IBindCtx = CreateBindCtx(...); IPropertyBag = IMoniker::BindToStorage(IBindCtx); pull the friendly name from the IPropertyBag and display it }}
Output of the tool on my system:
>devenum.exe-- Audio Capture Sources ({33D9A762-90C8-11D0-BD43-00A0C911CE86}) -- Front Microphone (High Definiti Line In (High Definition Audio Rear Microphone (High Definitio
-- Audio Compressors ({33D9A761-90C8-11D0-BD43-00A0C911CE86}) -- WM Speech Encoder DMO WMAudio Encoder DMO IMA ADPCM PCM Microsoft ADPCM GSM 6.10 CCITT A-Law CCITT u-Law MPEG Layer-3
-- Audio Renderers ({E0F158E1-CB04-11D0-BD4E-00A0C911CE86}) -- Speakers (High Definition Audio Default DirectSound Device Default WaveOut Device DirectSound: Speakers (High Definition Audio Device)
-- Device Control Filters ({CC7BFB46-F175-11D1-A392-00E0291F3959}) --
-- DirectShow Filters ({083863F1-70DE-11D0-BD40-00A0C911CE86}) -- WMAudio Decoder DMO WMAPro over S/PDIF DMO WMSpeech Decoder DMO MP3 Decoder DMO Mpeg4s Decoder DMO WMV Screen decoder DMO WMVideo Decoder DMO Mpeg43 Decoder DMO Mpeg4 Decoder DMO DV Muxer Color Space Converter WM ASF Reader AVI Splitter VGA 16 Color Ditherer SBE2MediaTypeProfile Microsoft DTV-DVD Video Decoder AC3 Parser Filter StreamBufferSink Microsoft TV Captions Decoder MJPEG Decompressor CBVA DMO wrapper filter MPEG-I Stream Splitter SAMI (CC) Parser VBI Codec MPEG-2 Splitter Closed Captions Analysis Filter SBE2FileScan Microsoft MPEG-2 Video Encoder Internal Script Command Renderer MPEG Audio Decoder DV Splitter Video Mixing Renderer 9 Microsoft MPEG-2 Encoder ACM Wrapper Video Renderer MPEG-2 Video Stream Analyzer Line 21 Decoder Video Port Manager Video Renderer VPS Decoder WM ASF Writer VBI Surface Allocator File writer iTV Data Sink iTV Data Capture filter DVD Navigator Microsoft TV Subtitles Decoder Overlay Mixer2 AVI Draw RDP DShow Redirection Filter Microsoft MPEG-2 Audio Encoder WST Pager MPEG-2 Demultiplexer DV Video Decoder SampleGrabber Null Renderer MPEG-2 Sections and Tables Microsoft AC3 Encoder StreamBufferSource Smart Tee Overlay Mixer AVI Decompressor NetBridge AVI/WAV File Source Wave Parser MIDI Parser Multi-file Parser File stream renderer Microsoft DTV-DVD Audio Decoder StreamBufferSink2 AVI Mux Line 21 Decoder 2 File Source (Async.) File Source (URL) Media Center Extender Encryption Filter AudioRecorder WAV Dest AudioRecorder Wave Form SoundRecorder Null Renderer Infinite Pin Tee Filter Enhanced Video Renderer BDA MPEG2 Transport Information Filter MPEG Video Decoder
-- External Renderers ({CC7BFB41-F175-11D1-A392-00E0291F3959}) --
-- Midi Renderers ({4EFE2452-168A-11D1-BC76-00C04FB9453B}) -- Default MidiOut Device Microsoft GS Wavetable Synth
-- Video Capture Sources ({860BB310-5D01-11D0-BD3B-00A0C911CE86}) --
-- Video Compressors ({33D9A760-90C8-11D0-BD43-00A0C911CE86}) -- WMVideo8 Encoder DMO WMVideo9 Encoder DMO MSScreen 9 encoder DMO DV Video Encoder MJPEG Compressor Cinepak Codec by Radius Intel IYUV codec Intel IYUV codec Microsoft RLE Microsoft Video 1
-- WDM Stream Decompression Devices ({2721AE20-7E70-11D0-A5D6-28DB04C10000}) --
-- WDM Streaming Capture Devices ({65E8773D-8F56-11D0-A3B9-00A0C9223196}) -- HD Audio Microphone HD Audio Muxed capture
-- WDM Streaming Crossbar Devices ({A799A801-A46D-11D0-A18C-00A02401DCD4}) --
-- WDM Streaming Rendering Devices ({65E8773E-8F56-11D0-A3B9-00A0C9223196}) -- HD Audio Speaker
-- WDM Streaming Tee/Splitter Devices ({0A4252A0-7E70-11D0-A5D6-28DB04C10000}) -- Tee/Sink-to-Sink Converter
-- WDM Streaming TV Audio Devices ({A799A802-A46D-11D0-A18C-00A02401DCD4}) --
-- WDM Streaming TV Tuner Devices ({A799A800-A46D-11D0-A18C-00A02401DCD4}) --
-- WDM Streaming VBI Codecs ({07DAD660-22F1-11D1-A9F4-00C04FBBDE8F}) --
-- WDM Streaming Communication Transforms ({CF1DDA2C-9743-11D0-A3EE-00A0C9223196}) -- Tee/Sink-to-Sink Converter
-- WDM Streaming Data Transforms ({2EB07EA0-7E70-11D0-A5D6-28DB04C10000}) --
-- WDM Streaming Interface Transforms ({CF1DDA2D-9743-11D0-A3EE-00A0C9223196}) --
-- WDM Streaming Mixer Devices ({AD809C00-7B88-11D0-A5D6-28DB04C10000}) --
-- BDA Network Providers ({71985F4B-1CA1-11D3-9CC8-00C04F7971E0}) -- Microsoft ATSC Network Provider Microsoft DVBC Network Provider Microsoft DVBS Network Provider Microsoft DVBT Network Provider Microsoft Network Provider
-- BDA Receiver Components ({FD0A5AF4-B41D-11D2-9C95-00C04F7971E0}) --
-- BDA Rendering Filters ({71985F4A-1CA1-11D3-9CC8-00C04F7971E0}) --
-- BDA Source Filters ({71985F48-1CA1-11D3-9CC8-00C04F7971E0}) --
-- BDA Transport Information Renderers ({A2E3074F-6C3D-11D3-B653-00C04F79498E}) -- BDA MPEG2 Transport Information Filter MPEG-2 Sections and Tables
-- Video Effects (1 input) ({CC7BFB42-F175-11D1-A392-00E0291F3959}) -- Fade BasicImage Convolution Chroma Matrix Pixelate DxtAlphaSetter Class Text Label Class Scale Blur Glow ICMFilter Alpha DropShadow Wave MotionBlur Shadow Emboss Engrave Light
-- Video Effects (2 inputs) ({CC7BFB43-F175-11D1-A392-00E0291F3959}) -- CrBlinds Iris RadialWipe Fade ZigZag RandomBars CrIris CrRadialWipe Spiral Pixelate Wheel Strips CrStretch Inset CrSlide CrInset Compositor Blinds CrSpiral Wipe CheckerBoard GradientWipe DxtCompositor Class CrBarn DxtKey Class Slide DxtJpeg Class CrZigzag Barn Stretch RandomDissolve
-- EncAPI Encoders ({7D22E920-5CA9-4787-8C2B-A6779BD11781}) -- Microsoft MPEG-2 Audio Encoder Microsoft MPEG-2 Video Encoder
-- EncAPI Multiplexers ({236C9559-ADCE-4736-BF72-BAB34E392196}) -- Microsoft MPEG-2 Encoder
Three quarters are better than a dollar because they make noise! -- Lilly, Lilly's Purple Plastic Purse
Last time I talked about how to calculate a sine sweep mathematically. There's a closed-form solution which is quite elegant but, alas, useless in a practical computer implementation due to the very big numbers that are being fed to the sin(...) function.
A computer implementation will care only about the discrete samples that need to be generated. The integral in the previous post turns out to be counterproductive - we're much more interested in the infinite sequence of φi, and more particularly in their residue mod 2π.
Here are Matlab scripts that implement a sine sweep both ways:
First, the naïve mathematical solution that just calculates the exponential:
function signal = sinesweep_nostate( ... start, ... finish, ... seconds, ... sample_rate, ... amplitude, ... initial_phase, ... dc ...)% sinesweep_nostate returns a single-channel sine logarithmic sweep% DO NOT USE THIS FUNCTION IN PRODUCTION% THIS IS A PEDAGOGICAL EXERCISE ONLY% THE SIGNAL THIS PRODUCES GRADUALLY DISTORTS% INSTEAD USE sinesweep% % start: starting frequency in Hz% finish: ending frequency in Hz% seconds: duration of sweep in seconds% samplerate: samples per second% amplitude: amplitude% initial_phase: starting phase% dc: dc% echo these interesting intermediate values to the consoleR = (finish / start) ^ (1 / seconds)B = 2 * pi * start / log(R)A = initial_phase - Btime = 0 : 1 / sample_rate : seconds;phase = A + B * R .^ time;signal = amplitude * sin(phase) + dc;end % sinesweep_nostate
Now, the iterative version that adds up the little Δφs to calculate φi iteratively:
function signal = sinesweep( ... start, ... finish, ... seconds, ... sample_rate, ... amplitude, ... initial_phase, ... dc ...)% sinesweep returns a single-channel sine logarithmic sweep% start: starting frequency in Hz% finish: ending frequency in Hz% seconds: duration of sweep in seconds% samplerate: samples per second% amplitude: amplitude% initial_phase: starting phase% dc: dctime = 0 : 1 / sample_rate : seconds;frequency = exp( ... log(start) * (1 - time / seconds) + ... log(finish) * (time / seconds) ...);phase = 0 * time;phase(1) = initial_phase;for i = 2:length(phase) phase(i) = ... mod(phase(i - 1) + 2 * pi * frequency(i) / sample_rate, 2 * pi);endsignal = amplitude * sin(phase) + dc;end % sinesweep
If anything, one would expect the first to be more accurate, since it is mathematically precise, and the second is only an approximation. But let's see how the signal produced by each of them holds up.
I calculate, and plot, the same sweep both ways, with a slight dc offset to facilitate seeing the different sweeps on the same plot. In particular this is a logarithmic sweep from 20 kHz to 21 kHz, over 30 seconds, using 44100 samples per second, an amplitude of 0.2, an initial phase of π, and a dc of 0.25 for one and 0.26 for the other:
plot(... x, sinesweep(20000, 21000, 30, 44100, 0.2, pi, 0.25), 'd', ... x, sinesweep_nostate(20000, 21000, 30, 44100, 0.2, pi, 0.26), 's' ...)
(x is just 1:30*44100 - necessary to allow a single plot statement.)
Note that the approximate method is plotted in diamonds, and will be 0.01 lower on the resulting graph than the "exact" method, plotted in squares.
(This takes a while to plot because there are a heckuva lot of points...)
Ah, a nice solid mass of green and blue. I won't show it here.
OK, let's zoom in to a very early chunk of the signal - I expect these to match up closely, with only the dc offset separating the points:
Yup. Looks pretty good - give or take a pixel (quantization error in the display.)
Now let's see what happens to the signal towards the end of the 30 seconds.
Ick. Something's rotten in the state of Denmark. This distortion is so bad that it's visible - you don't even have to take an FFT to see it.
Exercise: take an FFT and look at the distortion.
Advanced Exercise: demonstrate that the distortion is, in fact, in the "exact" method and not in the iterative method... that is to say, show which clock is right.
EDIT: On second glance it looks like the second picture is just showing a horizontal shift between the two signals, which is expected. I'll need to dig deeper if I'm to prove my assertion that the iterative method produces less distortion than the "exact" method.