Synthesizing simple chords with sox

SoX can do almost anything with audio files — including synthesize audio from scratch. Unfortunately, SoX’s syntax is more than a bit hard to follow, and the manual page isn’t the most clear. But there is one example in the manual that gives a glimpse of what SoX can do:

play -n synth pl G2 pl B2 pl D3 pl G3 pl D4 pl G4 \ 
     delay 0 .05 .1 .15 .2 .25 remix - fade 0 4 .1 norm -1

While it plays a nice chord, it’s not obvious how to make audio files from this process. I have a project coming up that needs a few simple guitar chords, and with much trial and error I got SoX to spit out audio files. Here’s what I keyed into the shell:

cat guitar.txt | while read chord foo first third fifth
do
  echo "$chord" :
  sox -n \ 
    -r 16000 -b 16 "chord-${chord}.wav" \
    synth pl "$first" pl "$third" pl "$fifth" \
    delay 0 .05 .1 \ 
    remix - \ 
    fade 0 1 .095 \ 
    norm -1
done

with these lines in the file “guitar.txt”

G   :  G2  B2  D3
C   :  C3  E3  G4
D   :  D3  F#4 A3
F   :  F3  A3  C4
A   :  A3  C#4 E4
E   :  E2  G#3 B3
Em  :  E2  G3  B3

How the SoX command line breaks down:

    • -n —use no input file: SoX is going to generate the audio itself
    • -r 16000 -b 16 “chord-${chord}.wav” — with a sample rate of 16 kHz and 16-bits per sample, write to the output file “chord-….wav”
    • synth pl “$first” pl “$third” pl “$fifth” —synthesize three plucked tones read from the file
    • delay 0 .05 .1 —delay the second tone 0.05 s after the first and likewise the third after the second. This simulates the striking of guitar strings very slightly apart.
    • remix – —mix the tones in an internal pipe to the output
    • fade 0 1 .095 —fade the audio smoothly down to nothing in 1 s
    • norm -1 —normalize the volume to -1 dB.

The chords don’t sound great: they’re played on only three strings, so they sound very sparse. As my application will be playing these through a tiny MEMS speaker, I don’t think anyone will notice.

Update: well, now I know how to do it, why not do all 36 autoharp strings and make the “magic ensues” sound of just about every TV show of my childhood?

Glissando up:

sox -n -r 48000 -b 16 autoharp-up.wav synth pl "F2" pl "G2" pl "C3" pl "D3" pl "E3" pl "F3" pl "F#3" pl "G3" pl "A3" pl "A#3" pl "B3" pl "C4" pl "C#4" pl "D4" pl "D#4" pl "E4" pl "F4" pl "F#4" pl "G4" pl "G#4" pl "A4" pl "A#4" pl "B4" pl "C5" pl "C#5" pl "D5" pl "D#5" pl "E5" pl "F5" pl "F#5" pl "G5" pl "G#5" pl "A5" pl "A#5" pl "B5" pl "C6" delay 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95 1 1.05 1.1 1.15 1.2 1.25 1.3 1.35 1.4 1.45 1.5 1.55 1.6 1.65 1.7 1.75 remix - fade 0 6 .1 norm -1

Glissando down:

sox -n -r 48000 -b 16 autoharp-down.wav synth pl "C6" pl "B5" pl "A#5" pl "A5" pl "G#5" pl "G5" pl "F#5" pl "F5" pl "E5" pl "D#5" pl "D5" pl "C#5" pl "C5" pl "B4" pl "A#4" pl "A4" pl "G#4" pl "G4" pl "F#4" pl "F4" pl "E4" pl "D#4" pl "D4" pl "C#4" pl "C4" pl "B3" pl "A#3" pl "A3" pl "G3" pl "F#3" pl "F3" pl "E3" pl "D3" pl "C3" pl "G2" pl "F2" delay 0 0.05 0.1 0.15 0.2 0.25 0.3 0.35 0.4 0.45 0.5 0.55 0.6 0.65 0.7 0.75 0.8 0.85 0.9 0.95 1 1.05 1.1 1.15 1.2 1.25 1.3 1.35 1.4 1.45 1.5 1.55 1.6 1.65 1.7 1.75 remix - fade 0 6 .1 norm -1

Could maybe use some reverb in there for the ultimate nostalgic effect.

 

making an hourly chime with cron

I wanted to have a “Hey, be here now!” ping throughout the working day. Something loud enough to hear, but not irritating.

Doing this with cron was harder than you might expect. It seems that sound is typically part of the X11 display infrastructure, so you need to give the command permission to make a noise on this particular machine’s display. Here’s the crontab line I came up with:

# m h    dom mon dow   command
  0 9-17 *   *   1-5   export DISPLAY=:0 && /usr/bin/play -q /home/scruss/sounds/ting/ting.wav

That translates as: at 0 minutes past the hours of 09:00 to 17:00 on any weekday (day of week = 1-5, and we don’t care about day of month or which month it is), execute the command play (part of the sox package) with no text output (-q). cron needs environment variables like DISPLAY set, and prefers full command paths. It may trigger a second or so after the turn of the hour; this is good enough for me.

As for the alert, I wanted something distinctive — percussive, short, bright — but with a tiny bit of modulation to stop it sounding like a bland computer-generated sine wave. This is what I made; click on the image and the sound should play or download:

ting-audacityIt’s essentially a 2093 Hz (C7) sine wave, mixed with itself frequency-modulated at 7 Hz. Why 7 Hz? Apart from sounding about right, 2093 is exactly divisible by 7, 13 & 23, so I used a factor for neatness.

There was some later messing about in Audacity (mostly fades and length edits; I forget exactly what). The two components were generated using sox:

sox -n ting-plain.wav synth 1 sine C7 fade l 0 1 1
 sox -n ting-vibrato.wav synth 1 sin C7 synth 1 sine fmod 7 fade l 0 1 1

Yes, sox does have pretty horrible syntax, doesn’t it?

The frequency-modulated one seems to be pretty close to the final result. It would be less time spent trying to save time …

micro, a nice little text editor

screenshot-from-2016-09-18-15-24-13

micro – https://github.com/zyedidia/micro – is a terminal-based text editor. Unlike vi, emacs and nano, it has sensible default command keys: Ctrl+S saves, Ctrl+Q quits, Ctrl+X/C/V cuts/copies/pastes, etc. micro also supports full mouse control (even over ssh), Unicode and colour syntax highlighting.

micro is written in Go – https://golang.org – so is very easy to install:

go get -u github.com/zyedidia/micro/...

If you don’t already have Go installed, it’s pretty simple, even on a Raspberry Pi: https://golang.org/doc/install

If your running under Linux, you probably want to have xclip installed for better cut/paste support.

Overall, I really like micro. It’s much easier to use than any of the standard Linux text editors. It uses key commands that most people expect. Creating code should not be made harder than it needs to be.

(I was about to suggest FTE, as it appears to be the closest thing to the old MS-DOS 6 editor that I’ve seen under Linux. While it’s a great plain text editor, its Unicode support isn’t where it needs to be in 2016.
micro suggestion came via MetaFilter’s Ctrl + Q to quit. Need I say more?
)

Working with case-sensitive CD-ROM images on Linux

I bought a CD-ROM, The World of Patterns. It’s supposed to work on ‘Any computer with an Internet browser and a CD-ROM drive’. Guess I don’t just have any computer, then …

The disk — an interesting mathematical/artistic study of patterns — is arranged as a tree of HTML files, with internal links and images. This is how the folders appear on my computer:

├── art
│   ├── islam
│   ├── preislam
│   └── pstislam
│   ├── latt
│   ├── other
│   └── quilts
│   ├── modern
│   │   ├── large
│   │   ├── patch3
│   │   └── patch4
│   └── usa
├── info
├── maths

All neatly lower case, as one might expect. Unfortunately, the internal links are hard-coded to access links such as /art/Islam/over.htm, and Linux, being good and literal, can’t find the upper case ones.

Unfortunately, the majority of computers quietly ignore the case of letters on removable media. Linux’s insistence on being correct is at odds with what is generally considered useful. But there’s a way around this. You can give the mount command options to tell it to be more chill about case:

sudo mount -t iso9660 -o loop,check=relaxed,map=normal,norock,nojoliet disk.iso /mnt/scratch/

This works for me quite well:

Screenshot from 2015-09-08 10:57:54

The CD-ROM is interesting, if a little dated. The author has gone on to produce the website tilingsearch.org, a huge database of historical tile patterns.

Thermal Printer driver for CUPS, Linux, and Raspberry Pi: zj-58


Update:slightly cleaned up for Raspbian Stretch, 2017-11.

This might be my last post on mini-printers, as I’ve found a driver that just works with CUPS on Raspberry Pi. It also works on Ubuntu on my laptop, and should work (though untried) on Mac OS. You’ll have to build it from source, but it’s not too hard.

The hard part is working out if your thermal printer will work or not. There are many out there, and they’re all slightly different. If they support the ESC/POS bitmap command GS v 0 on 58 mm wide paper, they should work. The ones I’ve tested are:

  1. Catex POS5890U — USB, cheap, fast.
  2. “701” control board panel printer — fairly generic, decent quality printer with serial input. A bit slow for daily use at 9600 baud.
  3. Xiamen Embedded Printer DP-EH600 — as above.

The following should also work, but haven’t been tried:

  • Adafruit Mini Thermal Receipt Printer — again, serial, so not super fast.
  • Sparkfun thermal printer — which now appears to be identical to the Adafruit unit, and is referred to as the “A1 (or A2) micro panel printer” in the documentation.

Known not to work:

  • BTHT-V6 printer — which uses a completely different command set. (Roughly that of an Epson FX-80 for image commands, if you care.)

If you have a manual for your printer, check it to see if it prints bitmaps by sending a three byte header of 29 118 48 (or 1D 76 30 in hexadecimal). If you’re not sure, try it with a small test image, and be ready by the power switch …

Getting and building the driver

The driver is meant for a ZiJiang ZJ-58 printer, and lives here on Github: klirichek/zj-58.

Building it is fairly easy, though it has some package requirements you’ll need to meet. On Raspbian, do something like:

sudo apt-get install libcups2-dev libcupsimage2-dev git build-essential cups system-config-printer

This new command may take a long time to run.

Now you can download the driver code:

git clone https://github.com/klirichek/zj-58.git

Building it is straightforward:

cd zj-58/
make

and installing takes all of:

sudo ./install

You’ll still have to set up the printer to accept jobs, but now you have the driver installed.

Setting up the printer

This bit is much more graphical. Open up the printer settings window (Preferences → Print Settings):

2015-07-11-220946_452x281_scrotSelect the Add icon, and the New Printer window opens:

2015-07-11-221141_602x592_scrotThe POS5890U shows up as “Unknown” on my USB port, as Linux doesn’t know the name of this device from its USB ID.

Update (for the slightly desperate): In the land of “Things have changed!”, my Catex printer isn’t showing up at all. I had to resort to this in the Enter URI option:

thermal printer usb lp uri
(hey, this image doesn’t quite match the flow. Look only at the the “Device URI” bit please)

parallel:/dev/usb/lp0 seems to work. Another option might be looking at the output of

sudo /usr/lib/cups/backend/usb

which suggests that usb://Unknown/Printer might work too. (All of this might need to have been preceded by

sudo usermod -a -G lp pi

and a logout or reboot; I did say this was for the slightly desperate …)

If the above doesn’t apply, your printer might have an known ID, or show up as a serial port. Select the right one, and click Forward:

2015-07-11-221221_602x592_scrotHere, I’m really pleased that the driver is for a Zijiang unit, as it’s conveniently at the end of the list. Click Forward

2015-07-11-221240_602x592_scrotNo options here, so again, Forward

2015-07-11-221311_602x592_scrotI changed the name from the default ZJ-58 to the more unixly zj58. You don’t have to, but either way, Apply the changes.

2015-07-11-222030_452x281_scrotAnd there it is, registered as a printer!

Printer Options

Most printers expect paper wider than 58 mm, but mini-printers can’t do that. To tell the system about paper sizes, right click on the printer’s icon, and change the printer settings:

2015-07-11-222225_570x560_scrotA test page might print properly now, but you should probably go into Printer Options first:

2015-07-11-222239_570x560_scrotYou do want to set the media size to at least 58 × 210 mm. This is just the longest strip it will print in one ‘page’; if your print is shorter, it won’t waste extra paper. You can choose longer prints, but not wider. The default assume your local standard paper size which —be it A4, Letter, or whatever — will not be what you want here. Hit OK.

Printing something

You could print the self test page, but it’s long and boring. If you’re fairly sure your printer will be supported, try this scaled PDF version of the Raspberry Pi Logo: raspberry-pi-logo.  Printed and scanned, it came out like this:

raspberry-pi-logo-miniprinterNot the best rendition, but not bad for a $30 receipt printer. My test image came out like this (iffy scan, sorry):

zj58-driver-testI haven’t covered the intricacies of setting up serial port connections here; maybe another time. Also, there’s a short delay (maybe 10–20 s) between selecting Print and the printer coming to life. CUPS is pretty complex, and is doing things in the background while you wait.

(Seeing as I use their logo prominently up there, I should totes acknowledge that “Raspberry Pi is a trademark of the Raspberry Pi Foundation”. Also, I couldn’t have done all this without the support of Reed Zhao. Though Reed has moved on to bigger things and doesn’t sell printers any more, his help — not to mention the generous loan of a couple of printers — was very welcome.)

fun with darktable

LiquidI’m really impressed with darktable, a raw photo workflow for Linux.  Unlike Gimp, it uses floating point for all image processes, so it doesn’t get caught up in quantization error. It’s a non-destructive editor, too: it assumes your source images are like negatives, and any changes you make are only applied to the exported images. Darktable also has a very intuitive black and white filtering mode (where you apply a virtual colour filter to the front of the lens, and see the results in real time) and some very powerful geotagging features. I’m sold.

darktable-uiIt’s not immediately obvious how some of the features work, and it took me a few hours (and some reading of the manual — eek!) to get files to export as I wanted them. It’s not quite perfect yet — the map feature can become unresponsive if you click too much on image icons — but it’s definitely solid enough for my purposes.

More of my initial darktable attempts on flickr: A Day by the Lake.

Notes on mini-printers and Linux

miniprinter galleryOver the last few weeks, I’ve been playing with a few small thermal printers. Meant as POS or information booth printers, they make a diverting project for the lo-fi printing enthusiast. While they all have common features — 58 mm/2¼” paper width, 8 pixel/mm resolution, 48 mm print width, serial connection — they all have their quirks. You may have seen these sold as the Adafruit Mini Thermal Receipt Printer or Sparkfun’s Thermal Printer, but there are many others. I’m going to write more on interfacing these directly to Raspberry Pi, Arduino, and (if I can navigate the documentation) a CUPS driver.

Update, July 2015: Here’s a CUPS driver: klirichek/zj-58, and my writeup on installing it on a Raspberry Pi — Thermal Printer driver for CUPS, Linux, and Raspberry Pi: zj-58

For now, I’m just leaving you a list of things I’ve found helpful for the DP-EH600 and 701 printers. Note that the similar-looking BTHT-v6 printer uses a completely different command set.

  • Replacement paper is sold as 2¼” × 30′. Staples have a box of 30 rolls for under $25 (item 279096, not on their website). Longer rolls don’t fit.
  • You’ll need a USB→TTL Serial adaptor, preferably one with DTR control. I use one from JY-MCU. In a pinch, you can use a simpler  Debug / Console Cable for Raspberry Pi, but you risk serial overruns and dodgy results. Remember that RX on the adaptor goes to TX on the printer, and vice versa.
  • A good solid power supply is needed; these printers draw ~8 W when printing. Some printers only support 5 V (for which a 3 amp adaptor would be ideal), others 5-9 V. The higher voltage makes text printing faster. You can’t drive these directly from your Raspberry Pi/Arduino power supply.
  • Linux serial ports are set to some defaults which may have been historically useful, but now corrupt 8-bit data. A trick I picked up here is to first issue the command
    stty -F /dev/ttyUSB1 0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
    which clears all settings, then set the device up as you need it:
    stty -F /dev/ttyUSB1 speed 9600 raw cs8
    (Most of these printers default to 9600 baud. Your device may be called something different to ttyUSB1.)
  • I’ve written a couple of Python driver stubs which take an image and produce the relevant binary output:
    • scruss / esc-pos-image.py – prints an image as a single command. May not work on the SparkFun printer. Does not work on the BTHT-v6.
    • scruss / esc-pos-image-star.py – prints the image in 24 pixel deep bands. Can sometimes cause visible gaps in the printout, but will work on almost all printers, except the BTHT-v6.
  • These Python libraries also work, as long as you address the printer properly (right device, right speed):

Notes/Credits

  1. Reed Zhao (of Tangram Software) lent me a couple of different printers for testing after I bought a different one from him. He’s put a lot of work into sourcing these printers direct from the manufacturers. Thanks, Reed!
    NB: Reed doesn’t sell printers any more. Try eBay.
  2. Image credits for print samples:

elementary OS: could be worse

Imagine there’s a really nicely arranged screenshot of elementary OS here. You know, browser arranged just so, dock showing shiny icons, and a coy little dropdown showing that I’m playing music that’s faaaar hipper than you’ll ever be. Got that image? Good. ‘Cos I just spent a ½-hour setting it up, then deleted it in a second of unthought when I cleaned up the elementary OS VM from VirtualBox. Aargh!

elementary OS is a very pretty Ubuntu/Debian distro. It has a very strong visual identity, and is designed and managed by a very small group. This rigidity may annoy the seasoned Linux user,  but will likely work in a more logical way if you’re used other OSs. You won’t face jarringly mismatched user interface elements, as still happens with Ubunty/Unity. Linux UX allows too much choice, so you’re never sure which options do what at any given time.
(F’rinstance: Ctrl+Q used to quit programs. Now, Ubuntu wants us to use Ctrl+W, the old close-the-window command. Some programs no longer quit with Ctrl+Q, so you’re left with an awksmash of Ctrl+Q_no-I-meant_W. Don’t make me think!)

A couple of things put me off elementary OS:

  1. You can’t put files on the desktop. In an effort to be tidy, eOS forbids you putting the stuff you’re working on in the place you’ll see it. This is a major annoyance, but worse things are coming.
  2. It expects you to pay for it. No, really. They want $10 from you, right from the get-go. While you can get around this (click the “Download” button; it only looks like it’s linked to the payment button), they do something far, far worse:
    They use a PayPal popunder.
    Srsly. Gahh. Eww. Pop-unders are the web equivalent of taking a 💩 on an art gallery floor. If they’re low enough to pull that kind of stunt, who knows what leakage lurks under their pretty graphics?

The HP48: the best calculator ever

We had an unscheduled overnight stop in East Lansing last week, and I took the chance to visit the MSU Surplus Store.  For $15, they had HP48G calculators, seemingly unused:

hp48gThey still have a bunch of them: HP 48G Graphic Calculator.

They’re maybe not the quickest (the 4 MHz Saturn processor chugs sometimes, and wanders off to clean up memory when it feels like it), the display is downright chunky these days, but they have everything that a scientific calculator should have. The keys have a good action. It just works. Yes, your smartphone has hundreds of times the processing power, but it’s not specialized to the task. The HP48 is.

If you’re feeling really nerdy, you can run an HP48 (a GX, not the G which I have) under Linux using x48. Jeff has some useful tips on installing x48 on newer ubuntu versions (though you don’t have to do the font thing under Ubuntu 13.10).

x48Building it is a small matter of ./autogen.sh ; ./configure ; make ; sudo make install.  To run it, you’ll need to install the GX ROM image to ~/.hp48.  The first time you run it, I’d recommend running it from the terminal with:

x48 -connFont -misc-fixed-bold-r-normal--13-120-75-75-c-70-iso8859-16 -smallFont -misc-fixed-bold-r-normal--13-120-75-75-c-70-iso8859-16 -mediumFont -misc-fixed-bold-r-normal--14-130-75-75-c-70-iso8859-16 -largeFont -misc-fixed-bold-r-normal--15-140-75-75-c-90-iso8859-16 -reset -initialize -rom ~/.hp48/rom

as the ROM format has an outdated config file which causes it to complain weakly every time you start the emulator.

Scanned manuals are available from HP and archive.org here: HP 48g User Guide, HP 48g Quick Start Guide.

Protext lives!

Protext screenshot (dosemu)

Oh man, Protext! For years, it was all I used: every magazine article, every essay at university (all two of them), my undergraduate dissertation (now mercifully lost to time: The Parametric Design of a Medium Specific Speed Pump Impeller, complete with spline-drawing code in HiSoft BASIC for the Amiga, is unlikely to be of value to anyone these days), letters — you name it, I used Protext for it.

I first had it on 16kB EPROM for the Amstrad CPC464; instant access with |P. I then ran it on the Amiga, snagging a cheap copy direct from the authors at a trade show. I think I had it for the PC, but I don’t really remember my DOS days too well.

The freeware version runs quite nicely under dosemu. You can even get it to print directly to PDF:

  1. In your Linux printer admin, set up a CUPS PDF printer. Anything sent to it will appear as a PDF file in the folder ~/PDF.
  2. Add the following lines to your ~/.dosemurc:
    $_lpt1 = “lpr -l -P PDF”
    $_printer_timeout = (20)
  3. In Protext, configure your printer to be a PostScript printer on LPT1:

The results come out not bad at all:

protext output as pdfProtext’s file import and export is a bit dated. You can use the CONVERT utility to create RTF, but it assumes Code page 437, so your accents won’t come out right. Adding \ansicpg437 to the end of the first line should make it read okay.

(engraving of Michel de Montaigne in mad puffy sleeves: public domain from Wikimedia Commons: File:Michel de Montaigne 1.jpg – Wikimedia Commons)

A (mostly) colour-managed workflow for Linux for not too many $$$

Colour management is good. It means that what I see on the screen is what you meant it to look like, and anything I make with a colour-managed workflow you’ll see in the colours I meant it to have. (Mostly.) You can spend a lot of money to do this professionally, but you can also get most of the benefits for about $125, if you’re prepared to do some fiddly stuff.

The most important part is calibrating your display. Hughski’s ColorHug (which I’ve mentioned before) is as close to plug-and-play as you’ll get: plug it in, and the colour management software pops up with prompts on what to do next. Attach the ColorHug to the screen (with the newly supplied stretchy band), let it burble away for 10–20 minutes, and the next time you log in, colours will be just right.

Calibrating the scanner on my Epson WorkForce WF-7520 was much more work, and the process could use optimization. To calibrate any scanner, you need a physical colour target to scan and compare against reference data. The cheapest place to get these (unless there was one in the box with your scanner) is Wolf Faust’s Affordable IT 8.7 (ISO 12641) Scanner Colour Calibration Targets. If there are a bunch of likeminded folk in your area, it’s definitely worth clubbing together on a group buy to save on shipping. It’s also less work for Wolf, since he doesn’t have to send out so many little packages.

(I’ve known of Wolf Faust since my Amiga days. He produced the most glorious drivers for Canon printers, and Jeff Walker produced the camera-ready copy for JAM using Wolf’s code. While Macs had the high end DTP sewn up back then, you could do amazing things on a budget with an Amiga.)

colour targetThe target comes packed in a protective sleeve, and along with a CD-R containing the calibration data which matches the print run of the target. Wolf makes a lot of targets for OEMs, and cost savings from his volume clients allow him to sell to individuals cheaply.

Scanning the thing without introducing automatic image corrections was the hard part. I found that my scanner had two drivers (epson2 and epkowa), the latter of which claimed to support 48-bit scanning. Unfortunately, it only supports 24-bit, like the epson2 driver, so whichever I chose was moot. I used the scanimage command line tool to make the scan:

scanimage --mode Color -x 175 -y 125 --format=tiff --resolution 300 > Epson-Workforce_WF-7520-WFaust-R1.tiff

which looks, when reduced down to web resolution, a bit like this:

Epson-Workforce_WF-7520-WFaust-R1It looks a lot darker than the physical target, so it’s clear that the scanner needs calibrating. To do this, you need two tools from the Argyll Colour Management System. The first creates a text representation of the scanned target’s colour patches:

scanin -v Epson-Workforce_WF-7520-WFaust-R1.tiff /usr/share/color/argyll/ref/it8.cht IT87/r130227.txt diag.tiff

The result is a smallish text file Epson-Workforce_WF-7520-WFaust-R1.ti3 which needs one more step to make a standard ICC profile:

colprof -A Epson -M 'Workforce WF-7520' -D 'WFaust R1' -ax -qm Epson-Workforce_WF-7520-WFaust-R1

I didn’t quite need to add that much metadata, but I could, so I did. The resultant ICC file can be used to apply colour calibrations to scanned images. Here’s the target scan, corrected:

Epson-Workforce_WF-7520-WFaust-R1-corrected

(I’ve made this a mouseover with the original image, so you can see the difference. Also, yes, there is a greasy thumb-print on my scanner glass near the bottom right, thank you so much for noticing.)

I used tifficc from the Little CMS package to apply the colour correction:

tifficc -v -i Epson-Workforce_WF-7520-WFaust-R1.icc Epson-Workforce_WF-7520-WFaust-R1.tiff Epson-Workforce_WF-7520-WFaust-R1-corrected.tiff

There are probably many easier, quicker ways of doing this, but this was the first thing I found that worked.

To show you a real example, here’s an un-retouched scan of the cover of Algrove Publishing‘s book “All the Knots You Need”, scanned at 75 dpi. Mouseover to see the corrected version:

all-the-knots-you-need_algrove

(Incidentally, there are two old but well-linked programs that are out there that purport to do scanner calibration: Scarse and LPROF. Don’t use them! They’re really hard to build on modern systems, and the Argyll tools work well.)

The last part of my workflow that remains uncalibrated is my printer. I could make a target with Argyll, print it, scan it, colour correct it, then use that as the input to colprof as above. I’m suspecting the results would be mediocre, as my scanner’s bit depth isn’t great, and I’d have to do this process for every paper and print setting combination. I’d also have to work out what magic CUPS does and compensate. Maybe later, but not yet.

Using large format paper with Linux and the Epson WorkForce WF-7520 printer

Update: Nope, I can’t get this to work any more.

I have an Epson WorkForce WF-7520, and I really like it: excellent built-in duplex large format scanner with ADF, CIFS network storage, giant paper bins, photo quality printing up to 330×482 mm, only slightly expensive print cartridges… Under Linux, though, it’s not so well behaved, especially if you want to print on large format paper. This is the workaround I developed:

  1. Put the B-size/11×17″ paper in Tray 1 (the upper one), and the Letter paper in Tray 2. This, unfortunately, matters — the driver that can print large format can only access the upper tray. On the setup menu on the printer console, tell the printer which tray holds what size of paper.
  2. Install the epson-inkjet-printer-escpr driver; it should be in the standard Ubuntu repos. Define a printer (wf7520-lf, for example) that uses this driver. Set the paper size to “US B 11 x 17 in”.
  3. Ensure that the lsb and lsb-printing packages are installed:
    sudo apt-get install lsb lsb-printing
  4. Download and install the non-free epson-201115w driver from the EPSON Download Center. Define a printer (I used wf-7520 for the name) using this driver, making sure that the correct PPD (epson-inkjet-printer 1.0.0-1lsb3.2 (Seiko Epson Corporation LSB 3.2)) is used. Set it up to use Letter paper, and (important!) set the source to Paper Cassette 2. You might want to make this printer the system default.

To print to large format, use the command:

lp -d wf7520-lf -o PageSize=USB file.pdf

To print regular size, just send the job to the wf-7520 device.

(modified from my Ask Ubuntu question/answer: Selecting Large Format Paper: what printing options work?)

Update for the (rightly) confused: Epson appear to have hoiked US B / 11×17″ support for this printer. Here are my PPDs:

Copying PPDs from one driver to another may not work, but you’ve likely nothing to lose.

fixing firefox’s fugly fonts on Ubuntu

Update 2015-09: Better yet, install Infinality. It makes font rendering pretty.


 

Switching back to Linux from Mac is still a process of ironing out minor wrinkles. Take, for example, this abomination (enlarged to show texture):—

Screenshot from 2013-05-19 11:42:18

… No, I’m not talking about Mr Paul’s antics (or the typo in the TP post, either), but the horrid non-matching ligatures (‘attack’, ‘flubbed’, ‘targeting’) in a sea of blocky text. Almost every programme I was running had this problem. Mouse over the image to see how it could look if you apply this easy fix.

Create (or edit) the file ~/.fonts.conf ~/.config/fontconfig/conf.d, and add the following lines:

<match target="font" >
  <edit name="embeddedbitmap" mode="assign">
    <bool>false</bool>
  </edit>
</match>

Log out, log back in again, and text is properly pretty. Yay!

clean up your GnuPG keyring

For reasons too annoying to explain, my GnuPG keyring was huge. It was taking a long time to find keys, and most of them weren’t ones I’d use. So I wrote this little script that strips out all of the keys that aren’t

  1. yours, or
  2. signatories to your key.

The script doesn’t actually delete any keys. It produces shell-compatible output that you can pipe or copy to a shell. Now my keyring file is less than 4% the size (or more precisely, 37‰) of the size it was before.

#!/bin/bash
# clean_keyring.sh - clean up all the excess keys

# my key should probably be the first secret key listed
mykey=$(gpg --list-secret-keys | grep '^sec' | cut -c 13-20 | head -1)
if
    [ -z $mykey ]
then
    # exit if no key string
    echo "Can't get user's key ID"
    exit 1
fi

# all of the people who have signed my key
mysigners=$(gpg --list-sigs $mykey | grep '^sig' | cut -c 14-21 | sort -u) 

# keep all of the signers, plus my key (if I haven't self-signed)
keepers=$(echo $mykey $mysigners | tr ' ' '\012' | sort -u)

# the keepers list in egrep syntax: ^(key|key|…)
keepers_egrep=$(echo $keepers | sed 's/^/^(/; s/$/)/; s/ /|/g;')

# show all the keepers as a comment so this script's output is shell-able
echo '# Keepers: ' $keepers

# everyone who isn't on the keepers list is deleted
deleters=$(gpg --list-keys | grep '^pub'|  cut -c 13-20 | egrep -v ${keepers_egrep})

# echo the command if there are any to delete
# command is interactive
if
    [ -z $deleters ]
then
    echo "# Nothing to delete!"
else
    echo 'gpg --delete-keys' $deleters
fi

Files:

Compose yourself, Raspberry Pi!

Years ago, I worked in multilingual dictionary publishing. I was on the computing team, so we had to support the entry and storage of text in many different languages. Computers could display accented and special characters, but we were stuck with 8-bit character sets. This meant that we could only have a little over 200 distinct characters display in the same font at the same time. We’d be pretty much okay doing French & English together, but French & Norwegian started to get a little trying, and Italian & Greek couldn’t really be together at all.

We were very fortunate to be using Sun workstations in the editorial office. These were quite powerful Unix machines, which means that they were a fraction of the speed and capabilities of a Raspberry Pi. Suns had one particularly neat feature:

Compose_key_on_Sun_Type_5c_keyboard(source: Compose key, Wikipedia.)

That little key marked “Compose”  (to the right of the space bar) acted as a semi-smart typewriter backspace key: if you hit Compose, then the right key combination, an accented character or symbol would appear. Some of the straightforward compose key sequences are:

  Compose +    
Accent First key Second key Result Example
Acute e é café
Grave ` a à déjà
Cedilla , c ç soupçon
Circumflex ^ o ô hôtel
Umlaut u ü küche
Ring o a å Håkon
Slash / L Ł Łukasiewicz
Tilde ~ n ñ mañana

Like every (non-embedded) Linux system I’ve used, the Raspberry Pi running Raspbian can use the compose key method for entering extra characters. I’m annoyed, though, that almost every setup tutorial either says to disable it, or doesn’t explain what it’s for. Let me fix that for you …

Setup

Run raspi-config

sudo raspi-config

and go to the configure_keyboard “4 Internationalisation Options” → “I3 Change Keyboard Layout” section. Your keyboard’s probably mostly set up the way you want it, so hit the Tab key and select <Ok> until you get to the Compose key section:

raspi-config: Compose key selectionChoose whatever is convenient. The combined keyboard and trackpad I use (a SolidTek KB-3910) with my Raspberry Pi has a couple of “Windows® Logo” keys, and the one on the right works for me. Keep the rest of the keyboard options the same, and exit raspi-config. After the message

Reloading keymap. This may take a short while
[ ok ] Setting preliminary keymap...done.

appears, you now have a working Compose key.

Using the Compose key

raspi-config hints (‘On the text console the Compose key does not work in Unicode mode …’) that Compose might not work everywhere with every piece of software. I’ve tested it across quite a few pieces of software — both on the text console and under LXDE — and support seems to be almost universal. The only differences I can find are:

  • Text Console — (a. k. a. the texty bit you see after booting) Despite raspi-config’s warning, accented alphabetical characters do seem to work (é è ñ ö ø å, etc). Most symbols, however, don’t (like ± × ÷ …). The currency symbol for your country is a special case. In Canada, I need to use Compose for and £, but you’ve probably got a key for that.
  • LXDE — (a. k. a. the mousey bit you see after typing ‘startx’) All characters and symbols I’ve tried work everywhere, in LXTerminal, Leafpad, Midori, Dillo (browser), IDLE, and FocusWriter (a very minimal word processor).
Special characters in Python's IDLE
Special characters in Python’s IDLE
Some Compose key sequences — Leafpad
Some Compose key sequences — Leafpad

To find out which key sequences do what, the Compose key – Wikipedia page is a decent start. I prefer the slightly friendlier Ubuntu references GtkComposeTable and Compose Key, or the almost unreadable but frighteningly comprehensive UTF-8 (Unicode) compose sequence reference (which is essentially mirrored on your Raspberry Pi as the file /usr/share/X11/locale/en_US.UTF-8/Compose). Now go forth and work that Compose key like a boß.

(If you’re on a Mac and feeling a bit left out, you can do something similar with the Option key. Here’s how: Extended Keyboard Accent Codes for the Macintosh. On Windows®? Out of luck, I’m afraid WinCompose!)

Mac to Linux: 1Password to KeePassX

I have too many passwords to remember, so I’ve been using a password manager for years. First there was Keyring for Palm OS, then 1Password on the Mac. 1Password’s a very polished commercial program, but it only has Mac and Windows desktop clients. Sadly, it had to go.

Finding a replacement was tough. It needed to be free, and yet cross-platform. It needed to work on iOS and Android. It also needed to integrate with a cloud service like Dropbox so I could keep my passwords in sync. The only program that met all of these requirements was KeePassX. I’ve stuck with the stable (v 0.4.3) branch rather than the flashy 2.0 version, as the older database format does all I need and is fully portable. MiniKeePass on iOS and KeePassDroid on Android look after my mobile needs. But first, I needed to get my password data out of 1Password.

1Password offers two export formats: a delimited text format (which seemed to drop some of the more obscure fields), and the 1Password Interchange Format (1PIF). The latter is a JSONish format (ಠ_ಠ) containing a dump of all of the internal data structures. There is, of course, no documentation for this file format, because no-one would ever move away from this lovely commercial software, no …

So armed with my favourite swiss army chainsaw, I set about picking the file apart. JSON::XS and Data::Dumper::Simple were invaluable for this process, and pretty soon I had all the fields picked apart that I cared about. I decided to write a converter that wrote KeePassX 1.x XML, since it was readily imported into KeePassX, would could then write a database readable by all of the KeePass variants.

To run this converter you’ll need Perl, the JSON::XS and Data::Dumper::Simple modules, and if your Perl is older than about 5.12, the Time::Piece module (it’s a core module for newer Perls, so you don’t have to install it). Here’s the code:

#!/usr/bin/perl -w
# 1pw2kpxxml.pl - convert 1Password Exchange file to KeePassX XML
# created by scruss on 02013/04/21

use strict;
use JSON::XS;
use HTML::Entities;
use Time::Piece;

# print xml header
print <<HEADER;
<!DOCTYPE KEEPASSX_DATABASE>
<database>
 <group>
  <title>General</title>
  <icon>2</icon>
HEADER

##############################################################
# Field Map
#
# 1Password			KeePassX
# ============================  ==============================
# title        			title
# username			username
# password			password
# location			url
# notesPlain			comment
#    -				icon
# createdAt			creation
#    -				lastaccess	(use updatedAt)
# updatedAt			lastmod
#    -				expire		('Never')

# 1PW exchange files are made of single lines of JSON (O_o)
# interleaved with separators that start '**'
while (<>) {
    next if (/^\*\*/);    # skip separator
    my $rec = decode_json($_);

    # throw out records we don't want:
    #  - 'trashed' entries
    #  -  system.sync.Point entries
    next if ( exists( $rec->{'trashed'} ) );
    next if ( $rec->{'typeName'} eq 'system.sync.Point' );

    print '  <entry>', "\n";    # begin entry

    ################
    # title field
    print '   <title>', xq( $rec->{'title'} ), '</title>', "\n";

    ################
    # username field - can be in one of two places
    my $username = '';

    # 1. check secureContents as array
    foreach ( @{ $rec->{'secureContents'}->{'fields'} } ) {
        if (
            (
                exists( $_->{'designation'} )
                && ( $_->{'designation'} eq 'username' )
            )
          )
        {
            $username = $_->{'value'};
        }
    }

    # 2.  check secureContents as scalar
    if ( $username eq '' ) {
        $username = $rec->{'secureContents'}->{'username'}
          if ( exists( $rec->{'secureContents'}->{'username'} ) );
    }

    print '   <username>', xq($username), '</username>', "\n";

    ################
    # password field - as username
    my $password = '';

    # 1. check secureContents as array
    foreach ( @{ $rec->{'secureContents'}->{'fields'} } ) {
        if (
            (
                exists( $_->{'designation'} )
                && ( $_->{'designation'} eq 'password' )
            )
          )
        {
            $password = $_->{'value'};
        }
    }

    # 2.  check secureContents as scalar
    if ( $password eq '' ) {
        $password = $rec->{'secureContents'}->{'password'}
          if ( exists( $rec->{'secureContents'}->{'password'} ) );
    }

    print '   <password>', xq($password), '</password>', "\n";

    ################
    # url field
    print '   <url>', xq( $rec->{'location'} ), '</url>', "\n";

    ################
    # comment field
    my $comment = '';
    $comment = $rec->{'secureContents'}->{'notesPlain'}
      if ( exists( $rec->{'secureContents'}->{'notesPlain'} ) );
    $comment = xq($comment);    # pre-quote
    $comment =~ s,\\n,<br/>,g;  # replace escaped NL with HTML
    $comment =~ s,\n,<br/>,mg;  # replace NL with HTML
    print '   <comment>', $comment, '</comment>', "\n";

    ################
    # icon field (placeholder)
    print '   <icon>2</icon>', "\n";

    ################
    # creation field
    my $creation = localtime( $rec->{'createdAt'} );
    print '   <creation>', $creation->datetime, '</creation>', "\n";

    ################
    # lastaccess field
    my $lastaccess = localtime( $rec->{'updatedAt'} );
    print '   <lastaccess>', $lastaccess->datetime, '</lastaccess>', "\n";

    ################
    # lastmod field (= lastaccess)
    print '   <lastmod>', $lastaccess->datetime, '</lastmod>', "\n";

    ################
    # expire field (placeholder)
    print '   <expire>Never</expire>', "\n";

    print '  </entry>', "\n";    # end entry
}

# print xml footer
print <<FOOTER;
 </group>
</database>
FOOTER

exit;

sub xq {                         # encode string for XML
    $_ = shift;
    return encode_entities( $_, q/<>&"'/ );
}

To run it,

./1pw2kpxxml.pl data.1pif > data.xml

You can then import data.xml into KeePassX.

Please be careful to delete the 1PIF file and the data.xml once you’ve finished the export/import. These files contain all of your passwords in plain text; if they fell into the wrong hands, it would be a disaster for your online identity. Be careful that none of these files accidentally slip onto backups, too. Also note that, while I think I’m quite a trustworthy bloke, to you, I’m Some Random Guy On The Internet. Check this code accordingly; I don’t warrant it for anything save for looking like line noise.

Now on github: scruss / 1pw2kpxxml, or download: 1pw2kpxxml.zip (gpg signature: 1pw2kpxxml.zip.sig)

SHA1 Checksums:

  • 3c25eb72b2cfe3034ebc2d251869d5333db74592 — 1pw2kpxxml.pl
  • 99b7705ff30a2b157be3cfd29bb1d4f137920c25 — readme.txt
  • de4a51fbe0dd6371b8d68674f71311a67da76812 — 1pw2kpxxml.zip
  • f6bd12e33b927bff6999e9e80506aef53e6a08fa — 1pw2kpxxml.zip.sig.txt

The converter has some limitations:

  • All attached files in the database are lost.
  • All entries are stored under the same folder, with the same icon.
  • It has not been widely tested, and as I’m satisfied with its conversion, it will not be developed further.

Ubuntu on the Samsung Series 7

My Late 2008 MacBook was getting a little slow, so I went laptop shopping. I ended up with the Samsung Chronos 7 (NP700Z5CH). Under my budget, but met my spec in every way.

Installing Ubuntu was a minor trial, but it works, and has preserved the Win 8 (blecch!) dual-boot. If it helps anyone, the procedure I followed was:

  • Updated the BIOS, made a recovery DVD and shrank the Windows partition using the DISKPART app (which reminds me so much of the old VMS admin tools).
  • Broadly following the UEFI instructions, I got the 64-bit Linux-Secure-Remix ISO and wrote it to a USB stick with UNetbootin.
  • In the BIOS (F2 when the Samsung logo shows), I disabled Secure Boot and Fast Boot, but kept EFI on, as Win8 won’t work without it. I also disabled (temporarily, with Shift+1) the HD and Windows Boot Manager from the boot sequence, moving USB boot up to first place.
  • After trying Ubuntu from the LiveUSB, I installed it. Once it had finished and rebooted, I re-enabled HD and Windows Boot Manager in the BIOS.
  • Ubuntu would work fine from here, but to restore Win8 to a usable (?) state, I had to reboot with the LiveUSB image and run Boot-Repair as suggested in the UEFI documentation.

The fan maybe runs a little more than it should, but everything I’ve tried works. There’s clearly been a lot of work done on Samsung/UEFI support recently, as any of the web tutorials I found from even 8 months ago recommended really arcane stuff I didn’t actually need.

(abstracted from my Reddit query: Linux-friendly future-proof MacBook replacement [13-15″, CA, $1600] : SuggestALaptop)

X10 home automation with Raspberry Pi: heyu

I never quite get the hang of setting timers for lights. Either I forget daylight savings completely, or I set something so general that I find the lights coming on mid-afternoon when it’s still light. Minor annoyances require the over-application of technology, and fast!

I scored an X10 ActiveHome Starter Kit for cheap(ish) on eBay. X10 is a pretty old technology (1970s! Scottish!) and has some severe limitations (slow! prone to interference! unencrypted!) but has a large user base, and did I mention it’s pretty cheap?

The key component of a computer controlled X10 system is the CM11 computer interface. It takes serial commands from a computer, and pushes them out (slowly) as signals modulated over your house wiring. Various plug-in modules pick up these signals, and if the device address in the command matches that of the module, the module turns on (or off, or dims).

Since the version of the CM11 interface that I have is serial, I’ll need a USB→Serial converter. All I had lying around was a very old Prolific PL2303 interface, which works fine with Raspbian, but I’d prefer an FTDI one for more reliability. Long-term stability of USB Serial on the Raspberry Pi is currently questionable; there’s some good discussion on kernel parameters that might help.

To send X10 commands from a Raspberry Pi (or indeed, any Linux computer) you need heyu. You have to build it from source, but the instructions are clear, and it takes about 10 minutes to build on a 256 MB Raspberry Pi. The install script asks you where your serial port is, and for my device it is /dev/ttyUSB0.

(Update: I re-imaged the Raspberry Pi that runs these tasks today and rebuilt heyu without success. Don’t assume you can do a ./configure; make; sudo make install here. You have to run heyu’s own ./Configure.sh first before make. It does some non-obvious magic. Read the README and you’ll be fine, unlike me …)

Most of the lights in our house are fluorescent, which is a problem for the standard X10 lamp modules. CFLs are not dimmable, and the standard lamp module doesn’t work with them. The lamp modules don’t work very well with low-voltage halogen lamps, either; extreme buzzing ensues, with a faint brownish light oozing out from the bulb and a vague burning smell. Best avoided, and better to use an appliance module, which is a simple mechanical relay.

The only controller that came with the kit that would work with my lights was the X10 transceiver, which also includes an appliance switch. I gave this device an address of H9 (house code H, unit code 9), and plugged in a lamp. To turn it on, I issued this command:

heyu on H9

After about 8-10 a couple of seconds and a loud CLUNK from the controller’s relay, the light came on (if it’s taking longer, read this comment). To turn it off, I told it:

heyu off H9

Whoa! Raw power! I can now turn AC devices on and off from my Raspberry Pi (Martin Creed, watch out!). I guess I could set up cron jobs to control the lights, but cron doesn’t know about solar time (Sunwait and SunCron do, if you want to futz with them). I’ve got MisterHouse running on the Raspberry Pi for more clever control, but more on setting that up later.

Incidentally, if you’re in Europe, Marmitek sell a variety of 220 V 50 Hz X10 modules. Their website is much clearer than the angry-fruit-salad that is x10.com. It looks like X10 have updated their starter kit to include the newer CM15 USB interface which will likely not work with heyu.

Sometimes, things do not go exactly as planned … C development for Amstrad CPC on Raspberry Pi

If you crash an Amstrad CPC, you often got some pretty patterns. Like the one above, which was supposed to print the alphabet, but got about as far as R, then started making coloured spots on the screen. My alphabet doesn’t (usually) contain coloured spots, so something went wrong.

This post is only about the Raspberry Pi in that it’s the nearest always-on Linux system that I have. This would likely work fine on any Linux machine. While the Z80 cross compiler I use (z88dk) is available in the repos, I can’t get it to build anything, so I just pulled down the latest version. To build the compiler:

wget http://nightly.z88dk.org/z88dk-latest.tgz
tar xvzf z88dk-latest.tgz
cd z88dk
export Z80_OZFILES=$(pwd)/lib/
export ZCCCFG=${Z80_OZFILES}config/
export PATH=${PATH}:$(pwd)/bin
./build.sh

This should result in a working environment. We can test it with a simple C program:

/* alfa.c - print the alphabet */
#include

int main(void) {
  char a='A';
  char b=26;
  while (b>0) {
    putchar(a);
    a++;
    b--;
  }
}

You can build it with:

zcc +cpc -create-app -make-app -O3 -unsigned -o alfa.bin alfa.c -lcpcfs -zorg=16384

You should end up with a file alpha.bin of approximately 4749 (!) bytes. You can copy it to a disc image using iDSK:

iDSK blank.dsk -i alfa.bin -c 4000 -e 4000 -t 1

It runs like this:

You can do the same with Z80 assembly language (shown here in the most gratuitously pretty Amstrad assembler, Maxam):
Although this results in only 11 bytes of code, it’s not portable; the C code above compiled and ran on both my Raspberry Pi and my Mac. It wouldn’t even run properly on a different Z80 system, as only the Amstrad CPC knows that call #bb5a prints the character in the A register. On the ZX Spectrum, for example, it was the completely different instruction rst 16 to print a character.

(There’s a lot more on z88dk on the CPCWiki.)

One year of amateur radio: what works

So I’ve just got my digital mode setup working again. It seems that somewhere, somehow, a driver for the SignaLink USB decided to stop working, and at best I got no signal on transmit and a very very quiet one on receive. Now my mind’s back in radio mode, I realise there’s a ton of stuff I’ve bought and found to be of variable utility. This is the good stuff:

  • Rigblaster Pro: this audio interface is far larger and far more expensive than it needs to be, but I got it used for a good price. Coupled with a $3 (!) USB sound card, it makes a sensitive and controllable sound device. I think I now prefer serial PTT-controlled audio interfaces to the SignaLink’s vox-style “Make a noise and I’ll transmit it” mode. It means you won’t accidentally tx system noises. That’s worth having another USB cable lurking about.
  • LDG autotuner: because of the wild and pointless diversity in radio interfacing, LDG makes a bunch of autotuners for specific radio models. Mine just works, and will tune my mini-G5RV from 10 to 80(ish) metres.
  • Big external meter: a cheap LDG meter is way better than the fiddly bar graph on the front of my FT-857D. I have it set up for signal on receive, and perhaps slightly unusually, AGC on transmit. Since I have a tuner and run almost entirely digital modes, it’s important that my signal doesn’t distort, so seeing AGC and being able to tweak it is important.
  • Heil Pro-Micro headset: this is comfy, and keeps the family sane. I have the footswitch too, which really helps to run nets.
  • Quarter-wave dual-bander HT antenna: The rubber ducks that all my HTs have are a bit rubbish. A simple replacement antenna allows me to talk through fairly distant repeaters from my sheltered back garden.
  • WinKeyer USB: I’m just starting morse. The WinKeyer kit was so well put together it was a delight to build, and seems to be an utterly sound keyer.
  • Fldigi: the digital mode program. Reliable, full-featured and free. It basically runs all the time on my shack computer.
  • Chirp: I can program all my HTs and my HF rig with this. It’s truly great, and miles better than proprietary programming software.
  • PSKReporter: a few minutes after calling CQ, I can see where in the world I’ve been heard. This automatic reverse-beaconing site is magic, and I’m amazed that a lot of digital users don’t even know it’s there.

My one annoyance about having a Linux-based shack is that ham radio is still very stuck in using serial ports. None of my computers have hard-wired RS232 ports, so I rely on USB serial adapters. These mostly work well, but Linux has a habit of shuffling the allocations around, so what was /dev/ttyUSB0 controlling your rig today might be ttyUSB1 tomorrow. You can get around this (if the software supports it) buy using long serial device names from /dev/serial/by-id/, which don’t change. They don’t change, that is, unless you have two Prolific serial interfaces that don’t have serial numbers set, so I can only have one attached at a time. Annoying.