
"My First GFA BASIC Program" by Troy H. Cheek on Nov 17, 2008
As I mentioned last week when I was grumbling that GFA BASIC is dead, I recently picked up the latest version of GFA BASIC 32 for Windows. Like any manly, independent, self-taught hacker, I immediately jumped in over my head and had to seek help.
It's hard to seek help. It's hard to look it up using a search engine, because no two people spell it the same. For example, this week alone I have seen the following:
I find myself wanting to write a GFA BASIC program to generate all the possible spellings of the name of the language in which the program will be written. Much like my program to generate all the possible names of God, I expect such an endeavor will not end well.
I call it GFA BASIC because it's an acronym. BASIC is, as everyone knows, Beginner's All-purpose Symbolic Instruction Code. GFA is an acronym for "Gesellschaft für Automatisierung" i.e. "Company for Automatization" which is part of the name of the company which hired Frank Ostrowski to create the language to begin with. If I ever meet him, I'll have to ask him what he calls it. Of course, I've also got to ask him about my spelling of Turbo BASIC XL for the Atari 8-bit.
My old buddy Lonny Pursell of the Unofficial GFA-Basic Support Site wasn't much of a help. He focuses on the Atari ST version of GFA BASIC. I also found fans of the Amiga version and the DOS version, but mostly the examples and help files and other articles I found were based on the Atari ST version. It's seems like there are a lot of people who don't want to move on to newer languages or platforms. There's even a guy who's written a Atari GFA Basic 3 to Java converter just so he doesn't have to learn a new language. I'm not quite that bad, am I?
I also found reference to Visual Basic converter, but this is a bit of a cheat since later revisions of GFA BASIC for Windows were mostly code compatible with Visual Basic. Or so I'm told. I haven't checked out Visual Basic yet. I tried once recently, but the setup file I downloaded turned out to just be the application which downloads and installs the half a dozen other applications needed before you can even install Visual Basic in the first place. And all by itself the downloader was much bigger than the entire GFA BASIC package already. Not being sure what all those other doodads would do to my highly tuned (read: periously balanced) operating system, I decided to pass for now.
It took quite a bit of digging to find any supporters of the Windows 16 or 32 version of GFA BASIC. Apparently, they don't spend a lot of time making websites. They also don't spend a lot of time learning English. I had some college German which does me absolutely no good. Everyone knows that computer geeks speak their own language anyway. But Google is pretty good as far machine translation goes, and I have been an Atari fan forever, which means that while I may not know that a word's origin is German, I likely do know what it means in terms of computers. So I dug out some of my old Druckerlisten and got to work writing a program in this new (to me) GFA BASIC 32 for Windows.
Actually, it's a remake of an existing Atari ST GFA BASIC program. Now, the official unofficial support site has this long and boring article about how to translate our old programs line by line into the new syntax, taking care to match variable types and paying careful attention to the blah blah blah.
I dozed off about then.
My program was simple enough at its heart that I felt I might do better to just start again from scratch. I figured I could both get some experience with the new programming language and perform a useful task at the same time.
You see, I have a very large LP record, 8-track tape, cassette tape, and CD collection. I have spent years capturing, converting, and locating mp3 versions versions of the songs in my collection. The files I have on my harddrive at this particular moment weigh in at 16.8GB, 4,379 files, 290 filders. I don't want to listen to those just on my computer, naturally. However, my nephews' mp3 players hold only a few GB at most, and they have their own collections. My truck stereo will play mp3 files off standard USB flash drives. My USB flash drive collection includes 128MB, 1GB, and 4GB devices. These don't add up to enough capacity to hold my entire collection, even if I and others didn't have other data we need to store on them. Besides, I can never which drive a particular album is on.
The answer to the problem is a computer program which rifles through the entire mp3 collection and copies a sampling to the USB flash drive in question. While this sampling could be random, I find it works better to keep track of the file access dates and focus mainly on songs that haven't been copied in a while. (Naturally, copying the files this time resets the file access dates.) Finally, while I could lump albums or artists or genres together, I prefer to mix them up. I could just hit "shuffle" on the player, but I find that good listening experience isn't so much random as stratified.
A truly random distribution of songs means that songs that start out right next to each other (songs on a particular album, for example) can end up right next to each other. This is a perfectly valid random outcome. Sure, it doesn't happen often, but the human mind purely loves to pick out patterns, and noticing two songs in a row by the same artist just screams "not random!" So, while making sure that I mix things up, I also have to make sure that similar items don't appear too near each other. Believe it or not, more shuffling is not the answer. You have to use a very careful pattern to keep the human mind from seeing a pattern. You have to define layers; not so much layers of what things are, but what things are not.
My so-called "Playlist Generator":
Step 1: It turns out that GFA BASIC has functions specifically designed for recursive walking of directory trees. In other words, it knows how to find all the mp3 files in a folder, then knows to look in the folders inside those folders, then the folders inside those other folders, ad infinitum. GFA BASIC knows how to do that. Unfortunately, I don't know how to tell GFA BASIC to do that. While the help file contains snippets of example code showing how to use most keywords, DirPush and DirPop direct me to a hundred-line example program, commented in German. First setback. Fortunately, my old Atari ST method of dealing with recursion, namely creating my own stack and faking it, worked just as well as it did in the old verison.
Step 2: Once I had the list of filenames, it was easy enough to find the file access date and combine that with the filename. By making each list entry of the form Date\Folder\[maybe some more folders]\Filename.ext, I used the built-in GFA BASIC Quicksort command to sort it by date, then tossed out the dates. I did something similar in the Atari ST version, but ended up with a modified comb sort because I wanted to prove I could write a sort as fast as the built in one. I never did, but I got close enough that I still claim bragging rights.
Step 3: I'll deal with this next week in Revising My First GFA BASIC Program.
Step 4: After the DirPush/DirPop thing, I was afraid that checking free drivespace would be a pain, but it turned out to be so easy and fast that I ended up re-checking it after every file copied, just to better estimate which files would fit on the USB flash drive.
Step 5: In the Atari ST version, I copied songs using a 32KB file buffer, because trying to allocate and use larger memory blocks always left me with an unstable system or corrupted copies. I'm sure I was just doing something wrong. I ended up altering my program to just create a batch file which I would then run to do the actual copying. With the new version, I found internal automated file copy commands with the same 32KB file buffer. Hmm. Perhaps I wasn't doing anything wrong after all. I've moved from an Atari 520ST with 512KB of RAM to an Atari Falcon030 with 4MB of RAM to a WindowsXP machine with 2GB of physical RAM and who knows how much virtual memory, and I'm still copying files 32KB at a time. The file copy command could even automatically call a subroutine after every block, just in case you wanted to display a progress bar or something else for the user to look at while the copying took place. I did. My progress bar didn't work at first, but it turns out that I was using the wrong variable types. It turns out that bytes_copied is only a large 64-bit integer if the file you're copying is larger than 2GB. Since I'm copying files a few MB at most, bytes_copied is a regular 32-bit integer.
In the end, it took about 8 hours of coding, including research, to
get a usable program. I'm listening to my mix tape
mix CD mix USB personalized radio
station on USB right now. Of course, there's still room for
improvement, which I'll talk about next week.