ACI volume help tool

9 posts / 0 new
Last post
Offline
Last seen: 5 hours 34 min ago
Joined: Dec 10 2021 - 12:26
Posts: 21
ACI volume help tool

Since the volume of the audio seems to be critical for error-free tape reading, I would like to develop a specific tool for finding the optimal level. After discarding many other ideas, I came up with this candidate:

1) craft a "test" audio signal containing the following pattern of bytes: $FF $FF $FF $FF $FF $FE $00 $01 $02 $03 ... $1F $20, where:

- $FF is a much shorter version of the header 

- $FE is the last section of the header which contains the start bit (LSB = 0)

- $00 to $20 is a fixed data block

2) the test audio signal is sent to the ACI and repeated over and over in loop 

3) on the Apple1 a test program scans for at least 3 $FF bytes (24 long pulses)

4) once the $FF bytes are detected, the scanner waits for the start bit and read the next 32 bytes as in the normal ACI ROM read routine

5) after the data block is read it's compared with the reference and the index of the first unequal byte is output to display as a single character (0-9, A,B,C...). So the higher the character, the better the decoding. 

6) read next pattern in loop (goto 3)

 

The point is that the user can adjust the volume on the playback device (PC, smartphone, iPod etc) and have a quick feedback on the screen of what is going on.

 

What do you think about this method, do you have any suggestion?

 

 

 

 

 

 

 

 

Offline
Last seen: 15 hours 44 min ago
Joined: Apr 1 2020 - 16:46
Posts: 299
The volume tool proposal ...

... of nippur72 looks like a solution that would work. I used similar software tools to investigate the ACI and I found strange effects both with the LM311 and the 741 opamp based version. But in the end it turned out to be a sort of wild goose chase. Regardless what you do, and which circuit is used, the ACI only works under two conditions as far as the volume is concerned:

 

1. if the volume is too low, the comparator will not trip, and the readback software will hang

2. if the volume is too high, noises and "pops" etc. in the recording will produce fake transitions on the comparator output, ruining this bit, and from that point on, the whole readback is screwed up.

 

To help with adjusting the volume, I have developed and published the "volume LED fix" which can be seen in this thread:

 

https://www.applefritter.com/content/uncle-bernies-improved-apple-1-cassette-interface

 

which works like this: if the comparator output toggles, the flipflop can "see" that and makes a pulse which lights up the LED.

 

There is no reason why the same effect could not be achieved using software. But I would not just rely on insisting on correct readback of known data in a short loop. You should output some character once the output toggles. But do not wait for the terminal section to be ready in a loop.  You see a toggle, set a flag. Then if the flag is set, check the DSP ($D012) port to be PLUS (MSB cleared). If so, output the character and reset the flag, else continue conting cycles until there is a toggle on the TAPEIN.

 

The next possible refinement would be to discern the number of cycles "seen" between the toggles. If number of cyles is close enough (20 % ?) to the nominal "0" and "1" times, output a "*", else a '?'.

 

So the user would see the following: 

 

With volume too low for a toggle, nothing happens. Volume increase will produce characters but with many '?' for "wrong timing". Further increase would produce '*' with no '?'. Further volume increase would again produce some '?'  again: too loud (if you can get there. With an iPOD not so likely but with a noisy cassette recorder, yes, you can get there).

 

Such a tool would certainly help. Note that it's also possible to get strange byte values from the TAPEIN other than $D0 and $FA. This happens when the comparator toggles at inopportune times and the data setup and hold times for the 6502 are not met. With the LM311 this event is rare and it seems not to affect the readback, but with the slower 741 it happens more often and I had to use the 2nd flipflop as a synchronizer between the 741 output and the pin #1 input of the 7410 to make that version work with the original ACI firmware.

 

This rabbit hole goes deeper than you think.

 

Comments invited !

Offline
Last seen: 5 hours 34 min ago
Joined: Dec 10 2021 - 12:26
Posts: 21
ok, I coded the tapemon

ok, I coded the tapemon utility I described in my post, you can find it here (both sources and binaries): 

https://github.com/nippur72/apple1-videocard-lib/tree/main/demos/tapemon

I simply copied the read routine from the ACI ROM making it load 64 bytes of data (the size of my test data packets). The only difference is the header detection: before the start bit I require 24 full cycles of long pulses (corresponding to 3 bytes of $FF) ; that makes header synchronization very fast.

Once a data packet is acquired, a character is displayed ('*' =  good, '.' = nothing, 0-F = partially received).

Data packets are played using a .WAV file that I created for the purpose.

Anyway, as Uncle Bernie said, volume on the ACI mostly shows two behaviours: "none" or "ok" with no in between values. So in this sense there is not much use of comparing the data packets with the reference. 

 

Regarding the possible improvement by couting the length of the cycles, I did a similar thing for another 8 bit computer; but there I had a graphic display where to plot the results. When plotted on a graph, the cycles for "0" and "1" create two bell-shaped curves. The more the two curves are separated, the better the quality of the signal. But since we can't plot on the apple-1 for a quick visual feedback, we could make some measurements (e.g. standard deviation) and display the numbers at regular intervals. Yeah, it's a rabbit hole. 

 

 

 

 

Offline
Last seen: 5 hours 34 min ago
Joined: Dec 10 2021 - 12:26
Posts: 21
UncleBernie wrote:You should

UncleBernie wrote:

You should output some character once the output toggles. But do not wait for the terminal section to be ready in a loop.  You see a toggle, set a flag. Then if the flag is set, check the DSP ($D012) port to be PLUS (MSB cleared). If so, output the character and reset the flag, else continue conting cycles until there is a toggle on the TAPEIN.

 

Interesting idea to explore, here's the code I wrote that implements the above logic:

 

simple_monitor:   lda TAPEIN               ; read tape input

                  cmp LASTSTATE            ; compare to previous state

                  beq no_toggle            ; if same just skip

                  sta LASTSTATE            ; else save new state

                  ldx #35                  ; set "toggle detected" flag in X, 35 is also the char to print

no_toggle:        bit DSP                  ; check if display is ready to accept a character

                  bmi simple_monitor       ; if not, just keep reading tape

                  stx DSP                  ; else display the "toggle detected" flag character

                  ldx #45                  ; resets the "toggle detected" flag to the "-" sign, sets also Z=0 flag

                  bne simple_monitor       ; cheap jump because Z is also 0

 

The program has the benefit of being only 24 bytes long, so it can be still typed in the monitor if one has ACI issues and can't load any program from tape.

0280: AD 81 C0 C5 29 F0 04 85 29 A2 23 2C 12 D0 30 F0 0290: 8E 12 D0 A2 2D D0 E9 60 

 

When compared to the "packet detector" of my previous post, it seems to be more sensitive, the toggle is detected at volume levels where a data read do fail, so that makes the "packet" technique still useful. 

 

 

 

Offline
Last seen: 15 hours 44 min ago
Joined: Apr 1 2020 - 16:46
Posts: 299
About the toggle detector from post #4:

Good work, nippur72, this seems to be a sort of minimalistic solution which does exactly the same thing as my "volume indicator LED fix"

 

The only flaw in your program I can see is the character codes having no MSB set (add 128 decimal). The Apple-1 does not care about the MSB but everywhere in Woz' code you see that he keeps ASCII codes with MSB set so somehow this is setting a programming standard probably worth to follow. Makes no sense ? Well, any (hypothetical) future emulator or replica, if it wants to extend the character set, must use MSB = 0 for that extended character set, such that the legacy software which runs on the Apple-1 and uses MSB = 1 would still work fine. Always keep the back door open ...

 

The "sensitivity issue" you describe is not a problem at all. The "volume indicator LED fix" behaves exactly like your software:

 

If volume is too low, no toggles are seen. Good. Now slowly dial up the volume and if you are slow enough you can find a zone where the LED just gives a blip now an then. These are spikes in the signal which otherwise is below the hysteresis threshold of the comparator. Just a little bit more will make the LED glow dark. More of the signal toggles the comparator. But still not enough. If you slowly increase the volume further, there is a point where the LED brightness does not increase anymore. Almost all of the signal above the threshold, but expect occasional spikes to reduce the signal below that threshold (load would fail). The correct volume setting for good readback performace is just a tad above that point. If your volume knob has markers, or numbers, go one marker or number above the one where the LED brightness did not increase anymore. Note that human ears have a logarithmic gain compression so they use logarithmic volume potentiometers. That one marker more increases the signal amplitude much more than if it were linear. 

 

These are the rules for the use of the fixed volume LED circuit. You could derive similar rules for your software system. But you just could decrease the recording volume of the test tone such that a  "toggle" indication means that this volume setting is correct for playback of AIFF or WAF files using a regular recording.

 

In the end we should establish some form of "standard" for the volume in AIFF or WAV files (to be more exact, the amplitude) such that all media players could provide enough volume for ACI readback. I have struggled a lot (over months) to get it right and many experiments were needed (thanks to my beta testers !) because it seems that every media player is different. You can't be too loud either, because this causes weird effects in some players (despite having more amplitude in the AIFF, the playback is much less loud that the AIFF with less amplitude). Some people have suspected this is due to some built-in limiter to protect hearing of the user. Could be.

 

I've seen weird things when recording from ACI outputs, too, the amplitude as seen by AUDACITY suddenly drops massively a short way into the header tone. This is not AUDACITY causing that. It's somewhere in the signal chain from the MIC input to the software port where AUDACITY plugs in. And it can't be some AGC function because any AGC is supposed to adjust slowly, and not that abruptly.

 

Within our modern computers, strange things go on which nobody can explain. Would you fly to the moon relying on such a modern computer with your life ? Me, no thank you. This is why I also refuse to fly airplanes with "glass cockpits". "Steam gauges" is what I want.

 

Offline
Last seen: 5 hours 34 min ago
Joined: Dec 10 2021 - 12:26
Posts: 21
UncleBernie wrote:In the end

UncleBernie wrote:

In the end we should establish some form of "standard" for the volume in AIFF or WAV files (to be more exact, the amplitude) such that all media players could provide enough volume for ACI readback. 

In all my WAV converters I always use 75% of the amplitude, and I've seen that also your .aiff files have a similar level (is it 78 perhaps?), so we can agree on that.

 

UncleBernie also wrote:

I can see is the character codes having no MSB set (add 128 decimal). The Apple-1 does not care about the MSB but everywhere in Woz' code you see that he keeps ASCII codes with MSB set so somehow this is setting a programming standard probably worth to follow.

I've to check my C compiler how to remap strings to a different ASCII set, anyway that has the drawback that you can't quickly inspect a binary file with a hex dump. 

 

 

 

 

 

 

 

Offline
Last seen: 15 hours 44 min ago
Joined: Apr 1 2020 - 16:46
Posts: 299
In post #6, nippur72 wrote:

"I've to check my C compiler how to remap strings to a different ASCII set"

 

Uncle Bernie now is confused.

 

Did you really mean "C Compiler" or did you mean a 6502 assembler ?

 

AFAIK there is no C compiler targeting the Apple-1. If you know one, please tell me. Most 6502 C compilers I know of produce very inefficient code. The 6502 is a perfectly fine processor, but it has no support for C stack frames, so the code for function ENTRY and EXIT gets extremely clumsy and inefficient. This applies to all vintage 8-bit processors. I've seen some C compilers (such like KEIL's) which are able to do global variable allocation so most of the variables can be accessed directly from memory and do not need to reside in stack frames. The C compiler for the PIC processors which are even more limited uses the same technique, but forget using recursion on any of these CPUs when using a C compiler. Still, I'm interested just in case you found a "good" one.

 

I write all my programs for the Apple-1 in 6502 assembler, using ATASM, which is open source and compiles and runs under Linux, too. It supports various ways to generate modified ASCII strings, you can tell it to add a constant (for Apple-1: $80) to all characters in a string. Or to invert the MSB or all or only the last character of a string. 

 

 For single characters like in your above code snippet, I use a construct like LDA #$80+'C  where the character C is first represented in ASCII and then the $80 is added.

 

I think it's important to use characters with a set MSB on the Apple-1, just to leave the "back door" to an extended character set open.

Offline
Last seen: 5 hours 34 min ago
Joined: Dec 10 2021 - 12:26
Posts: 21
C compiler

The C compiler is called KickC, I've discovered it only recently for my Apple-I experiments. Before, I used "cc65" but I wasn't happy with the quality of the code it produced, so I looked around and found KickC. And never turned back since then!

 

KickC uses the trick of global variable allocations at the cost of writing non re-entrant code (who needs it on a 8 bit cpu after all?). That makes a big difference, function parameters get a fixed address in memory (often in ZP) and reading them is just a single instruction. KickC does also a lot of very advanced optimizations, and the resulting code is very similar to hand written assembly. Another advantage is that it doesn't link  extra stuff (library or initialzation code). So I higly recommed KickC.

 

But there are some cons:

1) it's not 100% standard so you have to get used to it; but the non-standard features are usually for the good

2) it's beta version, meaning that it really has bugs, and sometimes you have to make workarounds to avoid them. But the author is active and constantly fixing the issues that are submitted on the Gitlab repo.

3) it does not directly produce code for the Apple-1 yet, it needs a "target configuration file". Anyway I've already written such configuration file, so it's no longer an issue. If you browse the apple1-videocard-lib you'll find the one I used to compile the demos (Tetris, etc). In the repository I'm also keeping a small C library for the apple1 (look for "apple1.h").

 

For the different ASCII character encodings, KickC has this feature but it doesn't have the specific encoding for Apple-1 yet (but I guess the author could add it very easily).

 

As regards the 6502 assembler, my choice is DASM, but for large projects I don't write directly in assembly, I instead use a compiler/transpiler of my own that lets me write structured code. For example I can write something like this

ldy #8

do

   lda $200,y

   if zero then 

      ldx #0

   else

      ldx #1

   end if

   dey  

loop while not zero

 

without the burden of manually writing branches and labels. The resulting source code is very clean and readable and still translated 1:1 to assembly. One example is a Go-moku game I wrote for the Commodore VIC-20 (which I might port to the Apple-I -- is there already a such game?) 

 

 

Offline
Last seen: 5 hours 34 min ago
Joined: Dec 10 2021 - 12:26
Posts: 21
duty cycle

There is another metric that might be helpful when dealing with volume issues. I noticed that when you increase the volume, the square pulse of the signal tends to change its duty cycle. For example a too low or too high volume may result in a imbalanced duty cyle of 25%/75%. Assuming that the optimal zone is 50/50, I wrote a small program that measures the length of 512 consecutive hi-lo phases of a pilot tone; then it makes an average and show the result on the screen at regular intervals. This way the user can adjust the volume setting until the duty is close to 50%/50%. 

 

 

 

Log in or register to post comments