Log in

Mar. 16th, 2008



Fixed some code regressions...

When I was cleaning up the code there were a few regressions, which caused improper PCM audio to be generated. I only picked it up recently.

Sufficed to say it has been fixed. Also, a Mac OS X DMG file containing pre-compiled binaries is now available from the the download page on sourceforge.

There is actually a make target for dmg now, so one can do this: -

> make
> make dmg

You will end up with a nice fluffy DMG file under the "pkg" subdirectory. Enjoy.

Tags: ,

Mar. 10th, 2008



Converting Audio to TAP files.

Well I did some work yesterday on the preliminaries of converting audio back into TAP files, using a process of quantization and sample counts, which gives back the original pulse lengths from the audio data.

So far, so good, with an emulator able to reload a reference audio file that I converted back to TAP. I use VICE for Mac OS X, for testing, as it is a good all-round emulator. It also allows me to save programs to TAP files, which I can then convert through tapdancer and load into the real machine for testing.

The converter code is in its infancy, but seems to be usable.

Tags: , ,

Mar. 4th, 2008



(no subject)

I started writing a more generic representation of a Tape file. It is needed for when I start the mamoth task of supporting the Spectrum TZX format. It is a great deal more complicated than the Commodore TAP format. But, by basing them off a common route class it will allow a more standardized interface for manipulating the files.
Each basically consists of a Header (of variable size and content), and a Data Block which contains the actual digital representation of tape signals.
TGenTapeFile is the top level container class.


Are you little or big (endian)?

I transferred the code onto to our PowerPC based Mac Mini last night and it compiled first time... it was however a shame that it didn't actually work.

Welcome to the world of endianess... where depending on whether or not you are putting some intel employees kids though college or not, or IBM kids, your lovely Pascal code might compile, but totally fail to do what it was supposed to.

The problem was, that I developed this on a PC, and moved the code to PowerPC based mac. Pascal is a wonderfully optimized language, down to the point where it uses the byte ordering of the CPU to represent words, integers and longwords. This is fine, except when you write code that is intended to be cross-platform. In that case, you need to ensure that when it compiles, it reads and writes the data to and from files in the correct way...

A LongWord is 4 bytes. On a Big Endian system, the most significant byte (MSB) is first in memory, and on a little endian system (ie. Intel based), the LSB (least significant byte) is written first. Now, if I ask the system to read a longword from a file stream, you see that this might present problems.

The solution, at least on FreePascal are some handy defines the compiler gives you...

Either ENDIAN_LITTLE, or ENDIAN_BIG will be defined, depending on the target architecture you are compiling for. My solution was to create some functions that would compile differently based on what the target system was. I created a unit called "Endian" which provides four functions...

function endianLittleLong( l: longword ): longword;
function endianLittleWord( w: word ): word;
function endianBigLong( l: longword ): longword;
function endianBigWord( w: word ): word;

So, if a value we read from a file is supposed to be a Little Endian LongWord value, we would wrap the access in endianLittleLong(). On a little endian system, this does nothing except return the value as is, but thanks to the wonders of conditional compilation, this same function will reverse the byte ordering of the LongWord on a BigEndian system.

After doing this, everything worked on PowerPC. Theoretically now, the same code should compile on Windows as well, and act correctly there as well.

Long story short (no pun intended), I have tested and run tapdancer on a PowerPC Mac and it runs fine. A little quicker than my Windows 2000 machine (but that is a Pentium II).



Impossible Mission

Remember last post I was curious about how the encoding would handle finicky loaders that use a very short pulse width?

These files, typically games with "US Gold" block loaders (or NovaLoad) when encoded by another program (I won't name names), hadn't had much success loading, as at some arbitrary point, the computer finds a glitch on the tape, or misses a pulse, and then resets. Anyone who has ever had one on these tapes on a less-than-perfect datasette will know exactly what I am talking about.

I encoded "Impossible Mission" last night in a batch of test games (by accident funnily enough), and it loaded. As the block counter crept towards zero, I kept wondering if it was going to glitch somehow, and yet it didn't. The game loaded perfectly first time. Bearing in mind that this same game seems impossible to load on the same equipment encoded with another program, I am pretty happy with the results so far.

Probably next weekend I will think about starting to write the decoder which will actually convert the analog audio back into TAP files, as the conversion only works one way so far...



It works...

I produced AU Files from TAPs that actually read properly into the real computer. There were some accuracy issues with the calculations that converted from TAP bytes to machine cycles to durations (in uS) and then finally to the number of samples needed per square wave. We converted about 20 TAP files and produced an audio CD, which we then loaded into the real machine by way of a CD cassette adaptor.

The interesting thing will be to see how it behaves when it comes to things like US Gold loaders, which use very compressed pulse widths in order to fast load off tape.

The next step will involve setting up DEV tools on our mac, installing freepascal there and then compiling a Mac PPC version.
Tags: , ,


About the commodore TAP format...

The TAP format was created for the Commodore 64 Emulator CCS64 (link) by Per Hakan Sundell, as a means of representing the audio pulses on a commodore tape. These pulses represent square waves, with a one to one mark spacing, which essentially means, that the pulse spends as much time "up", as it does "down".

A TAP file contains a simple header, followed by a series of bytes representing these pulse widths. These values represent the pulse widths in microseconds (millionths of a second), and are calculated by the following formula: -

TAP data byte = P(uS) * (1/1000000) * (F(Hz)/8)

Where P = length of pulse in microseconds, and F = PAL Frequency of the C64 (985248Hz).

Sometimes the measured pulses are longer than 255*8 machine cycles, and in that case, we instead encode a zero byte, followed by another byte (which represents the overflow). In the most recent version of the TAP format, we still use zero to flag overflow, by follow it with a 24 bit number (3 bytes) which gives the actual length of the long pulse in machine cycles.

The beauty of this format is that it preserves everything within it. Load a TAP file into an emulator, and you will see the original loading screens, music, and yes, if you run your emulator at 100% speed, it will take 5-6 minutes to load!

I guess just to finish here, I should document the actual TAP header format, as there are scarce few places where it is documented online: -

Offset        Size         Description
0             12 bytes     File ID. 'C64-TAPE-RAW'
12            1 byte       Version (0 or 1 so far)
13            3 bytes      Reserved for future use (usually zeros)
16            4 bytes      Data length (Longword - Intel endianess)


Welcome to the Tap Dancer Project

I've started this journal to document creation of Tapdancer.

Tapdancer will be a cross platform utility for managing Commodore 64 (and eventually ZX Spectrum) tape emulation files. There are already a few utilities available, but hardly any for Mac OS X, and very few that allow any kind of batch conversion of tape files.

These tape files store a representation of a series of audio pulses, which is how Commodore machines load off tape. The tape contains a series of square wave pulses of varying frequencies, which when combined, represent the bits (1's and 0's) of the stored program.

It is possible to convert these digital representations back into analog signals on tape, which is one of the jobs that Tap Dancer will perform. With a bit of fiddling, a car-audio cassette adaptor, a CD player, it is possible to load these images back onto an original C=64 or C=128, or of course, you could take the more obvious route, and just record them onto tape, and hey presto - you have software!

At this stage, the project is at the proof of concept stage of things...

I'm writing this in Object Pascal, because I think it is a wonderfully clean language which is still close enough to the actual machine / operating system to be useful.

At this stage I have created two main classes: - TTapeFile, which represents one of these emulator tape files, and TAUFile, which represents the SUN / Next AU audio file format. TTapeFile is already capable of loading, checking and performing some basic work on the TAP files, and TAUFile can now write 8/16/24/32 bit linear PCM files, which will serve as a conversion target for these tape images. I chose the AU format, because it has a very simple header structure, unlike something like the RIFF-WAVE format, which erm... just doesn't. Plus, AU files are very Mac/Unix friendly. I was looking at AIFF, but at this stage I think I'll wait on that one, since anyone can convert AU files to almost any format. (Just Google SoX)

So far, I can convert a TAP file into an AU file, but they are not playing as nicely with the real machine as I would like.