Measures the time between zero-crossings coming from the cassette, and leaves a list of these timings in memory. This lets you see what is on a cassette tape exactly the way the BASIC ROMs see it.
Loads into addresses $3000 through $3062 inclusive, starts execution at address $3000.
This program watches the cassette port, times how long each half-cycle of the sine wave signal takes, and saves these times in a list in memory. The list starts at $4000, and each time is a two-byte integer. The end of a sine wave's half cycle is recognized by watching for zero-crossings; when the signal changes from positive to negative or vice-versa. When it it finds the end of each half-cycle, it increments the character at the bottom-left corner of the screen so you can see that it is doing something.
Normally, a '1' bit is a full cycle of a sine wave at 2400 Hz, which means two times in the range of $0007 to $0009. A '0' bit is a full cycle of a sine wave at 1200 Hz, which means two times in the range of $000D to $0010.
I am not yet sure if there is really that much variation in the lengths of the recorded sine waves, or if it is an artifact of the measurement loop. That loop only samples the input every so often, so there is some inherent inaccuracy in its measurements. And my cassette recorder is a cheapo, so it could be distorting the signal a little bit.
Sometimes the first half-cycle of the first bit of a byte is much longer than it should be. One place where this happens is in the first byte of a block after a leader. It seems BASIC sometimes leaves the tape running for a few hundred microseconds between bytes, and it gets recorded as part of the next bit. Maybe it uses different subroutines to write the different parts, and wastes some time between them doing 'RTS' and 'JSR'? Anyway, this does not seem to bother it when reading the tape back. Maybe after getting into bit-synch, it knows to only look at the length of the second half of each bit to decide if it was a zero or a one?
If the input signal is not a sine wave in the expected frequency range, such as in the gap between blocks, the counter measuring the time between zero-crossings can overflow. If this happens, a time of $FFFF is added to the list, the counter is reset to 0, and it continues waiting for a zero-crossing. It takes approximately four seconds with no zero-crossings for the counter to overflow this way.
The program terminates either when its buffer is full, or when it has run into 30 overflows. After it terminates, you can examine memory to see what was on the tape.
This program is relocatable, but its data (at locations $3100 through $3105 inclusive) and the buffer that it will fill with timing measurements (at $4000 through $7FFF) are considered to be external to the program, so even after relocating it, it will still use the same addresses for those things. (So you don't want the program to cover any of those.)