Single Stage, Single Channel Phono Preamp With Power Supply Schematic

As I explained in the How Hard Could It Be? video, the first objective in getting sound out of a record player is amplifying the phono-level signal from the tonearm (about 5mV) up to line-level (1V). This pre-amplifier stage uses a low-noise operational amplifier to boost the signal to the appropriate level. For Project Califone, I’m building the preamp stage using a Texas Instruments NE5532 OpAmp chip. Of course, I was having a little bit of trouble getting the device to work because I neglected to realize that I needed to apply both a positive and a negative voltage to the chip in order for it to function.

After realizing my mistake, I sourced a 10:1 AC-AC transformer that I could use for prototyping purposes. From the wall, I can get down to a manageable 12VAC and with a simple rectifying circuit, split that into +/-12VDC. I will have to adjust the power supply circuit to account for the 30VAC output from the transformer already installed in the phonograph, but that is a problem for another day!

Single Stage Single Channel Phono Preamp With Power Supply

At this point, I have a minimum-viable amplifier circuit for a single audio channel. Note in this schematic that there is no resistance on the input signal, so there is effectively no gain control at this point. The signal is horrendously over-driven–and when piped through the main amplifier becomes so over-modulated that even Luigi Russolo would shiver–but it works! From here, it’s a matter of adding some resistors to control the gain before feeding the output to a single-knob tone control, the second pre-amp stage, then the main amplifier.

Cleaning a Focus Electronics FK-2001 Keyboard

New keyboard, who dis?

I’ve been using the Focus FK-2001 for about a week now, and I’m enjoying it. Coming from my Matias Tactile Pro, it’s a pretty easy transition (both using Alps switches and all). I do really enjoy the Tactile Pro, but I wanted something with Windows keys.

I also wanted something with a vintage style, but I didn’t like the prices for a Model M (most Model M keyboards with Windows keys are rubber dome switches anyway, and not the superbly clicky bluckling spring switches that the early Model M units employ). Anyway, I now have me a genuine vintage clicky keyboard that is a treat to type on.

Unfortunately, it’s rather…dirty. Time for a deep clean!

Opening up the case, we find the keyboard driver chip. Unfortunately, I haven’t been able to locate any information on this Intel microcontroller. It’s really just an object of curiosity right now, though.

Ran the keycaps through the ultrasonic cleaner for about 30 minutes and lubricated the switches before putting everything back together. These are all the keys with wire stabilizers reinstalled.

Gave the case a good wash with soap and water, too. Of course, I forgot to put the stabilized keys back together first, so I had to take it apart again 🙄

Now it’s completed, and I only messed up 1 key putting it back together!

All clicky, no sticky!

How To Run Old Windows Games on Windows 11

As much as I love to dig out one of my vintage laptops to get the full nostalgic retro gaming experience, sometimes it just isn’t very practical to fire up Windows 95 for a quick round of JezzBall. Unfortunately, the newer versions of Windows built on 32 and 64-bit architectures won’t run these old software relics. However, unlike Apple, Microsoft actually values backwards-compatibility. (Of course, this is mostly by necessity considering how many enterprises are running legacy software as well as due to the support of independent developers regularly bending the OS to their will, instead of the other way around.)

Windows Entertainment PackVirtue signalling aside, as part of my recent two-foot leap back into the daily-driver Windows world, I wanted to revisit one of my favorite casual diversions of the 16-bit era: Microsoft Entertainment Pack.

The only problem, of course, is that Entertainment Pack is a 16-bit application and Windows 11 won’t run 16-bit applications out of the box. Enter otvdm (forked from winevdm). Based on Wine, otvdm is a compatibility layer that adds the ability to run 16-bit Windows binaries in 64-bit exclusive versions of Windows much like the new Windows subsystems for Linux and Android. (At this point, Windows is almost a Swiss Army knife of computing, taking everything I’ve enjoyed from the Linux world without having to spend a few hours either setting up new hardware or reconfiguring everything after an update.)

How To Run 16-bit Windows Applications In 64-bit Windows

To use otvdm, download the latest release from GitHub, then unzip to the directory of your choice. From here, you can simply use otvdm as a portable installation by dragging and dropping your 16-bit application onto the otvdm.exe binary, and you’re all set!

If, like me, you prefer to have a more seamless integration into Windows, you can install otvdm with one of the included installer shortcuts. If you prefer to not show the console window while your application runs, use the “install (no console)” shortcut. At this point, 16-bit Windows applications (and their installers, for that matter) will run just like any other Windows application! Now, I’ll never get any work done ever again.

JezzBall
JezzBall on Windows 11!

How To Install Windows Applications To Removable Media

Not enough stickersI picked up one of those super-cheap ~$200 Windows 10 netbooks from Best Buy a while back because I wanted something inexpensive to keep at the shop for incidental tasks like programming microcontrollers or burning SD cards for Raspberry Pi. Unfortunately, someone at Microsoft boasted that Windows 10 could be installed on a 32GB storage drive, so manufacturers like Asus put exactly 32GB in their discount netbooks leaving very little space (after updates, usually less than 5GB) to install applications.

Fortunately, Windows 10 comes out of the box with the ability to change the default storage locations for the library folders and installation location for apps installed via the Windows Store. However, I use a lot of applications that aren’t available in the Store and I also require a fair bit of space for screen capture videos when I’m walking through a project, so I’m going to need some extra storage space. At least the little Asus that I selected has a MicroSD card slot so I can just grab a 128GB unit and leave it inserted. Windows treats it like any other removable media, but be warned: the MicroSD read/write speed isn’t anything you’re going to write home about! Applications are going to load more slowly, but in most cases will run just fine from RAM. (Writing that previous sentence gave me weird flashbacks of the 8- and 16-bit eras when we often ran applications directly from a floppy and experienced the associated slowdowns.)

Windows 10 Storage Options
Access Windows storage options by using the search function.

Install Windows Applications To SD Card

In most cases, Windows application installers will offer the option to select the install folder. For these, I just have the folder structure of the C: drive root copied to my MicroSD card, notably the Program Files and Program Files (x86) folders, so I just change the drive letter and everything installs like normal. However, many newer applications take advantage of the Windows User/AppData folder to store local data. One notorious example is Fusion360, which installs to the AppData folder and offers no option to do otherwise! For these exceptions, we’ll need to create a symbolic link from the C: version of the AppData folder to the D: drive location.

Use Symbolic Link To Redirect Folders

First off, using a symbolic link to redirect system folders to another location is generally bad practice because it can expose the machine to symlink attacks, but considering we’ve been backed into a corner by arrogant developers and clueless manufacturers, we’re going to need to pull this trick out of the bag. I wouldn’t use this kind of workaround on any mission critical systems, but it should be just fine for this little auxiliary machine. (Technically, Windows shortcuts are symbolic links, so we’re not doing anything too weird. We’re just forcing Windows to use a different storage location for something it prefers to have on the main storage device). The first step is to create a directory on the D: drive that will hold our AppData (since it’s a hidden folder and I’m the only user, I’ll just put it in D:\AppData). From here, just copy the contents of the AppData directory over to the new location and delete (yes, I said delete) the original.

Create Symbolic Links With Windows Command Line

Windows comes with the mlink command to create symbolic links, but you have to use the Command Line terminal to invoke it. Open an elevated command prompt (one with Admin privileges) by pressing Win + X and selecting the appropriate option from the list. The syntax for the command is as follows:

mlink /switch <link> <target>

So, to make C:\Users\<user>\AppData point to the new location on the D: drive, we’ll invoke the following command:

mlink /D "C:\Users\<user>\AppData" "D:\AppData"

Once the link is created, as far as Windows is concerned, the two locations are the same place. If an application needs to access the folder, it will seamlessly connect to the location on D:. As such, Fusion360 will run without a hitch (although it will load more slowly due to the reduced read/write speed)!

Unfortunately, this trick does not work to upgrade Windows 10 to 11, so this machine will be stuck in the late 2010s forever (or until I decide to install Linux on it…again).

How To Update Plex Plugin TrueNAS

Once upon a time, during the dark ages, we had to run several shell commands–like savages–to get the Plex plugin in TrueNAS (or FreeNAS, if you go back that far) to update. One had to fetch, then unpack the tarball, then move to the right directory, change ownership, and finally run the script! It was quite a pain when Plex was coming out with a new update every week (or so it seemed), and got to be more annoying than productive.

Fortunately, we don’t have to live like animals anymore because [mstinaff] wrote a nice, simple shell script to take care of all the heavy lifting! You can even set it up as a cron task to run on schedule (for when Plex decides to start issuing updates every few days again).

Let’s start by assuming that you know how to access your TrueNAS jails. On the Jails dialog, open Plex, then DO NOT CLICK “Update”. Click “Shell”.Once you’ve got your root prompt in the shell, download the updater by invoking the following command:
fetch https://raw.githubusercontent.com/mstinaff/PMS_Updater/master/PMS_Updater.sh

From here, you can just run the shell script with sh PMS_Updater.sh

Automating Plex updates on TrueNAS with cron jobs

To set up a cron job on your TrueNAS installation, navigate to the Tasks > Cron Jobs dialog. Click the “ADD” button to create a new cron job and give it a descriptive name such as “Plex update”. Then, enter the following in the “Command” field:

/usr/local/bin/iocage exec [plexjail] /bin/sh /usr/local/PMS_Updater/PMS_Updater.sh -r -a -v

Substitute the name of your Plex jail for [plexjail]. Mine is just called “plex“. The -r flag will keep your installation clean by removing the older packages before installing the new one. The -a flag automatically updates to the newest version without user intervention. Finally, the -v flag runs the script in verbose mode, so you’ll have a log available just in case anything goes wrong.

Set the “Run As User” field to root, and set your preferred schedule. I run mine weekly on Sunday nights. From here, make sure your job is enabled, and click “SAVE”. Now, you shouldn’t have to make another manual Plex update again!

A Serial Terminal For Windows Terminal

Since switching to Windows 11, I have fallen in love with Windows Terminal–the built-from-the-ground-up terminal emulator for Windows that combines everything that I loved about Linux and MacOS with the functionality of tabbed windows and a serious dose of customization. However, because much of my command line work falls into communicating with an external device over serial, I wanted to be able to keep that workflow within Windows Terminal like I’m used to doing already. In other words, I didn’t want to have to resort to using a separate GUI like PuTTY when a command-line tool like Screen or Minicom would do just fine. The problem is that, since the removal of HyperTerminal in Windows Vista, Windows has not included a CLI solution for serial communication (which is kinda weird because Telnet is still buried in Windows 11; if the reasoning was because obsolescence, you’d think that Telnet would also get the axe).

Now, since I have Ubuntu installed, I could just install Screen or Minicom and call it a day, but WSL 2 does not support serial communication. If I wanted to use those tools, I would either need to change the WSL version every time I wanted to use the serial port or install another instance of Linux under WSL 1. I mean, it works, but I really just felt it inefficient to have to fire up Debian (the install is smaller than Ubuntu) just so I could use Minicom.

After a little more digging, I found Makerdiary’s Terminal-S. It’s a simple serial terminal written in Python that can be compiled as a self-contained exe. This little gem was exactly what I was looking for in terms of functionality! It automatically connects to the COM port (or drops a list of available ports) and connects using some default settings for baud rate, stopbit, and parity. I can fire up Windows Terminal, invoke the command in PowerShell, and I’m good to go!

Windows Serial Terminal

But this is Windows Terminal, and I have this lovely menu of drop-down presets that will automatically spawn the environment of my choice with some lovely aesthetic theming. So, I want to be able to just click on a new tab and get that full retro terminal feel without needing to pretend I’m even in Windows! What I need to do is alter the program just a smidge so that instead of looking for flags in the command-line structure (ie -b for setting baud rate), the program will just ask me what settings I want to use (including some defaults for simplicity). To do this, I simply altered the @click.command section to only look for serial ports and moved the connection settings to a series of prompts in the main function, like so:

"""
Terminal for serial port

Requirement:

    + pyserial
    + colorama
    + py-getch
    + click
"""

import os
if os.name == 'nt':
    os.system('title Serial Console')

from collections import deque
import sys
import threading

import colorama
import click
import serial
from serial.tools import list_ports


def run(port, baudrate = 115200, parity='N', stopbits=1):
    try:
        device = serial.Serial(port=port,
                                baudrate=baudrate,
                                bytesize=8,
                                parity=parity,
                                stopbits=stopbits,
                                timeout=0.1)
    except:
        print('--- Failed to open {} ---'.format(port))
        return 0

    print('--- {} is connected. Press Ctrl+] to quit ---'.format(port))
    queue = deque()
    def read_input():
        if os.name == 'nt':
            from msvcrt import getch
        else:
            import tty
            import termios
            stdin_fd = sys.stdin.fileno()
            tty_attr = termios.tcgetattr(stdin_fd)
            tty.setraw(stdin_fd)
            getch = lambda: sys.stdin.read(1).encode()

        while device.is_open:
            ch = getch()
            # print(ch)
            if ch == b'\x1d':                   # 'ctrl + ]' to quit
                break
            if ch == b'\x00' or ch == b'\xe0':  # arrow keys' escape sequences
                ch2 = getch()
                esc_dict = { b'H': b'A', b'P': b'B', b'M': b'C', b'K': b'D', b'G': b'H', b'O': b'F' }
                if ch2 in esc_dict:
                    queue.append(b'\x1b[' + esc_dict[ch2])
                else:
                    queue.append(ch + ch2)
            else:  
                queue.append(ch)

        if os.name != 'nt':
            termios.tcsetattr(stdin_fd, termios.TCSADRAIN, tty_attr)

    colorama.init()

    thread = threading.Thread(target=read_input)
    thread.start()
    while thread.is_alive():
        try:
            length = len(queue)
            if length > 0:
                device.write(b''.join(queue.popleft() for _ in range(length)))

            line = device.readline()
            if line:
                print(line.decode(errors='replace'), end='', flush=True)
        except IOError:
            print('--- {} is disconnected ---'.format(port))
            break

    device.close()
    if thread.is_alive():
        print('--- Press R to reconnect the device, or press Enter to exit ---')
        thread.join()
        if queue and queue[0] in (b'r', b'R'):
            return 1
    return 0

@click.command()
@click.option('-p', '--port', default=None, help='serial port name')
@click.option('-l', is_flag=True, help='list serial ports')

def main(port, l):
    port is None
    if port is None:
        ports = list_ports.comports()
        if not ports:
            print('--- No serial port available ---')
            return
        if len(ports) == 1:
            port = ports[0][0]
        else:
            print('--- Available Ports ----')
            for i, v in enumerate(ports):
                print('---  {}: {} {}'.format(i, v[0], v[2]))
            if l:
                return
            raw = input('--- Select port index: ')
            try:
                n = int(raw)
                port = ports[n][0]
            except:
                return
    baudrate = input("Enter baud rate (Default 115200): ")
    if (len(baudrate) == 0):
        baudrate = 115200
    parity = input("Enter parity [N,E,O,S,M] (Default N): ")
    if (len(parity) == 0):
        parity = "N"
    stopbits = input("Enter stop bit (Default 1): ")
    if (len(stopbits) == 0):
        stopbits = 1    
    while run(port, baudrate, parity, stopbits):
        pass

if __name__ == "__main__":
    main()

Of course, it took me a little bit to deconstruct the program (as well as re-learn Python, which I hadn’t really used in any significant capacity for half a decade at least), but now I have it working exactly how I want it to work, and it feels right! Of course, I had never used Python on Windows before, either, so wrapping my head around PowerShell has been enlightening as well (Yes, I’m late to the PowerShell party, so I’m making up for it). Once I figured out how to use Pyinstaller (after remembering how to set a PATH variable in Windows), then I just have to drop the portable EXE file into a nice, out of the way place in Windows (might as well put it in a folder in C:) and make sure that folder is added to the PATH variable.

Add a folder to PATH variable

Adding a folder or application to the global PATH variable is a pretty simple proposition in Windows. From Windows Explorer, right-click on “This PC” and select “Properties”. This will bring up the settings dialog for System > About. Just under the “Device Specifications” section, click “Advanced System Settings” to bring up the traditional System Properties window. Click on the “Advanced” tab, then the “Environment Variables” button at the bottom of the window.

The “Environment Variables” window is divided into to groups: one for the current user and one for the system. In the system group dialog, find and double-click the line for “Path” to edit it. Click the “New” button to add a new line and type in the path for the folder or application you wish to add to the system PATH. When you’re done, click “OK” to close the window and save, then click “OK” to close the Environment Variables window, and finally click “OK” to close the System Properties window.

Customize Windows Terminal

In Windows Terminal, open the settings dialog and click “Add A New Profile”. Fill in the settings as appropriate. I’ve posted mine as a model:


Retrotacular

Of course, the real draw here is giving the terminal tab a lovely old-school green phosphor look which we can do either using the settings GUI to turn on the “Retro terminal effects” (this setting simulates CRT scan lines and gives a nice anti-alias that simulates the phosphorescent glow of the characters on the monitor). I’m using the Cascadia Mono font at 16pt weight to get the look I’m going for and the “Vintage” cursor style will round everything out nicely. For the color scheme, add the following block of code to the settings JSON file, then enable the new “Green Phosphor” color scheme.

{
            "background": "#000000",
            "black": "#000000",
            "blue": "#00FF00",
            "brightBlack": "#00FF00",
            "brightBlue": "#00FF00",
            "brightCyan": "#00FF00",
            "brightGreen": "#00FF00",
            "brightPurple": "#00FF00",
            "brightRed": "#00FF00",
            "brightWhite": "#00FF00",
            "brightYellow": "#00FF00",
            "cursorColor": "#00FF00",
            "cyan": "#00FF00",
            "foreground": "#00FF00",
            "green": "#00FF00",
            "name": "Green Phosphor",
            "purple": "#00FF00",
            "red": "#00FF00",
            "selectionBackground": "#FFFFFF",
            "white": "#00FF00",
            "yellow": "#00FF00"
        }

From here, everything is ready to go! Connect a serial device, fire up the terminal, and you’re off to the races!