Recently I got my first MiniDisc Walkman at a local Goodwill. It's a Sony MZ-R37, and it is an absolutely gorgeous machine. Most of the recorder is built with aluminum, and the disc loading mechanism is simply too fun to play with.
However, since the machine was released at 1999, it is one of the older MiniDisc recorders, and does not have the fancy capabilities some later models have, like NetMD, MDLP, and Hi-MD. So, the best way to put music onto a disc is limited to use a good old Optical In port. If you are not familiar with MiniDisc recorders, they usually have a Line In port that can accept both an analog input (which is our old friend, 3.5mm Stereo Mini Jack) and a Mini TOSLINK connection.
So, I grabbed a TOSLINK to Mini TOSLINK cable, and connect it to my computer's Optical Out port. Then, it is as simple as letting MPD to use the Optical Out, and then play the desired songs. Everything just works.
Until it doesn't! When transferring audio from a CD player, the player will send a marker when each song ends, so the MiniDisc player can automatically add a marker when each song ends. However, all the players I tried does not have this feature, which makes sense, since MiniDisc is pretty much obsolete now.
First attempt: A simple bash script!
When messing around
alsamixer, I discovered that ALSA will completely cut the optical stream when the S/PDIF output is set to
mute (which means, the light on the output will not shine at all). My specific recorder consider this as a
NO SIGNAL situation, and will stop recording. When the recording resumes, it would add a new track marker to where the new streams comes in.
So, in theory, we can abuse this behavior to add track maker for each song we record. At first, I decided to use
mpv, since it almost guarantee to work.
This seems to work, as I can see the track number bumping on the front LCD.
However, when I play it back, there is an issue: there's a very brief blank track between each song. This is due to the fack that
mpv closes the audio interface before we unmute the output. And since a digital signal, the recorder successfully capture the very brief second before line 11 and 12, and add a blank track.
Second attempt: Hack
<div class="card info"> <div class="header"> <div class="symbol"><svg xmlns='http://www.w3.org/2000/svg' class='ionicon' viewBox='0 0 512 512'><title>Information Circle</title><path d='M248 64C146.39 64 64 146.39 64 248s82.39 184 184 184 184-82.39 184-184S349.61 64 248 64z' fill='none' stroke='currentColor' stroke-miterlimit='10' stroke-width='32'/><path fill='none' stroke='currentColor' stroke-linecap='round' stroke-linejoin='round' stroke-width='32' d='M220 220h32v116'/><path fill='none' stroke='currentColor' stroke-linecap='round' stroke-miterlimit='10' stroke-width='32' d='M208 340h88'/><path d='M248 130a26 26 0 1026 26 26 26 0 00-26-26z'/></svg></div> <span>info</span> </div> <div class="content">
If you want to use the method here, don't forget to adjust the commands accordingly so that it fits your sound card. You can find information via executing
amixer -c CARD_ID.
So, I have to find a way to mute the sound output just before the audio stream is closed. The best way would be to find a simple command line audio player with the minimal number of code, since I don't want to view a huge codebase and potentially mess everything up. Fortunately, there's a program called
ogg123, created by the awesome lads at Xiph.org Foundation1. This is a very basic audio player, which is desirable for this project.
After grabbing a copy of vorbis-tools (which contains
ogg123), we can take a look. The main sound output codes are located at
ogg123/audio.c. And surely, there is a function called
void free_audio_devices. All we have to do should be add some codes to mute the output before the free process actually begins.
I can do it cleanly by using the user space library for
ALSA, but that means I may have to investigate a good amount of hours into learning, and I'm kinda busy. So nah, I just hacked it.
Since we already know how to use
amixer to mute the command, we can just use
system() function (provided by
stdlib.h) to execute a shell command. It is not expandable and flexible AT ALL, but it works and it does not kill my brain cells.
free_audio_devices looks like this now:
Then we can trigger
make and compile the patched code. Since I don't want to use this version globally, I did not install it.
Then the updated script should look like this:
ogg123 is responsible to mute the output, we can save a line here.
And now it works! No more additional empty tracks, only accurate track data.
File format conversion: make life easier.
So the recording process is way easier. No more manual operation, eh?
Well, if all your music is in CD quality (or less), just like in the 90s, that's it. However, for more advanced music format (like DSD and FLAC with higer bit rate), the MiniDisc recorder will be confused about the crazy burst of data, and won't record them at all.
So, we still have to somehow downsample the audio file. Luckily, that can also be automated too. I just used
ffmpeg to convert the audio sample to 16bit, 48000Hz (which is probably the best quality the little recorder can accept). Since the script has become pretty long, I won't quote it here. You can find the exact script I use at here.
And that's it! Now, we can create an awesome MiniDisc mix tape with the correct track marker easily with a command. The only drawback for now is that the track name is still lacking, but it is not a huge deal for me.
Enjoy your music!