Download
trsvid.zip

trsvid - A video player for TRS-80 Model 1, 3 and 4

Here's a video of trsvid in action:
What you see there is 60 frame per second, full-screen video. Well, on the Model 4. The Model III manages just over 54 frames/second and the Model I just over 51 frames/second. What you hear is about 15 Khz audio with effectively 5 or 6 bits per sample.

Choose Your Adventure

While there's nothing wrong with reading this page straight through, there's a lot to cover. If you've got something particular in mind here's a handy list of places to jump ahead.

More Videos

Model 3 playing A-ha's "Take On Me". By way of a compliment YouTube has muted the audio because they think it sounds like the original. How high is trsvid's fidelity? Enough to be considered copyright infringement!
Model 3 playing the intro sequence to "Doctor Who" (the 4th Doctor). Yeah, it's the same one I did from floppy disk, but on the Model 3 instead of the 4P.
Model 3 playing The Pogue's "Fairytale of New York".

Sorry, no video! Amazingly YouTube considered it too similar in audio and video to the original and blocked it. Banned in every country. Scroll down and watch the Model I version which is about the same. I think it got flagged because I had the Model 3 filling most of the frame.

Model 3 playing a Radio Shack TV ad for its successor the Model 4.
Model 3 playing the classic intro sequence to "The Six Million Dollar Man".
Model 4P playing A-ha's "Take On Me". No audio because YouTube muted it for being a copyright violation.
Model 4P playing the intro sequence to "Doctor Who" (the 4th Doctor). Yeah, it's the same one I did from floppy disk.
Same as above but the 4P is playing the Model I version.
Model 4P playing The Pogue's "Fairytale of New York". Another victory for fidelity; they'll let me play it but they get all the money. Bad deal for them because I wasn't getting any money. Except they'll probably put an ad into it so the joke's on me.
Model 4P playing a Radio Shack TV ad for the Model 4.
Same as above but with the ad encoded in ".tv1" format for the Model I.
Model 4P playing the classic intro sequence to "The Six Million Dollar Man".
Same as above but the ".tv1" version on the Model 4P.
Model I playing A-ha's "Take On Me". Once again, muted for sounding too good.
Model I playing the intro sequence to "Doctor Who" (the 4th Doctor). Yeah, it's the same one I did from floppy disk, but on the Model I instead of the 4P.
Model I playing The Pogue's "Fairytale of New York". As before, it sounded so nice they put an ad on it.
Model I playing a Radio Shack TV ad for its grandchild the Model 4.
Model I playing the classic intro sequence to "The Six Million Dollar Man".

User Manual

While getting a TRS-80 set up to play videos is not easy, trsvid itself is simple to use. It auto-detects your hardware so there's only one version of the program to download.

If a FreHD hard drive emulator is not attached it will print a message to that effect and also list what video file formats your TRS-80 can play: .tv1 and/or .tv3 and/or .tv6. If you have a FreHD but without the enhanced firmware then you'll still be able to browse the SD card for video files and see the preview images, you just won't be able to play any of them.

Once trsvid/cmd is running you can use the up and down arrow keys to select from a list of files in the current directory which is displayed on the top status line. Notice the right-angle bracket ">" which denotes the current selection. When a video file is selected trsvid will automatically display the preview image in the main window and the title of the video and playing time in the status line.

Model I users will notice black bars on the screen when a video preview is shown. But fear not, just tap the left or right arrow key a few times to move them out of the way. I had the choice between that and rolling static. I decided to go with the bars since it'll give the best display if you move them out of the way.

Directories are shown in the file list with a trailing "/". Press the space-bar to enter a directory. The special directory entry ".." is used to go up to the parent directory. As well, there is a "-=TRSVID=-" entry that will go right to the top of the SD card. If you want to change SD cards, select "-=TRSVID=-", switch cards and then press space-bar. That way trsvid will read the new card. This is important because if you switch cards in any other fashion trsvid will crash or print some message about an error talking to FreHD. There are some rough edges here.

To play a video simply select it and press space-bar. Note that trsvid will show the preview image of a video even if it cannot play it. A "<Not playable on this TRS-80>" message will be shown if either the video format is not supported (for example, a .tv3 file on a Model I) or if your FreHD hard drive emulator does not have the enhanced firmware in which case no videos will be playable.

While a video is playing you can hold the space-bar to pause the video until you release the space-bar. Or press "W" (or almost any key but "W" is mnemonic) to pause the video until you press another key. You can press the BREAK key at any time to stop video playback. When paused the video will show a progress bar at the bottom indicating how much of the video has been played and a "MM:SS" amount played indicator. There's currently no way to start in the middle of a video or rewind or fast-forward. No technical reason why that can't be done, I just got lazy.

TRS-80 Model I and 3 computers can only output audio through the cassette port. TRS-80 Model 4P computers only have an internal speaker. Model 4 computers have both an internal speaker (I think all model 4's do) and a cassette port. So on the Model 4 it will show a "(S)peaker ---> (C)assette" line showing where audio output goes. You press "S" to change to the speaker and "C" to change to the cassette port. You cannot do this when a video is playing or even when a video is paused. Again, pure sloth on me, the programmer's part.

trsvid can only handle about 75 entries per directory. Use sub-directories if, for some amazing reason, you have more video files than that.

trsvid shows a little information about what TRS-80 Model computer you have, what the video refresh rate is (60 or 50 Hz) and the relative CPU speed on Model 4 or 4P machines. Not something you really need to know, but good info for our customer support staff. However, note that only Model 4 machines with "CPU: fast" can play .tv6 files. Other Model 4's will be limted to .tv1 and .tv3 videos.

Since trsvid uses pretty much all the memory and generally takes over the machine there's no way to exit back to TRS-DOS or LDOS or whatever DOS. You'll just have to reset or power-cycle or trip a circuit-breaker to exit.

The trsvid player uses Einar Saukas' zx7 compression library. Not on the video data, mind you, but internally to keep the executable size down.

Emulator trsvid

Most TRS-80 emulators can't run trsvid because they don't emulate a FreHD. Best case is that trsvid would run, print a "sorry, no Frehd" sort of message and exit back to DOS. By absolutely no coincidence, my trs80gp emulator works. Here's what you'll need: Extract files and put trs80gp.exe, trsvid.cmd and one or more of the .tv1, .tv3 or .tv6 files into a directory and then run:
     trs80gp -m4p -frehd trsvid.cmd
If you'd like to see how it goes on a TRS-80 Model I then use -m1 instead of -m4p. Or -m3 to see it as it would be on a Model 3. Though there isn't much to it, you may want to read the trsvid manual. For that matter, couldn't hurt to look at the trs80gp documentation.

I daresay the emulator does a reasonable job of showing what the real thing is like. However, the sound quality is worse and the sound pitch will be off on the Model 4 machines (this is due to incomplete understanding of video wait state timing). And despite my efforts modern LCD screens are just not the same as CRTs.

The emulator is a good training ground if you want to try the real thing and a fast and excellent way to see if your own videos are coming out OK.

You'll notice that FreHD emulator inside trs80gp is essentially treating the current directory as the SD card. Just a word to the wise that while trsvid can browse up and down directories it is rather limited in the size of directory it can handle. If you think the directory is truncated that is not a bug. And if the directory path gets too long it will crash. And trs80gp won't re-scan directories so don't expect files to show up magically if you add them while it is running.

Real Machine with Stock FreHD

To actually watch videos on your TRS-80 you'll need the enhanced FreHD firmware and special care in copying video files. But trsvid will run with an unenhanced FreHD or no FreHD at all. The latter is useful if you want to find out what video formats your TRS-80 could handle. You'll still get to browse files and see the preview images. Think of it like just watching arcade games when you were a kid and didn't have a quarter. You'll need: If you're feeling conservative, just download tv1.zip to get video files that will play on any supported TRS-80. Otherwise you can run trsvid/cmd on your TRS-80 first to see which formats it supports and therefore which files you need to download and copy to the SD card. The zip archives are 30 to 50 MB in size. Generally considered small by today's standards but still far from instantaneous downloads.

Get trsvid.cmd onto your emulated FreHD hard drive in whatever way you usually copy files. Probably the easiest is to copy trsvid.cmd to the SD card you put into the FreHD and use the import2 utility from within TRS-DOS or LDOS to get it onto the emulated hard drive.

The video files are to be copied onto the SD card. They do not go onto the FreHD emulated hard drive.

Then just run trsvid and read the manual if anything is confusing from there on out.

Real Machine with Enhanced FreHD

Oh, boy, I'm glad you're here. Let me tell you this is what all the cool kids are doing these days. And I'm afraid there's a reason it's so cool -- it's not going to be easy. The tricky bit is that your FreHD will need to be ugraded to the enhanced firmware and it can't be done via the TRS-80 itself. I wish it could but the enhancements required changes to the bootloader. Here's what you'll need: Right up front let me tell you that I'm more than willing to help anybody who tries this. I'm even willing to flash PIC chips for you if that's what it takes. My e-mail address is at the bottom of this page.

I think it's always best to do the hardest and riskiest part of a project first. So the first thing to do is pull the enhanced FreHD firmware FreHD_3.00.hex out of the trsvid.zip archive. Pull the PIC chip (it's the big one) off your FreHD board and flash the new firmware on it. Put the PIC chip back and verify that your FreHD still works. Everything should work the same and vhdutl (ver) will show it having firmware version 3.00.

If "flashing a PIC chip" is meaningless or scary to you, I empathize. Heck, if "pulling a PIC chip" is scary then I'm with you on that. I've done this myself (obviously) but my process is essentially non-repeatable. You'd be better off to mail your chip to me and I'll flash it (uh, but e-mail me first before you do so). If you don't believe me, read this cautionary tale.

Next, just import2 or some other method to get trsvid.cmd onto the emulated FreHD hard drive. Then run it so it will show you what video file formats (.tv1, .tv3, .tv6) your TRS-80 supports. You're best to use the highest numbered format supported. You only need to do this for Model 4 machines. A Model I can only handle .tv1 and a Model 3 can only handle .tv3. A Model 4 might be able to handle .tv6 or maybe only .tv1 and .tv3 files.

Now the only trick is to get the video files onto the SD card. The problem is that for a video file to be playable it must not be fragmented. That is, it must be written to the SD card as a contiguous series of sectors.

If you're using Windows then the contig utility will help you out. Copy a video file to your SD card (say smdm.tv1) and then run contig -a on it. For instance, contig -a J:smdm.tv1). If it reports the file as having a single fragment then all is well. Pop it into your FreHD and try and play it. If not there are a few options. One is to use contig to degragment the file with contig j:smdm.tv1). That works, but let me tell you it took a long time when I did that once. Like 15 or 20 minutes. The other option is to put another ocpy of the file onto the SD card and see if that copy has only one fragment. If not, try another copy. That sounds a bit silly but chances are you'll quickly be writing the file into free space which hasn't been fragmented so you'll get a contiguous set of sectors. Even though it is slow, having contig defrag the file is better than moving on to the next method for non-Windows computers.

I presume Linux has some program that does what contig does on Windows and there's probably even one for the Mac, but I don't know what they are. But if you start with a freshly formatted SD card then every file copy should be contiguous. So grab an SD card, format it, copy on the files needed by the FreHD itself and then copy on the video files. That should work, but there's no way to be sure. And trsvid itself doesn't have the capability of testing the files. All you can do is try to play them. Even if the file is fragmented it will play fine for a while until the second fragment is hit. At that point trsvid will be reading random data and most likely will crash.

SD cards have little computers in them for managing the flash memory and answering sector read/write requests. They may look like a half stick of gum, but they're complicated. trsvid uses sector streaming to play videos. This isn't a commonly used feature and may not work properly. I've only had one card that I think didn't work, but keep in mind that using a different SD card might be the answer if everything else seems in order.

Congratulations if it works. If you want to level up even further, then try converting your own videos.

What's in the enhanced FreHD Firmware?

The enhanced FreHD firmware has three new features:
  1. Minimize wait states on data read.
  2. FAT32 file open returns both file size and starting sector.
  3. New command to start and stop sector streaming.
The wait state minimization was what required a new bootloader. A stock FreHD makes the Z-80 in a Model 4 wait 25 cycles for each data byte. I found that reduced the raw data rate so much that decent video playback was simply not viable. I managed to get that down to 3 wait states.

Even with that speedup I couldn't make ordinary file reading fast enough. The FreHD (correctly) computes and verifies the CRC for each 512 byte sector read. The CRC routine can be considerably sped up but even then it was quite a hit. But having a mode to skip CRC calculation if a file were opened in unsafe mode was a reasonable workaround. After all, I'd only be reading files so the worst case was a program crash. It wouldn't cause a problem in the file system itself. There were still lengthy delays whenever the FreHD had to read a new cluster sector to find the next data sector. In other words, every so often a read would take a lot longer. Finally, there was a delay every second 256 byte read because the FreHD has to break 512 byte SD card sectors into 256 byte chunks to feed to the TRS-80. I tried a number of different schemes to reduce or hide the overhead but the resulting data throughput was still a lot lower than I'd like. And the lengthy and somewhat unpredictatable delays between 256 byte reads would greatly complicate and slow down the video player itself.

Fortunately I found the sector streaming command. I think the intent of it was for video cameras and other special-purpose devices that needed higher throughput. I suspect it remains largely unused in recent times as ordinary sector reads will suffice as long as your device has a decent CPU. In any case it is perfect for trsvid's needs. All I had to do was have the file open command return the first sector of the file and add a command to initiate sector streaming from that sector. As long as the file was not fragmented everything would work perfectly.

Sector streaming doesn't give a perfect data stream. After each 512 byte sector it sends the CRC (which trsvid ignores, naturally) and then it transmits an undetermined number of "stuff" bytes while the SD card controller gets the next sector ready. Based on a few cards I tested the number of stuff bytes is usually only a small amount like 10 or so. That makes the player surprisingly more complicated but at least the effective data rate remains high.

How not to flash a PIC chip

Once I decided I wanted FreHD firmware improvements I went down the road of figuring out how to recompile the firmware (a journey in itself) and how to flash new firmware on the PIC. My first step was to carefully pry the PIC chip off the board and put a ZIF socket in there. That makes it easy to remove and replace the chip on the PIC board because I'd be doing that frequently. Oh, boy, did I ever.

Before rebuilding the firmware I better make sure I can flash an existing version. So I did a little research and got some advice from Andrew Quinn. I heard that something called a PICkit would do the trick. I also read a lot about how the PICkit 2 was great but Microchip was phasing it out for the PICkit 3 so it was hard to get them and their software tending toward not working with the old version. Deciding to save a few bucks I ordered a PICkit 3 clone from some random eBay seller. It came with a little circuit board and its own ZIF socket. Just wire the board up to the PICkit, drop the chip in, plug the PICkit to your PC's USB port and run the burning software.

Again, various Google searches and embedded programming messages boards didn't give me a warm and cozy glow. Most of it were complaints that the old, simple burning software wasn't available or didn't work with the PICkit 3 and that you had to use Microchip's fancy new MPLAB X IDE which is one of these soup-to-nuts things that will compile your C code, assemble your assembler, edit your files, link it all up and burn what remains to a PIC. Great! But all I had was a .hex file. Nonetheless it wasn't too hard to drill through the IDE and make it happy with a mere .hex file. I also had to tell it exactly what PIC chip I had. Sounds easy but there are a million different PIC chips and their names look all the same.

I can't remmeber exacty what I did next, but let me emphasize very carefully that it was all my fault. Andrew's guidance was nothing but sound. It seems that for reasons no doubt involving electrons and other non-software entities the PICkit 3 itself needs to be flashed with firmware depending on what PIC it means to program. The message boards mention this as one of the many faults of the PICkit 3 over the PICkit 2. I don't know if I chose poorly, picked the wrong chip, panicked and pulled a cable too soon or what but after a failed attempt to flash the PICkit the IDE kept saying that I had no PICkit attached. Fiddling with mysterious IDE settings and generally pleading did nothing to resolve this. My PICkit 3 was bricked.

Cursing my stupidity and/or luck, I ordered a somewhat more expensive but real Microchip brand PICkit 3. It didn't come with a little board so the original wasn't a total loss. And the message boards assured me that with a tiny bit of soldering my new PICkit 3 could be used to flash the dead PICkit 3 and bring it back to life. Maybe someday I'll do that, but at the time it just sounded like a new and exciting way to brick my new PICkit.

Fortunately this time around the flash of the PICkit 3 worked. It was ready to program my chip. I super carefully looked up which of the 5 (of 6) wires that came out of the PICkit needed to be hooked up to the pins of the chip. Made all the necessary connections, checked them thrice (at least) and tried again. Checked the connections several more times. After a while I realized that I'd wired the PICkit to the wrong row of header pins on the board. Looking at the board again I can't quite see what my mistake was, but it meant that the PICkit was wired to pins on the board that didn't go to the chip.

Once I got that wiring problem sorted out it worked. Mostly. I got it to burn once or twice but then it said something like "USB isn't giving me enough volts to get the job done." More Googling and UI poking ensues. While the recommended power setting for my PIC was 5 volts it seemed that a lower voltage would work. So I turned the voltage setting in the IDE down to 4.5 V and it didn't complain about the power yet still flashed the chip.

And now it works perfectly. And by perfectly I mean sometimes it still complains about the power but unplugging the USB cable and plugging it back in will usually clear up that error. And sometimes it complains about how there's a short detected so it can't do anything. That just means I haven't used it in a few months and have forgotten which way to put in the chip. The chip survived! It also survived being put in backwards to the FreHD and didn't even kill the FreHD. Who says you have to be careful with hardware?

Anyhow, that's my process for flashing PIC chips. Give it a try if you like, but maybe you should find someone who knows what the hell they're doing.

Convert Your Own Videos

Awesome as they are, I'm sure you'll tire of the 5 sample videos I provide. trsvid includes the utility programs I use to convert video files to its format. Most of the heavy lifting is done by a generic video processing tool called ffmpeg. The rest are some fairly simple C programs to marshal the data into .tv1, .tv3 or .tv6 format. To do this you'll need: If you can compile C programs then I think this is all easily doable on Mac or Linux. They both will have perl already installed and you'll find versions of ffmpeg for them in the same place as shown for the PC. You'll just need to compile the C programs from trsvid/convert.

Download and install perl and ffmpeg. The key thing is to have them set up so that both perl and ffmpeg are recognized as commands at the command prompt.

Unpack convert-example.zip

From the trsvid/convert directory (inside trsvid.zip) copy mixtv.exe, png2strip.exe, strip2txt.exe and tovid.pl so they're in with vidlist.txt where you unpacked convert-example.zip

tovid.pl is oriented towards batch style operation. By default it will convert all the videos listed in a file to all known formats. As a start I suggest just show what it will do to convert one video to .tv1 format with:

    perl tovid.pl vidlist.txt -v drwho4 -f 1 -n
That will spit out a series of commands that will be run. To actually convert a video just drop the -n flag:
    perl tovid.pl vidlist.txt -v drwho4 -f 1
All going well that will leave drwho4.tv1 in the converted directory and a bunch of temporary files in the tmp directory. I don't delete the temporary files as they're useful for debugging pipeline problems and if you hack the tovid.pl perl script or run the commands manually you can speed re-processing of a video by skipping any steps that don't change.

While you can see if that converted video works by running it on your TRS-80, I do recommend using the trs80gp emulator which will make inspecting the output much quicker.

To convert all the videos listed in vidlist.txt to all formats just run:

    perl tovid.pl vidlist.txt

tovid.pl isn't very friendly and doesn't respond very well when things go wrong like if ffmpeg decides it really couldn't convert the file. But for the most part it is just a wrapper around the commands themselves to automate the process.

Though it needs to be documented, for now I suggest you look at the vidlist.txt file to see how it names the temporary and output directories and how it gives the parameters for each video file. Notice how you can give the title and even the preview image to use. If no preview image is specified one will be extracted some number of frames into the video file.

One feature not shown in the example is specifying an alternate audio track. This is important as the trsvid sound is quite noisy so benefits from a higher volume. Especially on the Model 4P with its internal speaker that has no volume control so audio tends to be on the quiet side. The volume: option will tell tovid.pl to have ffmpeg amplify the video's audio volume. Don't be shy about turning up the volume as the distortion from clipping tends to get lost in the general audio degredation anyways. Dynamic range compression can also be quite helpful. It tends to be referred to as simple "compression" in audio editing programs, by the way.

Write Your Own Converter

Converting a video to trsvid format is conceptually pretty simple. The first step is to run a general purpose utility such a ffmpeg to convert the .mp4 or whatever format video file into raw data. The video portion is converted into a series of .png image files, one for each frame and the audio portion is converted into a raw, unsigned 8 bit per sample audio file. We also rely on the converter to resample the audio and video to specific sample rates. And the video frames must be converted to greyscale and downsampled to TRS-80 resolutions. The rates and resolutions vary depending on the target format:
.tv1.tv3.tv6
Resolution  128 x 48128 x 48160 x 72
Frame Rate  51.507454.4726760
Audio Rate  14307.096815130.7462716200

The .png files are fed to png2strip which converts them to a single file of raw grayscale pixels concatenated together.

The image strip is fed to strip2txt which does spatial and time domain dithering to convert the grayscale data into monochrome and then outputs it as TRS-80 graphics characters.

Finally, the raw audio data and strip2txt output are read by mixtv which produces the final combined data stream. It also fills in the file header so it has options to set the title and preview image. See video-format.txt for information on how the trsvid data file header is organized.

Running tovid.pl with the -n flag will show you how ffmpeg is manipulated into producing the required output. It will also show how my utilities are used to take that raw data and convert them in to trsvid format files. Note that the grayscale effect seen in preview images is done as a sort of mini video conversion of a single image.

One thing that could defintely use improvement is audio/video sync. The .tv6 format is OK, but .tv1 and .tv3 have very unusual frame rates and ffmpeg only supports a few decimal places. So video and audio get out of sync over time.

If you're generating movies directly through CGI or other means you may want to avoid the ffmpeg step and produce raw audio and grayscale PNG frames directly. Or output the strip form of the image data directly. If you're generating TRS-80 graphics (say maybe from emulator screen captures) then going straight to strip2txt output is best.

On the other side of things you may have some better ideas on how to convert grayscale video into monochrome data. strip2txt does pretty well but is hardly the last word. trsvid is not doing any clever processing. It merely intends to display the frames as fast as it is able. A more complicated or involved grayscale to monochrome process will make no difference to it.

mixtv.cpp is the only existing "documentation" of the low level trsvid video format. But I do note that at a low level the file data is a series of interleaved audio and video operations. There might well be some things that can be done beyond simple video playback.

Hack trsvid Itself

Most of trsvid can be built using zmac. So you just need: zmac comes with an executable for Windows but also includes source code and should easily build for both Mac and Linux. With zmac.exe on your PATH this command will do it:
    zmac --zmac trsvid.z
And you can immediately test it with trs80gp if you have it:
    trs80gp -frehd zout/trsvid.bds
You can also give it trsvid.cmd instead, but using the .bds output will enable source level debugging.

With only zmac you can modify the user interface and the .tv6 player. The .tv1 and .tv3 players are generated by a perl script and compressed using Einar Saukas' zx7 compressor. To fully build trsvid you need:

From the trsvid download find zx7/src/zx7.exe and make sure it is on your PATH. Should be easy to compile on Mac or Linux. Do a full build with:
    perl mkplay.pl
    zmac --zmac trsvid.z
If you look at mkplay.pl you'll see it mostly just runs genplayer.pl with all the different variations of the .tv1 and .tv3 players, assembles the resulting assembly file and compresses it with zx7. You can ignore the p4 commands it runs as those are just source code commands that are only needed if you use Perforce. mkplay.pl also happens to compress the splash screen.

The user interface portion of trsvid is pretty straightforward Z-80 code. The only really tricky bits are flipping the preview images quickly and exactly once per frame. The Model I variant runs a loop that executes in exactly the same number of cycles as a video frame thus it remains in sync with the video but doesn't with the relative phase. This is why the black bars appear because the code has no way to know where they are.

The Model 3 preview displays a single frame, then waits a rough amount of time to be guaranteed that the next frame is being displayed by the video. Since video waits are on it can display the next frame and know it won't show up too soon. At that point it can wait on the 30 Hz interrupt to keep in sync with the screen. In short, a simple cheat to maintain 60 Hz sync without getting too involved. If run trs80gp as below you'll see red lines indicating when the Z-80 is accessing video memory. You can see how the video memory accesses synchronize.

    trs80gp -bd -frehd zout/trsvid.bds

The Model 4 can get a 60 Hz (or 50 Hz) video interrupt so it simply draws a frame quickly and waits for that.

Theory of Operation

While they differ in details, the players for each format are pretty similar. Their main function is to read graphics data as quickly as possible and put it on the screen. Nothing but a whole bunch of ini instructions. There are two complicating factors: audio and inter-sector gaps. The only reasonable way I found to play digitized audio with the TRS-80's single bit sound is to use Pulse-Width Modulation or PWM. What you do is read the usual amplitude samples from an audio stream at some carrier frequency (I use around 15 KHz). Over that 1/15000 of a second interval you turn the audio on for a percentage of time equal to the sample's percentage of maximum amplitude. So for a sample 25% of maximum you turn the sound on for 1/60000 of a second and then off for the remaining 3/60000 of a second. Due to low-pass filtering (of the hardware? the air? your ears? I'm not really sure) this ends up sounding like an actual 25% speaker deflection.

On a (fast) Model 4 the interval is 256 clock cycles. And I've learned the hard way that if the player is not extremely consistent about that interval the sound suffers terribly. And if you should happen to skip an interval per frame you get a horrible and loud 60 Hz buzz. Since the audio only has to go on and off in the interval there's quite a bit of idle time. During that time we read the graphics bytes and display them on screen. The basic video format for .tv6 is one audio sample byte followed by 8 graphics bytes. The code reads the audio sample, turns on sound and then figures out how long it has until sound must turn off again. If the sample is small then it will just idle for a short period, turn off the sound and then do 8 ini instructions to display the graphics. For a bigger sample it might do two graphics bytes, turn off sound and then the remaining 6.

That's how it works conceptually. Practically speaking there's no time to make decisions. The code supports 64 audio levels and has 64 different chunks of code all ready to handle each case. To minimize overhead I use the fastest dispatch mechanism I know:

    in h,(c)
    jp (hl)
With L register always set to 0 then handler code for each audio level is at $0000, $0100, $0200, $0300, ... $3E00, $3F00. It's a bit awkward but amazingly workable.

The inter-sector gap makes this more difficult. After the 512 data bytes of a sector the SD card needs a little time before it can start outputting the next sector. Try as I might, I couldn't hide this detail in the FreHD. So the TRS-80 will see the $FF bytes that occur between sectors until a $FE byte appears signalling the start of the next sector. Since we cannot let the audio lapse for even one interval this means we must have some way to buffer enough audio data to keep things going until the next sector starts.

Thus to our original 64 commands we add $40 through $7F which tell the player that it must output a sample of $00 through $3F while it is reading a few more audio bytes to play back when the gap is hit. Well, as you might suspect, it isn't buffering literal audio data but another of a set of commands from $80 through $BF that tell the player to output an audio sample of $00 through $3F while is is reading data bytes looking for a $FE indicating the next sector is starting at which point we can go back to directly executing commands.

The buffered commands have the special command $C0 at the end. If we don't see a $FE byte before the buffer runs out then $C0 is a loop that simply reads until the $FE byte is found and continues on. Yes, that will cause a glitch in the audio but there's nothing to be done about it. It's just a safety valve in the very uncommon occurence that the SD card is slow on sending the next sector.

The "waiting for $FE" commands actually work in two states. At first they continue with L set to 0. But when the $FE is found they load L with $80. Now the commands are slightly different. We still must output an audio sample but we don't want to be pulling in the sector data. But we will check the buffer pointer so we know when to go back to reading and executing commands from the SD card.

Of course, there's a bunch of little details in getting this all to work smoothly. After the screen has been filled HL' needs to be reloaded with the start of screen VRAM. The SD card sends a two byte CRC after the sector data. That problem is solved by having a few bytes unusued in the audio buffering. mixtv sets those bytes to whatever value is needed to ensure the CRC does not contain $FE. Thus the CRC is skipped just like the stuff bytes.

There's one more code to signal that the file is done. And somewhere in there we peek at the keyboard so the video can be stopped or paused. And for no particularly good reason all the codes have 2 added to them. Some more of the unused audio buffer bytes are filled in with a seconds count so the pause code can display how far along we are in the video.

The Model 4 has wait states added when writing to video memory. Thus the timer interval for any commands that write graphics to the screen is suitably reduced to account for the extra instruction time.

The Model I and 3 operate with a slightly longer interval and only have time to do 4 bytes per graphics command. Which is OK because they have about 1/2 the number of bytes to display per screen. They only have 48K of RAM so cannot use commands lower than $40 which limits them to 32 levels of audio. And time is so tight on the Model I that I had to settle for some slight variation in the interval durations thus adding more noise to the playback.

Into the Future

I'd hoped to define .tv4 and .tv5 formats that do full-screen 160 x 72 video on the slower Model 4 computers. The idea of a .tv2 format for Model II computers is a much more ambitious goal. With non graphics character set like the others the video encoder would have to make do with matching ASCII and other characters to video data. It has been done on other platforms, but I had enough trouble getting simple graphics data to work that I backed away from that challenge. In fact, the project itself was stalled for a long time until I figured out how to convert video frames that wasn't a total mess.

For that matter I'm sure there's quite a bit of room to improve encoding of both the graphics and audio. Maybe the Model I/3/4 should take advantage of ASCII characters -- the video formats allow for it. And I'm sure there are even better graphics conversion algorithms out there. That goes double for audio. Some of the TRS-80 digitized speech is so good despite incredibly low bit-rates. If I could reproduce that in an algorithm then it could make for a better and simpler player.

Part of the fun and challenge of trsvid is using the stock hardware for output. Making use of high-res graphics cards would be an interesting challenge. There's no way you can update the graphics screen at a decent frame rate but you could update reasonble subsets. Makes for a lot of hard work in the video converter. Proper digital audio hardware like the Orchestra 80 would vastly improve audio quality. Heck, it would make the player software almost trivial. Where's the fun in that?

Perhaps the most tantalizing prospect is using the ethernet capabilities of MISE or M3SE expansion hardware. Even 10 megabit ethernet has enough bandwidth to feed trsvid. The only question is whether the expanders can deliver that data quickly to the TRS-80. Hack up some server software and maybe we could have a YouTube player for the TRS-80.


George Phillips, March 18, 2017, george -at- 48k.ca