[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: How is the IIgs beep generated?



Mitchell Spector wrote:
"Michael J. Mahon" <mjmahon@aol.com> wrote:


Mitchell Spector wrote:

Hmm, tried it on my Apple IIGS a moments ago (would have tried it on the Apple IIc I rescued from a recycling center a few
weeks ago, but I just put it into storage with my other Apple II's).

Well, it's quite similar to the IIGS "bonk" yet not at all the same. It still has that very distinctive Apple II speaker sound.
Difficult to describe, but I hear "Bonkzzzzzzt", "Bonkzzzzzt"
rather than a crisp and very defined "Bonk".
   The more I listen to the GS's bell, the more I'm convinced
it's not something that can be reproduced on an Apple IIe.
Example, set the pitch in the Sound Control Panel to the
highest level. Try listening to it over and over, I've never
in all my years of Apple II gaming, programming and tinkering
heard a sound like that from the speaker (excluding, say, digitized audio, though even then it wouldn't be as clear).

I don't know what parameters you were using, but...


    Parameters? All I did was download the Applesoft BASIC
program you wrote (the second revision) and ran it as-is on my Apple IIc (managed to dig it out over the weekend and had a listen). It runs through the sound scale from high to low. I didn't play with any of the parameters.

If you LISTed the program, you'd see that--like most sound routines--
the parameters are POKEd into page 0 prior to the CALL that actually
produces the sound.

At the time that I posted, I didn't have access to a IIgs, and
so didn't know what the actual frequency and duration of the
"bonk" was.

I just happened to get access to a IIgs this weekend.

The correct parameters for the default IIgs "bonk" are:

POKE 6,83
POKE 7,2
CALL 768

That reproduces it quite well.  The volume is about 2/3 the max
volume of a raw beep, but the ear doesn't really care.  ;-)


    It's a similar approximation of the GS "bonk" bell (especially
the lower tones), but certainly not the same. :)

Try POKEing the parameters I suggested and give it a listen.

After listening to them side by side, I'll bet it's the best
approximation that can be produced with Apple II hardware.

I'm still curious how the tone is produced. Maybe it's standard speaker toggling that is then filtered or enhanced somehow using
something unique to the GS's audio circurity?

The IIgs routine uses completely standard speaker toggling, combined
with linear decreases in speaker volume throughout the tone--which
only the IIgs hardware supports.

My routine does exactly the same thing, based on 21.3kHz pulse-width-
modulation.  Many people (particularly those "of an age" ;-) cannot
hear the 21.3kHz pulses at all, but only the modulation, which is at
the "bonk" frequency.  Ideally, one would use a low-pass filter to
remove all traces of the 21.3kHz "carrier", but we're trying to use
standard hardware...

I'm guessing that the primary difference is that on the IIgs, the
speaker is driven by an audio amplifier from the actual speaker toggle
logic level, while on all other Apple II's, the speaker is driven by
a Darlington driver with a peculiar AC-coupled, DC-clamped input.

The difference is increased when the toggling is low frequency.

The PWM approach assumes that the Apple II clock is constant
frequency, but that is not strictly true, since there is a stretched
cycle every horizontal line, or 62 cycles.  This introduces a 15kHz
sub-cycle timing variation, causing an audible beat which is most
apparent under conditions of very low modulation (near silence).

The code I use to generate the "bonk" sound is:

**********************************************************
*                                                        *
*         "Bonk" sound routine for Apple II              *
*                                                        *
*       Copyright Michael J. Mahon, 12/08/2009           *
*                                                        *
*  Uses 21.3kHz PWM to synthesize a squarewave sound of  *
*  diminishing volume, mimicing the "bonk" IIgs sound.   *
*                                                        *
*  The PWM pulses are generated in 46-cycle loops, with  *
*  the high duty cycle pulses varying between 7 cycles   *
*  and 37 cycles, and the low duty cycle pulses always   *
*  7 cycles.                                             *
*                                                        *
*  Sound generaton begins at maximum duty cycle (volume) *
*  and diminshes by 1/15 on each volume step, until the  *
*  volume has been reduced to zero (equal high and low   *
*  duty cycle half-periods).                             *
*                                                        *
*  Input parameters are:                                 *
*   'hperiod'  = Half-period of tone in 46-cycle samples *
*   'vperiods' = Tone (full) periods per volume step     *
*                                                        *
*  Since 15 volume steps are required to diminish the    *
*  volume to zero, the total sound duration is 15 times  *
*  'vperiods' cycles of the generated tone.              *
*                                                        *
**********************************************************

* Page zero data

hperiod  equ   $06        ; Half-period in samples (<129)
vperiods equ   $07        ; Periods until vol step
vctr     equ   $08        ; Volume step counter

* Hardware definitions

SPKR     equ   $C030      ; Apple II speaker toggle

         org   $300

* Initialize

BONK     lda   #15        ; Init to 15 steps
         sta   vctr       ;  of dimishing volume.
         lda   #0         ; Init modified branches.
         sta   vinc+1
         lda   #hiduty-vdec-2 ; Point to hiduty
         sta   vdec+1
         ldy   hperiod    ; Samples in half-period
         dey              ;  minus 1.
         tya              ; Save half-period count.
         ldx   vperiods   ; Countdown to volume step.

* Generate high duty-cycle half of squarewave

         nop              ; String of NOPs is target
         nop              ;  of varying 'vdec' branch.
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
hidutym2 nop
hiduty   sta   SPKR       ; Toggle speaker hi
vinc     bpl   *+2        ; <modified: 0..15> (always)
         nop              ; String of NOPs is target
         nop              ;  of varying 'vinc' branch.
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         nop
         sta   SPKR       ; Toggle speaker lo
         dey              ; Count down half-period
vdec     bpl   hiduty     ; <modified>

* Generate first low duty-cycle half cycle of squarewave

         sta   SPKR       ; Toggle speaker hi
         bpl   *+2        ; (always)
         sta   SPKR       ; Toggle speaker lo
         dex              ; Time to dec volume?
         bne   dnostep    ; -No, delay then rejoin.
         dec   vctr       ; -Yes, volume = zero?
         beq   return     ; -Yes, return.
         dec   vdec+1     ; -No, decrease duty
         inc   vinc+1     ;       cycle (volume).
         ldx   vperiods   ; Reload vol step counter
nostep   tay              ; Reload half-period ctr
         bne   lodutym4   ; >0, gen more low pulses.
         beq   hidutym2   ; (always)

lodutym6 nop              ; Kill 2 cycles
lodutym4 nop              ; Kill 2 cycles
         nop              ; Kill 2 cycles
         sta   SPKR       ; Toggle speaker hi
         bpl   *+2        ; (always)
         sta   SPKR       ; Toggle speaker lo
         jsr   return     ; Kill 12
         jsr   return     ; Kill 12
         dey              ; Half-period expired?
         bpl   lodutym6   ; -No, keep looping.
         tay              ; -Yes, reset for hi loop
         bpl   hidutym2   ; (always)

dnostep  jsr   return     ; Kill 18 cycles
         nop
         nop
         nop
         bne   nostep     ;  and rejoin...

return   rts

This code produces pulses in loops that are exactly 46 cycles long,
and varies the volume of the modulation by changing the "on" time
of the "high pulse" to the speaker from 37 cycles down to 7 cycles
in 15 steps of 2 cycles.

The parameters determine the audible frequency--the rate of switching
between the high duty cycle and the low duty cycle--and the number of
(audible) periods between decrements in volume.

-michael

NadaNet and AppleCrate II: parallel computing for Apple II computers!
Home page: http://home.comcast.net/~mjmahon

"The wastebasket is our most important design
tool--and it's seriously underused."