SoftDAC

SoftDAC: Digital Audio for the Apple II

(Just want the archive, ready to transfer to your Apple II? It’s here.)

A thread popped up on Slashdot back in 1999 regarding Audiohighway’s patent on playback hardware for compressed digital audio (click here for the thread). A comment was made by sjames (spam-resistant address, and it’s probably long since dead anyway) regarding the Apple II as prior art.

It just so happens that I wrote a little player program several years ago that does just that. It takes digital audio sampled at about 11.025 kHz and 4 bits per sample, with two samples per byte, and plays it to either the internal speaker or (if you have a IIe) the cassette-output port, to which an amplified speaker can be attached (preferably through a low-pass filter to get rid of the high-pitched squeal you get in the background with this player). I found the source code still sitting on the IIGS that I have now; the file it was in was date-stamped 11 August 1992. The “compression” applied here was to simply take raw 8-bit audio data and cram the upper nibbles of two samples into one byte for storage prior to playback. With the typical (128K) memory configuration of most Apple IIe and IIc systems, you’d get about 17 seconds of playback time. With RamWorks-compatible memory expansion (I had a RamWorks III with 1 meg of RAM), you could get a couple of minutes or so out of it, depending on installed memory.

The 6502 assembly source code for the playback engine is presented below. There was another assembly-language program that acted as a loader for the audio file, but it’s fairly ordinary code (some code to find RamWorks memory, some ProDOS MLI calls, and some really trivial code to “compress” the data from a WAV or VOC file (or whatever type) into memory for playback). In usage, you’d use a shell (such as Davex or ECP-8) to issue a command such as:

softdac foo.wav

to play foo.wav. (Ideally, you’d feed SoftDAC raw 8-bit data at 11.025 kHz with no header; programs such as sox could be used to strip the headers out of most types of sound files. Playing WAVs, VOCs, etc. as-is usually worked if their data were in the right format; the header info at the beginning would be barely audible.)

Note that all this was done years before Audiohighway’s patent application. You say that their patent was for portable players? Try a IIc with a flat-panel display and battery pack, and run SoftDAC on that. Others have mentioned x86-based laptop/notebook computers and various portable Macs as other possible portable digital-audio playback devices. None of these are as convenient as, say, a Diamond Rio, but from what I’ve heard, they all fall within the bounds of Audiohighway’s patent…and people were using them long before anybody even heard of Audiohighway.

So, without further ado, here’s the source. (Please, no comments on what a Beowulf cluster might be able to do with this. :-) ) The local labels, assembler directives, and such are in the format used by the MicroSPARC (=MindCraft) Assembler (which I think is now a free download available here). Others (such as Merlin and Lisa) used different syntax, but if you know 6502 assembly from anywhere, you should be able to figure out the code pretty quickly. For those of you who never wrote for the Apple II, $C030 is the speaker soft-switch. Accessing it toggles the speaker between “in” and “out” states. SoftDAC worked by toggling the speaker in and out rapidly enough that you could vary the distance traveled by the cone, as opposed to most other programs which would let the speaker move fully in and out.

;
;SoftDAC v2.0b2
;Playback Engine Source Code
;
;by Scott Alfter
;
;Copyright (C) 1990-1992 by Scott Alfter dba Skunk Works Software Co.
;
;Skunk Works Software Co.
;4600 Swenson St. #163A
;Las Vegas, NV 89119
;BBS: (702) 894-9619 (24 hrs., 300-14400 v.32bis)
;
;This program is free software; you can redistribute it and/or modify it under
;the terms of the GNU General Public License as published by the Free Software
;Foundation, version 1.
;
;This program is distributed in the hope that it will be useful, but WITHOUT
;ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
;FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
;details.
;
;The GNU General Public License is included at the end of SOFTDAC.DOCS in
;SOFTDAC.SHK as distributed by Skunk Works Software Co.
;
SPKR           EQU  $C030       ;Speaker softswitch
BANKSEL        EQU  $C073       ;RamWorks bank select
               ORG  $300
PLAY           LDX  #$0800      ;Begin playing at $0800
               STX  ]1
               LDA  #$0800/
               STA  ]1+1
               INX
]1             EQU  .+1
]LOOP          LDY  $0800       ;Grab a byte
               DEX
               TYA
]OTHER         AND  #$0F        ;Take the lower nibble; we'll call it t
               STA  ]2
               STA  SPKR        ;Bump the speaker
]2             EQU  .+1
               BPL  ]3          ;Pause a bit (t is inserted to branch to one
]3             NOP              ;of the NOPs)
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               STA  SPKR        ;Bump the speaker again
               EOR  #$0F        ;Take the 4-bit inverse of t
               STA  ]4
]4             EQU  .+1         ;Pause again (this makes sure each speaker
               BPL  ]5          ;bump is of equal length)
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
               NOP
]5             BIT  $0800
               TXA
               BNE  ]6          ;X=0 if both nibbles have been played
               AND  $00
               LDA  [1+1
               CMP  #$C0        ;End playing at $BFFF
               BCS  ]END
               TYA
               LSR              ;Play the upper nibble now
               LSR
               LSR
               LSR
               INX
               BNE  [OTHER
]6             INC  [1          ;Move on to the next byte
               BNE  ]7
               INC  [1+1
               BNE  [LOOP
]7             AND  $00
               LDA  #$00
               BEQ  [LOOP
]8             EQU  .+1         ;Stick next bank number here
]END           LDA  #1
               STA  BANKSEL
]NEXTBANK      JMP  PLAY        ;This instruction will be executed in the next
;                                bank

Leave a Reply