Quick and cheap audio editing for online courses

A family member is a college professor and her courses this fall will be held virtually. Her lectures will be recorded ahead of time and she asked me for some tips to be more productive.

Much of this will be for the tools that she is using, Microsoft Powerpoint and Techsmith Camtasia, but the general ideas work for most tools.

Use a decent microphone. You can go crazy and spend a lot of money on microphones and associated gear, but you can get very good results with a decent USB microphone.

The Blue Yeti microphone is a good choice. It has a stand and you can control the pickup pattern that it uses. The pickup pattern is important, you just want to pick up your voice and nothing else. Amazon.

The HyperX QuadCast microphone is another good choice. Designed for gamers, it has configurable pickup patterns, a built-in pop filter, and a stand. It also comes with a built-in shock mount. That will filter out any sounds that would be transmitted through your desk. Amazon.

The RØDE NT-USB is another good USB microphone that comes with a stand. Amazon. I use its big brother, the RØDE Podcaster. B&H.

You’ll probably want to use a pop filter with your microphone. Put your hand in front of your mouth and then say the letter “L”, followed by the letter “P”. Did you feel more air move when you said “P”?  That’s because the effort to say “P” is a plosive speech sound. Without a pop filter, that rush of air will get picked up by the microphone.

Depending on what comes with the microphone, you may or may not need an external pop filter. You can usually find a decent one that clips to the microphone or stand for $15-$20 dollars.

To get a consistent sound, you’ll want to record in the same place. Every room has different acoustics and it’s jarring to the audience to hear changes in the sound.

You’ll want to deaden the sound, basically remove any echos. If your room has bare walls, your voice will bounce around a bit. I have acoustic panels in my office, they help a lot. You can make your own, it’s basically linen fabric wrapped around insulation, inside a wood frame.  If you are doing a lot of recording, you may want to look into doing that as a DIY project. 

If you can hang up blankets or quilts around you, that will work just as well. And quilts hanging on the wall will look much better than acoustic panels.

The quilting wall in my wife’s home office helps dampen the sound for her Zoom calls.

Get in the habit of speaking into the microphone at the same location and angle. That will help get a consistent sound.

Also, you’ll want to record and edit your audio with a nice set of comfortable headphones. This will allow you to hear exactly what you recorded and filter out everything else that is going on.

I love Camtasia, but the audio editing tools are less evolved than the video editing tools. What I do is to record and edit the audio separately. We’ll be using Audacity here. Audacity is a free and open-source audio editing tool that is available on multiple platforms. You can get it here. Go install it now, I’ll wait.

You can record your audio directly with Audacity or you can take existing audio from a Camtasia project. Either way, you can clean up the audio in less time than it would from within Camtasia.

If you recorded the audio and video together, you can separate the audio and video tracks from within Camtasia. Once you have the clip loaded on the timeline, right-click on the clip and select “Separate Audio and Video”. You’ll now have individual audio and video tracks. 

If you go to the Share menu, you can select “Export Audio Only…”. Save the file as a .wav file. Now you can open the file in Audacity. When you open the file it may give you a warning about choosing an import method. Audacity can either work with a copy of the file or edit it directly. Either way will work.

Warning message from Audacity

Once you have the file opened in Audacity, we can reduce the background noise. Select a section of the file where you are not talking. From the Effect menu, select “Noise Reduction…”.

Selecting the Noise Reduction effect for the selected audio

Once you have the file opened in Audacity, we can reduce the background noise. If you don’t have a lot of background noise, you can skip this step. Select a section of the file where you are not talking. From the Effect menu, select “Noise Reduction…”.

A dialog will open up. Click the “Get Noise Profile” button. It will scan the selected clip and build a noise profile. Then, select the entire clip (press Ctrl-A) and select “Noise Reduction…” from the Effect menu. This time, press the “Ok” button.

The Noise Reduction effect

Now you can normalize the volume in Audacity. This will allow your narration to have the same volume for every clip. You can select Normalize from the effects menu. You set it at a maximum db level. Your peak should be at -6 db. You can go lower, like -8 db, but you once you pick that level, that’s the level you want to use for the entire video. If someone else will be mastering the audio afterward, find out what level they want you to use.

The Normalize effect

And that is the peak level, the overall audio should be in the range from -9db to -18 db. You can use the normalize filter to set the level so that the peak is at -6db. This will raise all of the levels, including pops, clicks, and other noises in the recording in between your words. That makes it easier to find and remove them.

The Hard Limit option of the Limiter effect

If your voice has a lot of dynamic range, you may find that setting the peaks to -6db doesn’t raise the rest of your voice enough. What you can do is to raise the level higher, to say -3db. Then run the hard limiter filter at -6db. That will clip the peaks to -6db and the net effect is that your voice will sounder louder.

Once you have the audio level set, you want to remove any and all sounds in between your words  Not every word, just in the pauses. Select that section so that it’s highlighted and press the Ctrl-L key combination  That will silence that section. You still want to do this after running the noise reduction filter.

To make your time more efficient in Audacity, you can assign keyboard shortcuts to the filters that you used the most. If you open up the Audacity preferences, from the Edit menu or by pressing CTRL-P, you can select “Keyboard” and edit the key bindings. I assigned the CTRL-8, CTRL-9, and CTRL-0 shortcuts to the Noise Reduction, Normalize, and Limiter filters. Those shortcuts were not being used, and they are easy to remember.

Keyboard shortcuts, use them

If you find that your voice has “click” sounds, you’ll want to remove as many of them as you can. There is a de-click effect with Audacity, but I haven’t had much luck with it. I use a program called RX 7 Essentials from Izotrope that does a nice job of removing the clicks out of my voice. It retails for $129, but they run sales from time to time. Two weeks ago, I paid $29 for it. There is 50% education discount on their site. If you are doing a lot of videos, this can save you a lot of time. If you have this tool, you may not even need to use Audacity.

RX Essentials with the De-click dialog

Once you are done cleaning up the audio, you can import it into Camtasia as a media file. Drop it on the timeline in a track above the existing audio track. That will make it easier to line it up in place. Once you have it in the right place, you can just delete the original audio track from the timeline.

If you are doing a presentation that is a series of Powerpoint slides, you’ll want a second of silence in between each slide. Basically, a half-second at the end of one slide, then another half-second at the start of the next slide. You can use the Camtasia tools to measure a 1 one-second clip, but a friend shared a quick way to this. 

Record a one second of silence audio file. Add it to your Camtasia project. At the end of the audio for a slide, add the one-second clip to the timeline. If each slide is it’s one video clip, extend the end of the clip to the halfway position of the one-second clip. Then place the next slide’s clip next to the previous slide on the timeline. If you need a copy of a one-second clip, I put one here that you can download.

If your slides are in a single clip, split the clip at the end of the first slide. Move the timeline cursor to that position and press the “s” key. That will split the clip at that point. You can then drag the of the clip to the halfway point. Make sure to hold the ALT key down when dragging the edge of the clip. That extends the last frame of the clip.

One more tip for Camtasia. Turn off the preferences setting for “Auto-normalize Loudness”. It’s hidden under the Projects tab in the Windows version of Camtasia and defaults to being on for new installations. You’ll want to disable this feature.

If you are following your own script and you have a sentence that you keeping mangling when you try to say, there are a couple of things to try. One is to keep saying it until you get it right. Another thing is to change the wording. What looks good written down may, for whatever reason, fail to flow off your tongue.

Another thing that you do is to pause during the sentence that is killing you. Say part of the sentence, pause, then continue with the rest. You can use the audio editing tools to clip out the pauses so it sounds more natural.

If you need to embed a link in your video and you just have a video file, use a QR code and let them scan the code with their phone. There are tons of free QR code generators on the Internet. I used QRCode Monkey to create the following QR code and placed into a Powerpoint slide.

Scan it with your phone’s camera, it’s just my Twitter timeline

They give you a fair amount of tweaking to the QR code format. If you do something like this, add a 5-second pause and tell people to pause the video while they scan the code with their phone.

And that’s the budget-friendly way of getting a better sound out of your narration.

Using PowerShell to set the Num Lock state

During these work from home times, on the darkest timeline, I spent a lot of my day using my work PC over an RDP connection. For some reason, every time I connected, the Num Lock status would be set to off. Which is silly and annoying. 

When you are connected to a remote machine and you press the Num Lock key on your keyboard, it toggles the Num Lock state for both the client and guest machine. Which can get confusing if you are working with apps on both machines and the Num Lock state is different between the machines. Ideally, you want the Num Lock state to be the same on both machines.

For me, the preference was a command-line option for setting Num Lock. My shell of choice on Windows is PowerShell, so I decided to write a PowerShell script to set the Num Lock Status. The Num Lock key is a toggle switch, press once to turn on, press again to turn off. The script needed to be able to check the current state to be able to set a specified state correctly.

With a little trial and error, I came up with the following script. I put it on gist to make it easier to grab and make your own:

# One parameter, to set the Num Lock state to On or Off, with
# On as the default
[ValidateSet("On", "Off")]
[String[]] $onoff='On'
# Get the current state of the Num Lock key
$CurrentState = [console]::NumberLock
# the RequestedState, based in the command line param.
# On is true, Off is false
if ($onoff -eq 'On') {
$RequestedState = $true
else {
$RequestedState = $false
# If the requested state is the current state, we declare
# victory and go home
if ($RequestedState -eq $CurrentState) {
if ($CurrentState -eq $false)
Write-Host 'Num Lock is already off'
else {
Write-Host 'Num Lock is already on'
else {
if ($CurrentState -eq $false)
Write-Host 'Num Lock is off, turning on'
else {
Write-Host 'Num lock is on, turning off'
# If the requested state is not the current state, then
# we need to do a Num Lock press
# Create a new instance of the WScript object and send
# the NumLock key press to it
(New-Object ComObject WScript.Shell).SendKeys('{NUMLOCK}')
view raw num-lock.ps1 hosted with ❤ by GitHub


I put the comments inline, it should be pretty self-explanatory with the comments. While PowerShell is supported on macOS and Linux now, this is a Windows only script. The [console] ::NumberLock expression returns the following error message:

OperationStopped: Operation is not supported on this platform.

Which is odd, [console] is a shortcut for [system.console], a class that is accessible on the macOS Powershell. If you run the following command in a PowerShell on either Windows or macOS, you’ll get a list of static properties that should be readable from a POSH script.

[system.console] | Get-Member -Static -MemberType property | Format-Table 

And the NumberLock property is listed, but just not implemented. And that’s not even the real sticking point. This script creates an instance of a WScript object and uses it’s SendKeys method to pass in a Num Lock key press. WScript is the Windows Script Host, a technology that lets scripting languages make Windows API calls. A minor sticking point, I only need this Windows. You can get a list of the special keys that SendKeys can send from here.

That’s the heavy lifting. Because I am lazy, I don’t want to type in the name of the script. So I created an alias for it.

Set-Alias nl d:\scripts\num-lock.ps1

Now I can just run “nl” or “nl On” or “nl Off” to change the Num Lock state. I added the alias to the profile so it’s always available. Now when I connect to my work PC, I run “nl” and all is well.

Colored notes in OneNote

I like using OneNote when I’m working on a project with different kinds of assets. I’m in the middle of doing a new course for Pluralsight that will be out in a couple of months. I have slides, a script, PowerPoint decks, code, media files, etc. It can get a little confusing trying to keep track of everything.

For the new course, I have been using OneNote to map out each module. The way I create the content is that I create a PowerPoint deck for each module and then write a script for the narration of the deck. I create a new OneNote file for the course, and then add a tab for each module. Inside each module, there are tabs for each section of that module. I have one tab for just for notes and links to resources.

Each tab has multiple OneNote paragraphs, basically one paragraph for each slide. To make it easy to pick out paragraphs, I wanted to give each paragraph it’s own background colors. It makes it easier to find the text that I want and I can move stuff around and easily see what text belongs in each paragraph. You would think it would be as simple as right-clicking in the paragraph and selecting the color. No, that is not an option.

You could just place a colored shape behind the paragraph. That kind of works, but it’s an annoyance if you are constantly editing the text as the shape will not resize with the text.

There is another way, and it’s a bit of a hack. You can do this for new text or for a paragraph that you already have added.

For an existing paragraph, copy the text, and cut it from the paragraph. Then, insert a 1×1 table into the paragraph. Next, paste the text into the single cell table.

Click on the table and select the Layout tab in the OneNote ribbon. In the Format section of the Layout ribbon, select the drop-down arrow for shading. Now you can pick the color that you want for the paragraph. Now you have colored paragraphs and the color matches the size of the text. And with the default borders for a table, you get a simple box drawn around the text.

For a new paragraph, insert the 1×1 table first and just start typing into the table cell. By default, OneNote will add a new table row for each hard return of the Enter key. A way around that is to press Shift-Enter twice at the end of the first line and arrow back up the first newline. As long as you leave one empty line at the bottom, pressing the Enter key will keep the text in a single row.

I can take no credit for this technique, I saw it mentioned a few times on the Internets.

Add a POSH ADB to your Windows Terminal

Windows Terminal is so close to being out of beta. It’s been my default CLI on Windows for about a year. I still don’t think in PowerShell, but I try to use PowerShell as my default shell. I just love how you can configure Terminal.

The default shell for me is PowerShell Core, aka Powershell 7.0. Out of the box, it doesn’t have ADB on the path. When I’m doing Android stuff, I want the ADB. But I don’t want it to be on the path by default. Just like Visual Studio has the “Android ADB Command Prompt” menu option, I wanted to add shell option to Terminals so I can spin up a new PowerShell, but with ADB support. This is what I ended up with:

PowerShell with ADB goodness.

The first thing I did was to create a PowerShell script that just adds the ADB tooling to the path. My first attempt was:

$NeedsAdb = $true

foreach ($p in $env:Path.Split(";"))
    if ($p -match "android-sdk\\platform")
        $NeedsAdb = $false

if ($NeedsAdb)
    write-host "Adding Android SDK Platform tools to path"
    $env:Path += ";C:\Program Files (x86)\Android\android-sdk\platform-tools"

It walks through the path and checks to see the folder with the ADB bits is already there.  If not, it gets added. That worked but seemed like a lot. I did a quick refactor and got it down to this

$NeedsAdb = $true

$env:Path.Split(";") | ForEach-Object {
    if ($_ -match "android-sdk\\platform") {
        $NeedsAdb = $false

if ($NeedsAdb) {
    write-host "Adding Android SDK Platform tools to path"
    $env:Path += ";C:\Program Files (x86)\Android\android-sdk\platform-tools"

A little cleaner, but still too much.  I was taking the path, splitting it up into an array of strings, and then testing each string.  But wait, the path is a string.  That made it simpler.  Instead of doing a string match on each folder the path, I can make one string match against the whole thing.

if ($env:Path -NotMatch "Android\\android-sdk\\platform")
    write-host "Adding Android SDK Platform tools to path"
    $env:Path += ";${env:ProgramFiles(x86)}\Android\android-sdk\platform-tools"

So I called that one add-adb.ps1 and saved it to a common folder that I put scripts in.  Next, I wanted a cosmetic tweak so that I knew which shell has the power of ADB.  I went to materialdesignicons.com and did a search on “Android”.  I found an icon named “android-debug-bridge”, which was perfect.  I downloaded the .svg version of the icon and then made a .png file out of it with PhotoShop.  I named it android-debug-bridge.png.  Then I made a smaller version to be the icon. You can grab the images and the .ps1 file from the following Gist link: https://gist.github.com/anotherlab/364e3805d9ea56b574b394127acc9aa6

Now that I had the script and the images, it’s time to add a new shell profile.  From within Windows Terminal, select “Settings” from the drop-down menu.  You can also press the CTRL+, shortcut.  This will load the settings.json file in the text editor of your choice.  I have Visual Studio Code registered as the default app for JSON files.  You can use a lesser editor, but that’s on you.

There will be an array of objects named “list”.  These objects are the different shells that can be run from within Windows Terminals.  I added the following item to the list array


        "guid": "{50caca3f-bff1-4891-b7f7-e3a05c040003}",
        "fontFace":  "Cascadia Code PL",
        "backgroundImage": "d:/grfx/android-debug-bridge.png",
        "backgroundImageStretchMode": "uniform",
        "backgroundImageOpacity": 0.15,
        "hidden": false,
        "name": "ADB PowerShell",
        "icon": "d:/grfx/adb-32.png",
        "commandline": "pwsh.exe -noe -c D:/scripts/add-adb.ps1"

Let’s go over this line by line.

guidIt wants a GUID, so just get one.  I used guidgenerator.com, but any GUID generator will do.
fontFaceI’m using the Powerline version of Cascadia.  More on that in a bit
backgroundImageGrab it from my Gist or use your own.
backgroundImageStretchMode Size the image to fit the Shell window
backgroundImageOpacity I set it to be mostly transparent
hiddenIf you want to hide this from the list of shells, just set it to True
nameCall it what you want
iconThe tab icon is optional, but you can grab it from my Gist.
commandlineThis is what gets launched. The “-c” option says to run the next parameter and the “-noe” says not to exit after running the command

And that lets me spin up a new PowerShell with ADB on the path.  Mixing PowerShell with ADB makes it easier to do ADB commands that would normally be clunky.  For example, I want to test some Android code that would access the photo gallery.  When you new up a new Android emulator, there are no images.   ADB lets copy files to the emulator’s filesystem, but it doesn’t do wild cards.

You may have notice the “/” slash being used instead of “\” for file paths. Windows Terminal lets you use the “/” as the directory separator and this avoids having to use “\\” to get a single “\” in.

I have a folder with a bunch of images that I wanted to copy to an Android Emulator image.  I then run the following command from PowerShell:

Get-ChildItem .\*  -Include *.jpg,*.png | Foreach-Object {adb push $_.Name /sdcard/Pictures}

Get-ChildItem gets a directory listing and I use the -Include parameter to only include the files that have the .jpg and .png extension. If I didn’t need to filter the files list, I could the aliases for Get-ChildItem of gci or ls. I then pipe the results into Foreach-Object. This will execute everything in the {} block for each item. $_.Name is the name of the file and that gets passed to adb push to copy that file to /sdcard/Pictures in the emulator. There’s a bit of typing, but it does save time when trying to copy a set of files over to Android.

About that “Cascadia Code PL” font face.  I’m running a theming engine inside PowerShell called “Oh-my-posh”.  I’ll do a longer post on it in the future, but the short story is that it makes the PowerShell prompt contain the current git status for the current folder.  Read about it and get it here.  On the Mac, I use Oh-my-zsh to get a souped-up zsh shell.  Scott Hanselman did a good write up of Oh-my-posh here.

Oh-my-posh uses Powerline Glyphs (originally defined here) as part of the status display.  So you’ll need a font that includes the Powerline Glyphs.  Microsoft’s Cascadia Code font has a version with Powerline and you can get it here.  Here’s what that looked like when I was adding the files to the Gist

You can see the color and text information change as I used git to add the icon to the Gist. When working with git, it’s very handy to easily see which branch you are working with and the current status of that branch.

Some quick improvements for the home video conferencing experience

After a few months of full time working from home, there are a couple of things that I have done to improve the video conferencing experience. Well, for me, anyway.

Having a decent webcam will be a big improvement in the quality of your video. And it can give you some added flexibility with positioning over the webcams that are built into laptops.  Even though they are hard to get now, they are well worth the money.

For a long time, I used a Microsoft LifeCam.  It was more or less fine, but every time I sat back in my chair, it would hunt for focus.  That’s an unnecessary distraction.  I wrote some code to deal with that.  And that became a project that still lives on.  But I no longer use that webcam.

I bought a Logitech (sorry, I refuse to say “logi”) c922 webcam.  It had the resolution that I wanted and a tripod mount on the base. It tilts up and down but oddly doesn’t adjust from side to side.

I’m pretty sure it came with a tripod, but at the moment I’m not exactly sure where that went.  I have it mounted on an old JOBY Gorillapod that I had in my camera bag.  It’s an older one, without the adjustable head. 

With the c922 on the tripod, I can move the webcam around as it suits my mood.  I like having the camera at more or less eye level.  With my PC, when it was mounted on top of one of the monitors, so it was always looking down on me.  With the tripod, I can place it in between two of the monitors and at eye level.

Webcam deployed

Sometimes I want it at a slight angle from my face.  With the webcam free to move around, that makes it easy to adjust.  I’ve been in meetings where we spend most of the time going over documents, and we don’t need the “eye to eye” viewpoint.

If you are doing a family Zoom meeting, it’s handy to connect a laptop to a TV and then be able to move the webcam so that it’s in front of the TV.  And yes, sometimes I just aim the webcam at the dogs.

Every day is now take your work to dogs day

At this point, replacing the background of your webcam is getting a bit tired.  But early on in WFH mode, it was fun to change it up.  At work, we use Teams, and back in March, it didn’t support virtual backgrounds.  So I bought a license for XSplit VCam.  VCam lets you use static images, videos, and even YouTube links for the background.  And it will let blur any of that with fine control over the level of the blur.

One of my teammates had bought a house last year from another co-worker.  Thanks to that co-worker, I was able to grab pictures from the real estate listings for the house.  For our first standup meeting after WFH, it looked like we in the same house.  It’s a fun trick but grows tiresome after a few times.  Also, do not make your webcam background a live feed of puppies playing.  Unless bringing a meeting a flying stop is the desired outcome, then, by all means, go ahead.

Puppies, the meeting killer

The meeting apps that have the virtual background (and the 3rd party apps) can usually do the replacement without a green screen.  But if you have an actual green screen, you can get better results.  When I was given the WFH order, that night I bought the parts to make one.  It’s basically a 2×4, some PVC pipes, and cheap green table clothes.  I think I spent $15 at Home Depot and a dollar store.  I followed the instructions from this video:

It was cheap and easy.  And I can tear it down in seconds.  If you have kids at home that are bored out of their minds, let them use a green screen and make their own videos.

Another thing I did was play around with the lighting.  By genetics and behavior, I’m pretty pale.  If the lighting is not balanced, I look like Caspar.  And not in a good way.  For Christmas, I received a Circadian Optics Lattis Light Therapy Lamp as a gift.  It’s very bright and full spectrum.  For the longest time, I couldn’t figure out what to do with it.

Now, when I’m in a video meeting, I turn the Lattis light on, but I have it facing the wall by my desk.  By bouncing it, I’m getting a nice gentle fill, instead of the light of a thousand suns.  I have a window directly behind me and having a light source off to my side keeps me properly lit.  The Lattis has three settings, Low, Medium, and I’m Going Blind.  I find the lowest setting works the best.

At the lowest setting

Then there’s the audio.  If you are going to be in video meetings, get a decent set of headphones with a noise-canceling microphone.  If your environment has other people in it (like children, spouses, angry farm animals), the other people in the meeting will appreciate it. 

I have a Macbook and a Windows desktop and on the Mac, I use my Jabra earbuds.  They fit well and the microphone is good enough.  On the Windows box, I use a set of cheap headphones, the Microsoft Lifechat LX-3000.  They get the job done and they work with everything.

Work From Home is the new normal for me. And based on current conditions, I don’t expect that will change for a few months, probably longer. So it’s important to me to do what I can to improve the video conferencing setup.

In other news…

Next week, I’m restarting the TVUG user group after a few months of hiatus. It’s on Tuesday, the 12th. You can join in via this handy link via Teams. I’m going to be the presenter, so it’s important that the audio and the visual work well.

And don’t even get me started on chairs…

Bag man

I just finished listening to Rachel Maddow’s excellent 7-part podcast, Bag Man. It’s an oral documentary of the events and actions that led to the resignation and conviction of Vice President Spiro Agnew. You can listen to episode one here:

Spiro Agnew, 39th Vice President

As a kid, I vaguely remembered when Agnew resigned. From that event, my strongest recollection was learning what the legal term Nolo Contendere meant (pleading no contest). At the time, the news reports indicated that he was resigning because of tax evasion. And then he went away and that was it for Agnew. Granted, there was a bigger political thing going on at the time. so it’s easy to see how he was able to fade away.

There was a lot more to that than just tax evasions. But hey, spoilers. This happened far enough in the past that most people don’t know about this or have forgotten about it. Maddow went deep on this and you’ll get hooked on it. Then get the book and go deeper down a rabbit hole from five decades ago.

Why I like working on Open Source (back to FocusUF)

About a month ago, I blogged about an update to a webcam hack that I did called FocusUF.  There wasn’t much to the code and I put it all up on GitHub.  Someone came along and submitted a pull request that added some cool functionality.  

My version was hardcoded to a single webcam.  Because that’s all I need it for.  At the time, I was using a Microsoft LifeCam HD-5000.  Someone else created an issue on my GitHub repo asking if I could add support for the HD-6000, which apparently suffers from the same annoyances with focus.

I was going to add a command-line parameter to FocusUF to allow you to specify all or part of the webcam name, but someone else beat me to it.  Cain Hopwood updated my code to add that and a bunch of other useful command-line switches.  And somehow, I had missed his PR when it was submitted a month ago.

So I tossed my changes out the window and accept the pull request.  It was pretty good.  After merging the changes, I added a couple of things.  Cain added code to list all of the webcams.  That would fail if you have any webcams that didn’t support the IAMCameraControl interface from the DirectShowLib.  If you have software that runs as a virtual webcam, it probably doesn’t support IAMCameraControl.   Now when you run it without any parameters, you get the following usage help:

Get the source at https://github.com/anotherlab/FocusUF

Usage: FocusUF [--help | -?] [--list-cameras | -l]
[--focus-mode-manual | -fm] [--focus-mode-auto | -fa]
[--set-focus <value> | -f <value>]
[--exposure-mode-manual | -em] [--exposure-mode-auto | -ea]
[--set-exposure <value> | -e <value>]
[--camera-name <name> | -n <name>]


Now when you ask it to list the cameras, you get the following output:

❯ .\FocusUF.exe -l
Get the source at https://github.com/anotherlab/FocusUF
Camera: c922 Pro Stream Webcam
    Focus Capability: Auto, Manual
    Focus Range: 0 - 250
    Focus Setting: Auto, 0
    Exposure Capability: Auto, Manual
    Exposure Range: -11 - -2
    Exposure Setting: Auto, -5
Camera: XSplit VCam
    Camera does not expose settings through DirectShowLib

I also made the search by name case insensitive.  That was low hanging fruit.  I also updated the compiled version of the code at focusuf.zip.  While I don’t support this as a product, it’s useful for people who don’t have the compiler installed.  And I updated the readme file to document the new changes.

And to go off on a tangent, I’ve been using a tool (Windows only) named Markdown Monster to edit the readme files.  Markdown Monster is written and supported by Rick Strahl.  You can try it for free and then buy a cheap license for it.  Working in Markdown is fairly easy, but it has its own syntax to learn.  Markdown Monster gives you a nice editor with full preview and it makes updating the readme file one less thing to think about.

And that’s one of the great things about open-source software.  Other people can jump in and contribute.  I wrote a little tool to fix something that was bugging me.  It sparked joy with someone and he added some additional joy to fix something that he needed.

Return to FocusUF

A while back, I blogged about a command line hack to set the focus for a web cam.  I was using a Microsoft LifeCam HD-5000 and it has the annoying habit of refocusing if you move around in your seat.

It’s two years later and I have had a request for a compiled version of the FocusUF.  It wasn’t much more than a paragraph of code and I put it up on GitHub for anyone to use.  That’s all I had wanted to do, just the share the code and move on.

It’s not a product, it’s a block of code.  I had resisted putting a compiled version up because it’s not something I wanted to support.  But if you are not a .NET developer, it’s big ask to take that code and make a tiny command line tool.  I get it.  I decided to add a compiled version of the code to the GitHub repository.  For use as is, no support.

I went back to the project and fired it up.  It’s been two years and management has made some changes.  I’m using Visual Studio 2019 and I no longer use that web cam.  I upgraded to a Logitech c922 and no longer use the LifeCam.

The good news is the code compiled with no changes from VS 2019.  Which is what I expected.  When I ran it, tt crashed and burned with an error.  Which I did not expect.  It literally dies on the second line of code.  The first two lines of code look like this:

// Get the list of connected video cameras
DsDevice[] devs = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);

// Filter that list down to the one with hyper-aggressive focus
var dev = devs
  .Where(d => d.Name.Equals("Microsoft® LifeCam HD-5000"))

I broke the second line into multiple lines to make this a little easier to follow.  I was getting a null exception on the highlighted line, specifically on d.Name.

For some reason, one of the items in the devs array has null for a name and that broke my code.  It was never a problem before, because the LifeCam was first in the list returned by GetDevicesOfCat.  Since I no longer had that web cam plugged in, the LINQ query was going through the entire list.  And then erroring out trying to call Equals() on a null value. [SPOILER ALERT! That assumption was completely wrong.]

I was curious to see what was null. When I want to quickly visually data structures, I like to use LINQPad. So I copied and pasted those two lines into LINQPad and pulled in the nuget package for DirectShowLib.  I then used the Dump() extension method to look at what was being returned for GetDevicesOfCat.

@device:pnp:\?\usb#vid_046d&pid_085c&mi_00#7&18173bf5&0&0000#{65e8773d-8f56-11d0-a3b9-00a0c9223196}\globalc922 Pro Stream Webcam

And there’s the null value.  That was odd and we’ll get back that in minute.  In the meantime, let’s fix that code.  Instead of trying to be clever and use the Equals() function, I changed the code to just use the equals operator and let it handle the null check.  That one line becomes:

var dev = devs
  .Where(d => d.Name == "Microsoft® LifeCam HD-5000")

I compiled the code and ran it.  And it did nothing.  Which is what I expected since I no longer had the LifeCam plugged in.  More importantly, it didn’t throw an error.

I went back and added some Console.Writeln() statements so the app would at least say what it was doing or not doing.  I built it again, zipped up the .dll & .exe files and added the zip file to a new win32 folder in the GitHub repository.  So if you don’t have access to Visual Studio, you can grab just that zip file and get the FocusUF.exe app.  But I’m not supporting that app.  If it doesn’t work for you, just grab the code and compile it.

With the repo updated, it’s time to see what is our little null friend. If you look at the DevicePath, it has a wierd name buried in it. What is psycamera? If you google it, you find that a lot of people mispell “spy camera”. So that was no help. Names that are null set off my spidey senses. I wasn’t going to let that one just sit there with a look at it.

Going with the path of least resistance, I fired up Device Manager to see if something looked unfamilair or out of place. Sure enough, under “Cameras”, there was a new item named “Personify Virtual Camera Universal”. The Personify name was vaguely familiar [SPOILER ALERT] and I had a pretty good idea of what was going on, but I decided to double click on it and drill into the details.

Literally into the details. I selected the Details tab and select Device Instance Path from the drop-down list. That gave us this:

And there is the mystery psycamera. Going back to the LINQPad dump, the third item that the list returned by GetDevicesOfCat was named ChromaCam. ChromaCam is a virtual webcam. It lets you replace your background with an image. And ChromaCam is made by a company named Personify. I’m not sure exactly what they are doing with the psycamera device, but it’s fairly innocuous. When I wrote the code two years ago, I did not have ChromaCam, so my code back then only had to deal with a single item in the devs list.

I did see if the code would compile with Visual Studio code and I think it would, but not out of the box. It looks like it would be more trouble than its worth. But I do recommend ChromaCam, it’s fun to play with.

Getting a new dev machine set up, macOS Style

It’s that time of the decade when I get a new Macbook Pro. I use a Macbook to compile iOS apps with Xamarin which makes it required equipment. Even though my current one was a late 2014 model, it was still fast enough to do what I needed to do. It’s a work laptop and was out of warranty, so I was due for a new one. The 2014 one will go to another developer.

The last time I did this, I did a blog post on what I installed. This will version will be mostly the same, plus adding the cool new things that have come down the pike in the last 4 years.

First thing to do is to enable Apple’s full disk encryption. If someone steals this thing, they can’t access the files. They can get my body, but not my soul.

This is my work laptop. Which means the usually Corporate IT requirements. Which includes a VPN so that I can connect back to the mothership when I’m remote. Plus the corporate AV solution de jour.

I had tons of files to move over. I was pretty good about keeping the files under the user folder. Between my old MacBook and this one, I used AirDrop. I also copied a fair amount of files from the old Macbook to my home server and then from the home server to the MacBook.

I took care in copying over the .ssh folder. Which in retrospect was a waste of time, It’s easier just to regenerate the public keys.

This is a one of those command tools that makes it easier to get other command line tools (git, node, iterm, etc). Here’s a good guide for how to install Homebrew.

Fira Code
If you spend half of your day slinging code around, treat yourself to a font that is designed for coding and has ligature support. Fira Code is a nice, easy on the eyes font and has the ligature support that your eyes have been craving.  Using ligatures with coding is a personal preference and there are some good arguments against using them.  I would suggest turning off ligature support when presenting your code or posting code listings.

While MacOS comes with fully capable terminal app, there are ones out there that provide a more productive workspace. One of them is Iterm2.  Better copy/paste, better tabs, better autocomplete.  Just get it from here.

After installing iTerm2, the next thing is to install Zsh with Oh My Zsh. Zsh is an *nix shell built on, but greatly improved over Bash, the standard MacOS shell. Oh My Zsh is a an open source kit for managing Zsh. I followed this guide for installing Zsh and Oh My Zsh. And I’m learning how to use it from this cheatsheet.

If you are doing screen captures, you don’t always want the captures done at Retina resolution. I usually use a second monitor at 1920×1080 (1280×720 if recording for Pluralsight), but if you only have the MacBook, you can use 3rd party apps to force the resolution down. QuickRes is a popular one. I haven’t had the need to use of of these utilities, so this is more of a way of stashing that information.

Even though I do my coding with the .NET stack using Xamarin, I still need to have Xcode installed.  Apple makes the Xcode compilers part of the tool chain.  Plus that’s the only way you get the iOS Simulator.

The bane of any Apple developer. I have a bunch of developer certs to move over. I didn’t use any sane way of moving them. I just let Xcode pull them down to the new machine. Afterwards, I discovered Fastlane.

Fastlane is an open source project designed to manage Android and iOS deployment and it has command line tools and strategies for managing the Unholy Hell that is Apple codesigning. I think I’m going to redo how we handle certificates and provisioning profiles for the next project and use Fastlane to manage them.

Visual Studio 2019
As a Xamarin developer, this is where I spend a great of deal time in. When installing, make sure to add Xamarin Workbooks. Get it here.

After installing VS, I used to have to update ~/.android/advancedFeatures.ini to include the line
HVF = on
This sets Google’s Android Emulator to use Apple’s Hypervisor-Framework to speed up the performance of an x86 emulator image. I used to use Intel’s HAXM, but we don’t need that anymore. The Google Android Emulator can now use the native hypervisor on MacOS and Windows. Taking HAXM out means one less thing to worry about breaking when you update the OS. With the current install of VS 2019, this is set for you.

Visual Studio Code
This has replaced every other text editor for me on both Windows and the Mac. I use it edit MarkDown files, write C for embedded hardware, quickly hack .csproj files, and pretty much any file that starts with “.”. Get it here.

If you want to run VS Code from the command line by just typing code, do the following:
Open the Command Palette (⇧⌘P) and type ‘shell command’ to find the Shell Command: Install ‘code’ command in PATH command.

Remember when we used to spin VMs to run specialized apps? I still do run Windows on my Mac, but for everything else we have Docker containers. It’s 2019 and the ability to run SQL Server on a Mac in a Docker container is old news. So you’ll probably want Docker Desktop for the Mac.

Pluralsight Offline Player
I’ve been a big fan of Pluralsight for a number of years. And as of this year, I’m also a Pluralsight author. If you get the Offline Player App, you can download courses and watch them without an Internet connection. Like on a plane.

When testing Android code, an actual device works much better than an emulator. Vysor provides a remote desktop to the Android device, which is handy for using the keyboard and doing presentations. Vysor uses ADB to make the connection, but if you doing Android development work, the odds are high that ADB has already been installed. There is a free version, but get the paid Pro license. You get more features and it keeps the product funded.

I share files with multiple providers and on multiple machines.  I use OneDrive a lot.  I have a personal account of about 20 GB and an Office 365b account for work.  I used to be a big fan of Dropbox, but they changed their policies and it costs more to use an account on multiple computers.  So I’m phasing out my usage of DropBox.

Microsoft Edge
Who knew that Microsoft would do a better Chrome than Google? It behaves a lot like Chrome, but it feels a little snappier. Competition is a good thing. Get it here.

Google Chrome
While the Chromium based Edge browser is my day to day browser, I still use Chrome. It has better synching of bookmarks and easy access to Google Services. You know where to find it.

Adobe Creative Cloud
Photoshop and Illustrator are still the gold standard for working with bitmap and vector images. I also use Premiere and After Effects for inhouse video projects. If you are creating animations with Lottie, you are going to need After Effects.

PaintCode is one of those really cool developer apps that only exist for the Mac. This app lets you take and edit vector images (.ai, .svg, .pdf) and convert them to resources that you can use in your apps. It can take an image and convert to an object in Swift, Objective-C, C#, and Java. It can also export Android Vector Drawables and SVG files.  My typical usage for PaintCode is to take a source image from Adobe Illustrator in .ai format and use it to render Android Vector images along with .png (with the @2 and @3 variants) for iOS.

A really cool feature is if you are creating an object in code, you can assign properties to parts of the images. You can move, rotate, or scale them. Change their colors, animate them, change the visibility. Very handy when you have an object that change appearance based on the input from the user or the data.

This is probably the best screen capture tool that you can use. I use it on both Windows and Mac and I just love it. From the good people at TechSmith.

Also from Techsmith comes Camtasia, a video editing app that is great from online training courses. It’s what I use for making Pluralsight courses.

Office 365
The Office apps on the Mac have more or less parity with the Windows version. It’s what we use at work, so I have most of the Office experience. In additional to the standard Office apps, I add Skype for Business and Teams. Our team lives inside MS Teams and it’s pretty much the same experience on both platforms.

I’ve installed the Slack desktop app as an experiment. I have been using the web page, but when you belong to a bunch of Slack sites, it starts getting cumbersome to manage.

A handy tool for checking web service calls. Design and test your web API calls with one tool.  Get it here.

This video player will play just about anything. Video files, DVDs, streaming protocols, etc.

Google Earth Pro
Vey handy when working with KML files and just fun to play with. You can do more with the desktop edition of Google Earth than is available with the online versions.

While Adobe CC has a good audio editor with Audition, most of the time when I need to edit an audio file, Audacity is just what I need. It’s free and open source and it does pretty much what most of us need,. I should learn Audition though.

Parallels Desktop
When I need to run Windows on my Mac, I use Parallels. I used to use VMWare Fusion, but it was just a pain in the ass. Dragging a window from a Retina screen to a FHD didn’t handle the font scaling correctly. And it was slow.

Moving my Windows 10 VM from my old Mac to the new one was trivial. I copied the VM as a file from one machine to the other. I then installed Parallels on the new machine and it was able to open the VM without any complaints. When I enter in the activation code, it prompted me to deactivate the license on the old PC. I hate having to deal with licenses, but this was tolerable.

This should have been baked into the OS. If you want window snapping features or want to customize the Touch Bar, then get BetterTouchTool.

Disk Inventory X
Sometimes you run out of disk space. This will show you where it went

Windows only apps that I would to see on the Mac

Multilingual App Toolkit
This is a Windows only tool from Microsoft. It provides a workflow for managing language resource files and can perform machine translation through Cognitive Services. It integrates into Visual Studio, but only Windows.

Markdown Monster
This is a neat editor for editing Markdown files. While VS Code has pretty decent support for Markdown, Markdown Monster is better.

I have had days where this is the only development tool that I have touched. When I’m testing some new .NET code or tweaking calls to a web service, LINQPad is the tool that I tend to grab first. And I really want a Mac version.


At my desk, I use both Windows and Mac machines. I often go back and forth. I used to have identical keyboards with separate mice. This takes a fair amount of desk space. For the last 100 years, my keyboard of choice has been the Microsoft Natural Keyboard 4000. If I’m lucky, I get a year out of one.

After I fried the last one, I decided to switch gears a bit. I got the Logitech Craft keyboard and MX Vertical Mouse. The MX Vertical supports Logitech’s Flow feature. When paired to two or three computers, you can treat the desktops as single expanded desktop. When I move the mouse off the right edge of my Windows desktop, the cursor is on the left edge of the Mac desktop. And the keyboard switches at the same time. You can also copy and paste between the computers. It’s a neat trick and probably works as expected 98% of the time.

I’ve been using the MS Natural keyboards since they came out and I’m still getting used to the regular layout. The vertical mouse helps my wrist more than then keyboard and having just one keyboard on my desk is worth the compromise. They are wireless and use USB-C, which made me like them before opening the box.

For years, I’ve been asking for every port that wasn’t USB-C to just go away. For better or worse, I got my wish with this Macbook Pro. It has 4 USB-C/Thunderbolt 3 ports, and oddly enough given what Apple did to the iPhone, a headphone jack.

My old MacBook Pro has this wonderfully insane dock from Henge Docks. You place the MacBook down and two arms would automagically connect to each side, replicating all of the ports to the back. Except some how it gained a full sized Display Port connector and Ethernet port. It was crazy and fun, but tied to the port configuration of the models that it supported. So they stopped making it.

I now have one of their new models, the Stone Pro. It sits underneath the Macbook and connects with a USB C/Thunderbolt 3 cable. When I get to work, I just connect the one cable and my external monitor and iOS devices are connected. And it has it’s own dedicated power supply. Which means I get to leave the Apple brick in my backpack.

I did get a smaller dock that connects to the side of the MacBook Pro, using two of the USB C connectors. It replicates the ports, plus adds a HDMI connector, USB A ports, and SD/Micro SD card slots. All of which is useful when I go somewhere and want to share my screen.

I do want to note that as much as I love having a chunky USB C charging brick, I already miss the Mag Safe 2 connector. There are 3rd party magnetic USB C connectors, but I have yet to see one that would fully support the power and data functionality. There is something common sense about a power cable that wont drag your laptop off the table when someone trips over the cord.

I get that it’s trickier to do data connections with a magnetic connector. A momentary disconnect of the power lines will have little to no effect. Dropping the data lines is different matter altogether. But Apple, find a way to make it work.

In the 4 years since the last Mac upgrade, it has become a lot easier to work all day on the Mac. All of the MS Office apps that I use are there and have more or less parity with the Windows versions. The developments tools are on both. Still better on Windows, but that gap is narrowing. The Mac keyboard still drives me crazy, but since I use external keyboards most of the time, it’s just something for me to complain about.

All product logos in this post are property of their respective owners.

When your Apple device refuses to be trusted

Back in July, I received a new Macbook Pro.  A lovely little device, but I had this one problem.  It wasn’t showing up as a trusted device under my iCloud account. 

When you log into a site or a service that requires Apple’s 2 factor authentication, you can use a Trusted Device to generate a 6 digit authentication code.  Most people use their iPhone, but I don’t have an iPhone.  Plenty of other Apple devices, just not the phone.  And 2 factor authentication works on my iPad, my old Macbook, and my Mac Mini.  Just not on the new Macbook. 

The 2 Factor Auth prompt

When I’m travelling, the only Apple device that I carry is the Macbook.  When I log into a service that needs the Apple auth, I want to be able to use my Macbook to provide that code.  That’s a pretty reasonable request.

This is what you should get

This has been frustrating me for a good month or so.  There is no switch or setting to enable.  Once you enable your iCloud account on an Apple device made in the last few years, that device is now a trusted device. That’s all you are supposed to have to do.

Except for my new Macbook.  It would not display the dialog that would prompt for the authentication code.  I tried Apple Support via email, but that proved to be fruitless.  I don’t think that they fully understood the problem.  I tried again today with Apple Support via phone.  It took the better part of an hour, but we finally resolved the problem.

Basically everything was setup correctly and should have worked.  But it didn’t.  With anything computer related, sometimes the best solution is to nuke the problem from a Low Earth Orbit.

It’s the only way to be sure

So we removed the iCloud account, rebooted, and added it back again.  That resolved the problem.  The Apple Support rep thinks that the iCloud auth token on the Macbook was corrupt. I have no idea how or why that happened, but that would explain what caused the problem.