Tool for digitalized retro computer cassettes
bzt d71448c3f5 Better decoding when there's no sync bit | hace 1 año | |
---|---|---|
examples | hace 1 año | |
libmp3lame | hace 1 año | |
public | hace 1 año | |
.gitlab-ci.yml | hace 1 año | |
LICENSE | hace 1 año | |
Makefile | hace 1 año | |
README.md | hace 1 año | |
decode.c | hace 1 año | |
encode.c | hace 1 año | |
main.c | hace 1 año | |
minimp3.h | hace 1 año | |
wav.h | hace 1 año |
This is a quick'n'dirty tool that can convert digitialized retro computer cassettes (C64, Spectrum, Homelab etc.) into binary files and vice versa.
Available as a CLI tool and as a webservice.
Just run make
, no dependencies (other than libc). Type make wasm
to compile the WebAssembly version (requires emscripten).
Cassette by bzt GPLv3+
https://gitlab.com/bztsrc/cassette
./cassette [opts|-s] <in.wav|in.mp3> <out.bin>
./cassette [opts] <in.bin> <out.wav>
./cassette [opts|-b|-q] <in.bin> <out.mp3>
-v | -vv be verbose
Data encoding options
-e endianess, least significant bit comes first
-7 assume 7 bits per byte on the tape
-0 no sync bit (default, 0 = 0, 1 = 1)
-1 two bits, first is sync bit (10 = 0, 11 = 1)
-2 two bits, second is sync bit (01 = 0, 11 = 1)
-3 three bits, two sync bits (101 = 0, 111 = 1)
-d FM, frequency modulated, down-edge (defaults to AM)
-u FM, frequency modulated, up-edge
-du FM, frequency modulated, both edges
Sample encoding options
-h do not detect but generate Homelab header
-s input is signed 8-bit PCM
-S <n> skip N samples at the beginning
-l <usec> one bit's length in microsec (eg. 770)
-g <usec> gap between bytes (AM) or diff in zero and one lengths (FM)
-r <rate> sample rate (eg. 44100 or 48000)
-o <num> bit set level (eg. 127)
-z <num> bit clear level (eg. -32)
MP3 encoding options
-b <bitrate> bit rate (eg. 96, 128 or 192)
-q <quality> quality (0 best, 9 worst)
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
To extract binary data from a digitalized cassette audio file (where 8 bits make up a byte and most significant bit comes first), just use
./cassette audio.mp3 image.bin
If the old computer have used 7 bits in a byte, then
./cassette -7 audio.mp3 image.bin
If the least significant bits were stored first on the tape, then you can change endianess with
./cassette -e audio.mp3 image.bin
Or you can combine the two:
./cassette -e7 audio.mp3 image.bin
Normally the length (how many samples make up a bit) is autodetected by examining the up-edges. If this fails for whatever reason, then you can specify manually with
./cassette -l 10 audio.mp3 image.bin
This would assume that two consecutive set bits have a down to up edge at 10 μsec distance.
| ___ ___ ___
| | | | | |
| | | | | |
+--|---|-|---|-----|---
| _| |_| |_____|
| . .
| .<--->. 10 μsec
For frequency modulation, -l
overrides the calculated average distance, and acts as the distance treshold length.
Normally all input PCM should have signed samples. However due to some f*ck up by Microsoft, WAVE files storing 8-bit PCM data are
tend to store unsigned samples (Audacity saves unsigned 8-bit samples too). This is taken care of, but you might run into a 8-bit
WAVE file that actually uses signed samples, just like the 16-bit variant. Use the -s
flag in this case, to avoid unsigned
to signed sample conversion.
Otherwise the WAVE reader is quite flexible, it supports 8-bit, 16-bit, 24-bit, 32-bit integer and float sample formats, with any number of channels (those would be converted to mono automatically). Additional and unknown chunks are also considered.
For MP3 decoding, Cassette uses minimp3.h (included).
The other direction works as
./cassette image.bin audio.wav
This reads in image.bin
, and creates an audio file that you can use with the vintage computer (or emulator).
You can also set the endianess and number of bits in a byte with -e
and -7
here too, respectively. The length of one bit
defaults to a duration that results in 4 samples (depending on the frequency), but you can set it with -l
in microsec. Normally
1/4 of that duration is used to encode the bit's value, and 3/4 at the end is always zero, so that up-edges can be detected
correctly. You can also set the bit is set level (one) between 127 and -127 with -o
and bit is cleared level (zero) with -z
like
./cassette -l 771 -o 127 -z 0 image.bin audio.wav
Note that encoding with MP3 introduces a significant noise which might cause trouble. To avoid this, set bit level defaults to 127
and cleared bit level defaults to -64, so that all the noise fluctuations will be in the negative range, and only true one values
will be positive. You can also set the sample rate with -r
, used to calculate how many samples -l
and -g
durations mean.
To save in MP3 format (uses LAME, also included), just use a filename that ends in .mp3
:
./cassette image.bin audio.mp3
In this case you can also specify the bitrate (defaults to 96) and the quality (defaults to 0, best). For example
./cassette -b 192 -q 5 image.bin audio.mp3
Please note that MP3 is particularly inadequate for this job; it's not just the lossy compression and the added noise, but also because of poor design. Its codec introduces a mandatory silence at the beginning and at the end of the samples, however there's no standard way to tell how much silence has been added. Cassette generates the Xing header for this purpose when it creates MP3 files, which is quite common, but not guaranteed to be recognized by all software. You could also run into trouble if you try to decode an MP3 audio file with Cassette which doesn't have a Xing header. Better to stick with WAVE files if you run into trouble. (No, opening in Audacity won't solve your problem, because Audacity does not trim the MP3 samples, so you will always actually see that codec introduced silence.)
This is the default, no flags. Samples are taken at regular intervals (see the red dots above at equal distances). The interval is
autodetected by examining the up-edges, but you can specify it with -l
. If the given sample at one of the specified time is
below the base line, then it encodes a 0 bit. If it's above the base line, then it encodes a 1 bit. (The wave is normalized,
so it doesn't matter what the actual base line is. Cassette will take care of this for you).
Using -d
, you can set up frequency modulation with down-edge. Here samples are taken when the wave crosses the base line from
above. As you can see, the distances between the red dots aren't regular this time. All distances considered and their average is
taken (or you can specify with -l
). If a particular distance is shorter than the average, then it encodes a 0 bit. If it's
longer than the average, then a 1 bit. When the wave is generated, you can set the length of the 0 bit with -l
, and 1 bit will
be 3 / 4 longer. If this does not suit you, then you can explicitly set how many microsecs longer 1 should be with the -g
flag
(two samples at least).
Using -u
, you can set up frequency modulation with up-edge. Same as the previous, except samples are taken when the wave crosses
the base line from below. Similarly distance average taken, and shorter distance means 0 bit, longer distance means 1 bit.
Using -du
, you can set up frequency modulation with both edges. Same as the previous two, but here samples are taken whenever the
wave crosses the base line no matter the direction. Just like the previous two, distance average taken (or you can set it explicitly
with -l
), and shorter distance means 0 bit, longer distance means 1 bit.
By default all decoded bits are handled as data bits. Using -1
you can tell that each data bit is prefixed by a sync bit, -2
tells the sync bit follows the data bit, and -3
means the data bit is surrounded by two sync bits.
Cassette is Free and Open Source Software, licensed under the terms of GPL version 3 or (at your opinion) any later version.
Cheers, bzt