Welcome Guest



Remember me

[ ]
[ ]
[ ]


Listeners: 9 (Peak: 66)
Songs: 36181, Authors: 6123
by JC
BitJam 221 - Out Now!

Search BitFellas

Search BitJam:

Search Modland:

Scene City

content search


The C64 Digi - C=hacking issue 20

on Mon 21 May 2007 by Robin Harbron, Levente Harsfalvi, Stephen Judd author listemail the content item print the content item create pdf file of the content item

in Tutorials

comments: 0 hits: 8945

The C64 Digi
=============> Robin Harbron Levente Harsfalvi Stephen Judd


Digis -- digitally sampled audio -- are fairly common on the 64. This is
meant to be a comprehensive article on digis: how they work, examples,
different playback methods on the 64 (volume register and Pulse Width
Modulation), and some tricks. We'll even show you how to play 6-bit and
even 8-bit digis in high quality on a 64, which is really pretty neat to

The first part discusses digis from a fundamental point of view -- just
what a digi is, acoustic signals, and things like that. The most common
method of playing digis is via the volume register at $d418, and the next
two sections are devoted to this technique. Section two discusses some
SID fundamentals, and the reason why $d418 may be used for digis (and why
later-model SIDs don't play digis correctly); Section three discusses
$d418-digis from a software perspective: how to play them, tricks for
improving them, how to boost digis on 8580 SIDs, and how to detect what
kind of SID (6581 or 8580) is in the machine. The fourth and final part
of this article discusses pulse width modulation, and includes example source
code and a binary that plays a true 7-bit digi at around 16KHz -- something
which, we think, has never been done before.

Without further ado...

Digis: Overview

The whole point of playing a digi on a 64 is to provide something
for your ear to hear. So let's begin by discussing just what an acoustic
signal is and how that relates to digis.

Probably everyone knows that "sound" is how your ear responds to
changes in air pressure -- that is, when you clap your hands together,
it compresses the air between your hands in a special way, and that
higher pressure moves outwards into the surrounding air (since it's at
lower pressure). That pressure change propagates along and when it
encounters your ear it causes the ear drums to move, causing three little
bones to move, causing some fluid to move, causing tiny, exquisitely
sensitive hairs to move, transmitting a signal that your brain converts
to "sound".

An audio speaker also changes the air pressure in response to a
signal. If you take a coil of wire and change the voltage on it, it
generates a magnetic field; if a magnet is placed inside the coil, the
changing magnetic field will place a force on the magnet, causing it to
move, causing some air to be pushed along, causing a change in pressure,
causing a signal to propagate to your ear which your brain interprets as
Van Halen. All a stereo (CD player, etc.) does is send a varying voltage
signal to the speaker. As that voltage level goes up and down the magnet
moves back and forth, and so the speaker converts that electrical energy
into an accoustic wave.

For us, the trick is to coax SID into sending a specific voltage
signal to the speaker, the way a stereo or CD player might. And a CD player
is of course a very apt comparison, since it is itself a digi player.

Just for reference, a really good pair of ears can hear signals from
around 20Hz to 22KHz, with the sensitivity dropping considerably outside
of around 100Hz to 10KHz. A CD player has a playback rate of 44KHz, and
the highest frequency SID can generate from the frequency registers is
around 4KHz. If you've ever set SID to maximum frequency and heard just
how high 4KHz is, you can appreciate that even 10KHz is _really_ high, and
actually quite difficult to hear. In human speech, most of the information
content of vowel sounds is contained in the range 300Hz - 3KHz, and above
around 1KHz for consonant sounds; most information in musical sounds is in
the range 100Hz - 3KHz.

Discrete Sampling

To understand digis a little better, consider the more general
case of a discretely sampled signal -- a continuous signal sampled at
discrete time intervals. Let's say we had some device producing a
_continuous_ sinusoidal signal in time:

* *
* *
* *
* *
* *
* * *
* * *
* *
* *
* *
* *
* *
* *
-----------------------------------------------> time

(yes, I did miss my calling as an ASCII artist)

To turn the signal into a _discrete_ signal, we simply sample the
signal at discrete intervals of time. For example, let's say the above
signal lasts one second, and is input into a device which measures the
value every 1/4-second. The device will spit out four numbers: 0, 1, 0,
and -1:


* *


The sampling frequency here is four samples per second -- 4 Hz. If we were
to then play back this signal at the sampling frequency, we'd get a signal


********** **********


So one thing sampling does is to "staircase" a signal -- the sample becomes
some sort of "average" value over the sample period. Increasing the sample
rate -- taking more samples per second -- will smooth things out, and the
sampled signal will look (and sound!) more like the original signal.

Now let's say we just took two samples in that one second -- 2 Hz sampling
rate -- and just happened to catch the signal at its maximum and minimum
values (the peak and trough). Upon playback, the signal would look like


That is, a square (pulse) wave. If you're on the ball, you've noticed
that the frequency of the new signal is 1 Hz -- exactly half the sampling
frequency. This is also called the Nyquist frequency. In general, the
_maximum_ frequency that can be captured in a discrete sample (called the
Nyquist critical frequency) is half the sampling frequency -- as you can
see above, it takes two data points to get a single (nonzero) frequency.
So, for example, the highest frequency a CD player -- which has a sampling/
playback rate of 44KHz -- can capture is 22KHz, well above the range of
normal human hearing.

Thus, increasing the sample rate increases the frequency range captured
in the discrete signal. This is why a digi at a high sample rate in general
sounds better than a digi sampled at a low sample rate.

BUT -- there is more to life than sample rate: there is also sample
resolution. The sample resolution -- 4-bit samples, 8-bit samples, etc. --
determines how accurately the sample measures the actual signal. For
example, let's say we sample sin(x) when x=0.5:

sin(0.5) = 0.4794255...

No matter what sample resolution we use, there will always be some error
in the measurement, and the _true_ value of the sample will be the
_measured_ value plus some error.

In general the sampling errors are random and uniformly distributed, so
the sampled signal corresponds to the original signal plus some noise (the
random errors). That is why you almost always hear some sort of hiss on
a normal C64 digi, which uses a resolution of 4 bits per sample.

So, increasing the sample _resolution_ decreases the amount of noise introduced
into the sampled signal (and increases the dynamic range), and increasing the
sample _rate_ increases the frequency range.

If you're _really_ on the ball, you've noticed that the 1-Hz square pulse
above actually contains frequencies higher than 1Hz, simply because a
square pulse contains higher harmonics in addition to the 1Hz fundamental
frequency. And you've also no doubt realized that the sampled pulse wave
would sound different than the original sine wave (due, of course, to the
added harmonics) -- it's at the right frequency, but it will sound like a
pulse wave instead of a sinusoid.

Have we somehow broken the Nyquist limit?

The answer is no, because of a nifty thing called the Discrete Sampling
Theorem, which says that, given the samples h_n of a bandwidth-limited
function h(t), the original function h(t) is given by

h(t) = dt * Sum{ h_n * sin(2*pi*f_c*(t-n*dt)) / (pi*(t-n*dt)) }

where dt is the sampling period and f_c is the cutoff/critical frequency.

What this means is that the original signal can be _reconstructed_ from the
discrete samples, not that it is _equivalent_ to the discrete samples.
The Nyquist limit is the highest frequency that can be _reconstructed_ from
the discrete samples, not the highest frequency that will be produced if you
"staircase" the discrete samples through a speaker. If the original
signal is bandwidth-limited, and there are at least two samples for the
highest frequency, then the signal can be completely reconstructed.

Since a "normal" digi contains all these extra frequencies, shouldn't a digi
sound "different" than a "true" analog signal? Sure. On the other hand, many
of the extra frequencies are beyond the range of human hearing, and the rest
can often be removed using a filter -- all CD players filter the output, for
example. So sometimes it is worthwhile to turn on a low/band pass filter
when playing a C64 digi, especially at lower sample rates.

And that more or less summarizes basic discrete sampling theory.

D418 Playback -- Hardware

The SID contains both analog and digital subparts on one silicon plate -- in
other words, it is a mixed signal device.

At the time, the SID was certainly the best of the microcomputer sound chips.
This may be mostly due to its mixed signal design, which the designers used
to solve certain problems.

The hard thing in a sound generator design is to implement waveforms, volume
control, and mixing. Things like that don't really fit into the digital
'either 0 or 1' philosophy, unless lot of data bits and arithmetic functions
are involved. In a fully digital sound chip, the waveforms could be generated
by ROM lookup tables. The mixing function could be derived from binary
addition, while the volume control from division or multiplication. Unless the
sound functionality is greatly simplified, the arithmetic functions must be
present and they must be implemented in hardware. Finally, the D/A conversion
could be done by (fast) pulse width modulation just at the output stage.
(Most of today's wavetable sound cards operate like this).

This method implies heavy arithmetic hardware, which was not an option for
designers back then. Still, most sound chips were fully digital, and all
suffer from the required compromises (i.e. generating square waves only,
no dedicated channel volume control, etc. - both TED and the VIC-I are obvious

The solution that one finds in the SID design is very straightforward: mixing
and variable volume level is problematic in a digital circuit when dealing
with waveforms, so simply avoid doing it. In the SID, only the microcomputer
interface, the registers, the oscillators (phase accumulating oscillators),
and other controller logic are digital; the mixing and volume control parts
are fully analog. There are digital to analog converters providing analog
voltage levels from the digital state variables. The SID D/As are in fact
'multiplying' D/As, having an analog input (AIN), an input base voltage
(IBASE), and a digital input. They operate by amplifying the input voltage
offset (AIN-IBASE) by a factor proportional to the number on the digital input
and adding this offset back to the base level.

This mixed signal design also allowed some other features to be implemented.
The most important one is the analog filter (that is, a two integrator loop,
bi-quadratic filter, according to Yannes). With that, the SID points beyond a
home computer sound chip - it is a true analog subtractive synth (marketing as
such was cancelled because of manufacturing capacity reasons).

Here is a detailed map on the SID inners (analog path; probably my most
beautiful ASCII ever ). Info can be found in the SID patents (US 4,677,890;
1986), the MOS 6581 technical document (can be found somewhere on the Net), or
the back of the Programmer's Reference Guide (PRG).

----------------- 11bit ------------
|Cutoff freq reg|-------->|Cutoff D/A|---------o
----------------- ------------ |
$d415-16 |
----------------- 4bit ------------ |
|Resonance reg. |-------->|Reson. D/A |-o |
----------------- ------------- | |
$d417.[4-7] | |
| |
=0 v v
----------- ----------- >o------------>| ------------------
|wave D/A |--->|env. D/A |-->o/ | | |
----------- ----------- o--->| | | |
^ ^ ^ =1 o--------|--->| |
|12bit |8bit | | | | |
| | | | | | |
----------- ----------- | | | | |
|OSC1 + | |ADSR cnt+| | | | | |
|wave sel.| |env. log.| | | | | |
----------- ----------- | | | | |
$d400-03, $d405-06, $d417.0 | | | |
$d404.[1-7] $d404.0 | | | FILTER |
| | | |
=0 | | | |
----------- ----------- >o----|------->| | |
|wave D/A |--->|env. D/A |-->o/ | | | |
----------- ----------- o--->| | | |
^ ^ ^ =1 | | | |
|12bit |8bit | | | | |
| | | | | | |
----------- ----------- | | | | |
|OSC2 + | |ADSR cnt+| | | | | |
|wave sel.| |env. log.| | | | | |
----------- ----------- | | | | |
$d407-0a, $d40c-0d, $d417.1 | | | |
$d40b.[1-7] $d40b.0 | | | LP BP HP |
| =0 | ------------------
=0 | >o->| | | |
----------- ----------- >o----|--o/ | *** o o o
|wave D/A |--->|env. D/A |-->o/ | o- | / / /
----------- ----------- o--->| ^ =1 | =0 V V V =1
^ ^ ^ =1 | | | o o o o o o
|12bit |8bit | | | | | | | | | |
| | | |$d418.7 |<-------o | |
----------- ----------- | | |<------------o |
|OSC3 + | |ADSR cnt+| | | |<-----------------o
|wave sel.| |env. log.| | | |
----------- ----------- | | |
$d40e-11, $d413-14, $d417.2 | |
$d412.[1-7] $d412.0 | | -----------------
| | | Master volume |AUDIO
=0 | o--->| D/A |-----> >o----|------->| ----------------- OUT
EXT IN --------------------->o/ | ^
o--->| |4bit
^ =1 ^ |
| | $d418.[0-3]
$d417.3 ^ |
| |
Analog mixing ---|--------|

***: Filter type select switches, $d418.[4-6] respectively

$d418 digis

The most common method of playing a digi is to use the register at $d418.
When someone plays a digi using the master volume register, the situation is
similar to the waveform D/A converters. Both D/As are multiplying D/As --
signal amplifiers whose amplification is proportional to the input digital
number. If there is a nonzero signal offset on the D/A input it will be
multiplied proportionally by this number.

Playing digis with $d418 is possible because there is indeed a relatively
large DC voltage offset on the master volume D/A. This offset is present
right from the moment when the SID is powered up.

Where can this DC offset come from?

There is a mixer before the master volume D/A (see figure). If there's a DC
offset on the D/A input, it must come from there. ...And going further,
the DC offset on the mixer must also come from somewhere. But where?

Signals come from the three ADSR volume D/As, the EXTIN line, and the three
outputs of the filter. Fortunately, all paths that go to the mixer have analog
switches (all paths can be disconnected from the mixer individually, if that's

The above analog switches are driven by the filter selection bits ($d417 bits
0-3), the voice 3 off bit ($d418 bit 7) and the filter type selection bits
($d418 bits 4-6).

After a reset, the filter selector bits are all 0 (all signals are routed
towards the master mixer), the 'voice 3 off' switch is on, and the filter type
selector bits are 0 (filter outputs are unconnected). In this state, only
EXTIN and the three SID voice signals are present on the mixer. EXTIN can
be eliminated as the source since it has no DC offset (as long as the computer
was not hacked, see notes on the 8580).

The ADSR volume D/A is similar to the previously mentioned multiplying D/As.
If the digital number on the input is 0, the input analog signal offset can't
pass through (as measurements verify). This is the case when SID is reset,
setting the envelope counters to zero. Therefore, nothing behind the ADSR
multiplying D/As can have any effect on the DC offset of the mixer.

So, the DC offset must come from the ADSR multiplying D/As. Another
measurement shows that even the mixer itself has a small DC offset.

Tests and results

I did some tests that support this theory. They were done 'by hand', by simply
using a digital voltmeter + the FC3 monitor.

The chip was a 6581(R1), 0883, Hong Kong (an early 6581).

When turned on the voltage on the AUDIO OUT was about 5.5 volts (slowly
decreasing as it warmed up, stopping at about 5.43 after some 10 mins - all
subsequent tests were done after this time period).

Writing $0f to $d418 raised the output voltage to 6.15 volts. Therefore, the
maximum output amplitude that can be achieved when playing digis is 0.72 volts
in this 'mode' (without wiggling any other SID settings to achieve higher
voltage levels) -- remember that what counts is the maximum voltage
_difference_, not the maximum absolute voltage.

The next test is to determine if the mixer has its own DC offset (with all
possible paths are disconnected). It's possible to do. With the volume at
maximum (to maximize any effect), all voices are routed towards the filter
($d417 = $0f), while making sure that the filter outputs are not routed to the
mixer ($d418 = $0f). In this state no paths can drive the mixer. The result
is 5.39 volts. When the volume changes, the output also changes towards the
previous 5.43 volts --> there is a (very small) DC offset from just the mixer.

What could be the DC offset value of each individual SID voice (i.e. the base
level difference of the multiplying D/As)? Doing the above, but leaving one
voice routed to the mixer ($d417 = $0e, $0d or $0b) gives 5.69 volts.
5.69-5.43 = 0.26 volts, and 5.43 + 3*0.26 = 6.21, almost 6.15 volts.

To determine if the ADSR multiplying D/As act as expected, I used pulse
waves with zero frequency and 0 or $fff pulse width (two cases), to make the
input signal of the ADSR multiplying D/A the minimum and maximum possible
level. After careful checking, the output changed a few hundredth volts
(about 0.01 volt per voice). So the D/A doesn't close up completely, but
it's still O.K.

To prove that these offsets are equal for all voices, I did another test. Some
people know that the filter inverts phase (multiplies the input signal by -1).
Machine is reset, $d417 = $01, $d418 = $9f. (Voice 1 is routed through the
filter, voice 3 is cut off from the mixer completely ($d418.7), low pass
filter is selected, volume = $0f). The output voltage was 5.41 volts, just
very slightly below the "default" output level. This means that the DC of
voice2 + (-1*) DC of voice 1 resulted in about 0 relative offset. Doing
similar tests proved that the DC offsets for the voices match each other
almost exactly (within a few hundredths of a volt).

These measurements all support the idea that the DC offset comes from the
ADSR multiplying D/As, that the offset is mostly independent from the waveform
D/A converters (as long as sustain levels are 0), and that the offsets are
equal for all voices. In addition, a small DC offset is supplied by the master
signal mixer itself.

What if we try different sustain settings? For this test, set the volume to
maximum, as usual. Set the sustain level to $0f for all voices ($d406, $d40d,
$d414 = $f0). Start the attack, but with no waveform selected ($d404, $d40b,
$d412 = 01). The output level is now 5.21 volts, a little bit below the '0'
offset of the audio output! (Doing the test with just one voice (all
others disconnected), the output is 5.29 volts).

Finally, we can do some experiments with the pulse waveform. The pulse
waveform is useful for these tests, since at zero frequency we can set both
the minimum and the maximum constant DC levels at the voice D/A just by using
the pulse width registers. Reset the computer. Set voice 1 to zero frequency,
pulse level $0fff, sustain level 15, and $d404=$41 (pulse waveform + gate on).
Route only voice 1 through the mixer ($d417 = $0e). The output voltage is
similar to the test when no waveform was selected -- 5.29 volts! This seems to
show that "waveform accu = $0fff" is the same as when no waveform is selected
(i.e. the waveform D/A digital input pins are pulled high when they're not
driven, as seen in most other NMOS chips).

When the pulse width is 0 in the above test the output changes to 6.34 volts.
This seems to be strange (a multiplying D/A giving higher signal level for
multiplying something by 0).

Now, when the ADSR multiplying D/A is closed, the output is 5.70 volts. When
it's fully open, the output changes from 5.29 volts (wave acc= $fff) to 6.34
volts (wave acc = 0). One reasonable answer is that the base voltage of the
waveform D/A is higher, and the analog input is tied lower than the base
voltage of the ADSR D/A -- the effect is that the SID waveforms will lie
'around' the ADSR multiplying D/A base voltage, more or less symmetrically.

This was surely done intentionally, to reduce absolute voltage levels (for
linearity). In the 6581, the big DC offset is probably a result of having the
ADSR D/As and the master volume D/A at different base levels (the difference
appears as true DC offset on the master volume D/A). If both were the same
(presumably at VDD/2), and the waveform D/A parameters were selected similarly
(operation is symmetric to VDD/2), there would be no final DC offset at all.
Rather like the 8580...

Other issues

So now we know why $d418 digis are possible - but still, there are some things
to note.

The DC offset on the master volume D/A changes with different SID settings,
and whatever affects the DC offset on the mixer will affect the digi
volume. For example, even the filter output signals have a small DC offset.
Just do a test - set the volume to 0f, then simply turn one filter route on
(for example, $d418 = $1f). You'll hear a small click (i.e. a small DC offset
change on the mixer), even if the filter has no input.

Moreover, as seen above, the DC offset can be eliminated completely (just by
SID register settings), leading to no audible digi sound at the output. In
other words, whatever affects the DC offset on the mixer _will_ affect the
digi volume.

One place where this is important is playing a digi with a tune: there's a
constantly changing signal going to the mixer instead of a constant DC offset,
so playing a digi on the master volume also causes distortion for both the SID
voices and the digi sound (since they're cross modulated). To reduce this
effect most 3+1 like SID + digi players play samples by writing 8-offset sample
values to $d418 (ie. adding 8 to 3-bit sample values and writing this to $d418
- see players used by Jeroen Tel and other famous composers using digi). This
trick reduces the modulating effect while still maintaining good digi volume.

The DC offsets used to create awful clicking sometimes. For example, the
filter inverts phase. If the filter is currently routed to the mixer, there'll
be a large 'click' (2 times the DC offset) when a voice is on and its routing
is changed to or from the filter.

The 8580

This is a completely redesigned chip. I don't know details, but it was
probably redesigned by the time all other chips in the C64 were done for CSGs
new manufacturing technology and the C64c. It is a 'better' chip from the
technical side (but in my opinion it sounds crude in comparison to the 6581,
at least the R4 series). The 6581 was designed in months. Bob Yannes had to do
everything from scratch and use the manufacturing technology MOS currently had
(NMOS). And it shows. First, it has high background noise. The DC offsets are
really also a misfeature. The D/A converters are sometimes non-monotonic (at
least, the waveform D/As and the filter cutoff D/A have some drops at the
change of the most significant bits). The op-amps in the active (resonant)
filter are simple, linearized NMOS inverters (loopbacked, they act like
more or less linear op-amplifiers around VDD/2). And I still haven't mentioned
bugs in the digital side (ADSR envelope bugs). Because of the above, one
probably won't find two identical 6581 chips -- each sounds a little bit
different (mostly due to the filter). Since the active components of the
filter are far from ideal, the filter is strongly nonlinear (the cutoff curve
changes with signal amplitude). On the other hand, these things are what make
the SID sound so unique.

Most of the problems were fixed in the 8580. It has much less background
noise. The chips sound the same (there are hardly any differences between
different 8580s). Most of the DC offset issues (the clicks) were elminated. It
needs less power, and lower VDD level. Something was changed also in the
digital logic, but the ADSR part was not touched. The 'combined' waveforms are
a bit different (and more useable from the musician's point of view).

The clicks were reduced, which means that there is no (or no significant) DC
offset on the master volume D/A in the 8580.

(I have not done any measurements, but after listening to a lot of 3+1 channel
type musics, I have a strong suspicion that even if sounds are turned on, the
average DC offset on the master volume D/A is still minimal).

To fix this in software, you'll have to wait until the next section of this

To fix this in hardware, people use a simple hack: take a resistor of about
330k and tie the SID EXTIN line to GND through that (directly, beside the
chip, on the mainboard).

The EXTIN line goes directly to the mixer, and thus the master volume D/A, or
can also be routed through the filter. In either case, unless the filter is
disconnected, the above hack will give a pretty large DC offset, similar to
the original 6581s. So, digi sounds can be played (even with SID music
playing simultaneously, similar to the 6581).

This solution is good as a work around, but there's one thing to note: this is
not completely the same as the 6581 ADSR D/A offset voltage. At least, this
offset is negative (should that pin rather be tied to VDD?). Programs that
depend on the 6581s way of DC offsets will not work correctly (but I know of
very few such programs, so at worst you'll experience slightly different digi
sound only occasionally -- but hey, the 8580 sounds different anyway). Another
problem is that when EXTIN is routed through the filter the DC offset may
cause strong distortion since the DC operating point of the filter is changed
-- bad news if the 'semi-linear' amplifiers in the filter are picky about
absolute DC level. Some music (not neccessarily involved with digis) indeed
do route EXTIN through the filter, for noise reduction on older C64s (with the
earlier C64 mainboards that pick up lots of 'digital' background noise from
EXTIN). DC distortion can also occur occasionally for the same reason but on
the master volume D/A (the higher the difference from VDD/2, the greater the
risk of experiencing nonlinearity and clipping distortion).

Some final words

A lot of this information comes from Dag Lem, who is certainly the No. 1 SID
hacker for me . Take a look at reSID, his SID emulator library (the sources
can be downloaded from somewhere). reSID contains so much reverse engineered
information of the real SID that you won't believe it -- check it out if
you're interested.

D418 Playback -- Software

$D418 digis are by far the most common playback method. The volume register
gives 16 different amplitudes (0-15), and so can provide 4-bit digi playback.

In its most basic form, this is an extremely easy routine to code. Simply
load each 4-bit sample, and store it in the volume register ($d418).
Assuming $fd/$fe are pointing to the beginning of a series of samples, the
following code will play it back:

ldy #0

:loop lda ($fd),y
sta $d418

ldx #5 ;some delay value
:delay dex
bne :delay

bne :loop

inc $fe
jmp :loop

The ldx #5 would have to be adjusted depending on the speed of the
sample - the lower this number (not including zero) the faster the
sample will play back.

There are a number of improvements we could make to this code - first
of all, this method takes twice as much RAM to store the sample as is
necessary. Because we're dealing with 4-bit samples, we can store 2
samples in each byte. This can be handled simply by alternately
masking out the high bits (with AND #15) to play the sample stored in
the low nybble, and by shifting the high nybble down to the low nybble
to play the high nybble (LSR : LSR : LSR : LSR). A lookup table may also
be used to save processor cycles (but use more RAM).

Another improvement is to move the routine to zero-page, and use self-
modifying code. In general, this results in the fastest digi players.

We should of course have the routine check for the end of the sample --
typically just checking the high byte of the zero-page pointer is enough
(in this case, checking $fe). Typically digis are page aligned anyway, so
just zeroing out the unused part (if any) of the last page is fine.

Finally, it is often important that each sample of a digi is played back
at regular intervals. If the samples aren't played at a steady speed,
extra distortion is audible. In the example above, playback is steady
for a full page (256) of samples - but several extra cycles are added
by incrementing the zero-page pointer to the digi. The situation
worsens when we start adding extra code to check for the end of the
digi, and even the main loop starts getting irregular when we add the
code for the simple form of packing discussed earlier (2 4-bit samples
per byte).

These problems can be solved by careful cycle counting and adding NOP
and harmless BIT instructions in strategic places to make each
iteration the same number of cycles, regardless of which branch is
taken - people who have written a stable raster routine, or done some
Atari 2600 coding have likely done this sort of painstaking work

NMI-driven digis

More commonly, however, we enlist the help of CIA #2 and have it
generate regular Non-Maskable Interrupts which we use to call our digi
player. This has two important advantages - first, it makes timing
much more simple. Second, it frees your main program to do other
things while the digi is playing "in the background".

To experiment, I pulled a 4-bit packed digi from the extras disk
included with Super Snapshot 5.22. It's the beginning seconds of the
introduction to Classic Star Trek (Space, the Final Frontier).

Here's the source for a fairly "frills-free" NMI based digi player,
with my comments after blocks of code:

start = $1400
end = $7cff
freq = 141
ptr = $fd

Labels start and end simply point to the beginning and end of the
digi. Freq isn't actually the frequency - it's the number of
processor cycles between interrupts necessary to play the digi at the
desired speed/pitch. If you know the frequency (in hz) of the digi,
simply divide your CIA clock speed (approximately 1000000 hz) by the
digi frequency. In this case, the digi runs at approximately 7100 hz.

We use two zero page locations to form a 16-bit pointer to the current
sample in the digi to play.

*= $1000

;disable interrupts
lda #$7f
sta $dc0d
sta $dd0d
lda $dc0d
lda $dd0d

This code simply disables interrupts and initializes both CIA timers.

;blank screen
lda $d011
and #255-16
sta $d011

Just like erratically timed code can introduce distortion when a digi is
played back, the VIC steals cycles from the processor that can cause
interrupts to not occur precisely when you'd like them to. This routine will
work without the screen blanked, but the extra noise introduced when the
screen is on is noticeable when the time between samples is less than around
2.5-3 times the time the processor is stopped. Another option is to use some
multiple of the raster timing as the sampling rate, and start the routine on a
non-badline, to ensure that the interrupts never occur on a badline. (A final
option is to use a raster-driven interrupt for the digi; with the SCPU, it is
actually possible to drive an IFLI display and play a digi at the same time,
badlines and all -- email Robin for more info, or maybe wait for a future
article!). But the simplest thing to do is to blank the screen .

;switch out roms
lda #$35
sta 1

;point to our player routine
lda # sta $fffa
lda #>nmi
sta $fffb

Unless using the KERNAL routines is necessary in my program, I always
switch out the ROMs. One of the biggest benefits is that our NMI
routine will be immediately called, rather than using $0318/$0319 and
waiting for the KERNAL to indirectly call your routine.

;initialize player
lda # sta ptr
lda #>start
sta ptr+1

ldy #0
sty flag
lda (ptr),y
sta sample

This section simply initializes the various memory locations that the
player uses - sets ptr/ptr+1 to point to the beginning of the digi,
loads the first sample, and clears the flag that handles the
alternating between the lower and upper nybble of the packed samples.

;setup CIA #2
lda # sta $dd04
lda #>freq
sta $dd05

Sets Timer A on CIA #2 to freq.

lda #%10000001
sta $dd0d

Enables Timer A interrupts on CIA #2.

lda #%00010001
sta $dd0e

Sets Timer A to run in continuous mode. As soon as Timer A counts
down to zero, it will automatically be reloaded to the last writes to
$dd04/$dd05 and begin counting down again.

endless jmp endless

For this example, we just put the computer in an endless loop.


;play 4-bit sample
lda sample
and #15
sta $d418

We play the sample while all the code is still linear - before any
branches have occurred. This is to minimize the distorting effects I
mentioned earlier. The AND #15 is used so we don't inadvertently
enable the filter bits in $d418 with the high nybble packed into

;clear NMI source
lda $dd0d

By reading $dd0d, we are acknowledging the source of the interrupt,
and the CIA will now generate another interrupt next time Timer A
counts down to zero.

;just something to look at
inc $d020

;every other NMI do 1) or 2):
lda flag
bne lower

Now we deal with "unpacking" the samples.

;1) shift upper nybble down
upper lda sample
lsr a
lsr a
lsr a
lsr a
sta sample
jmp exit

When flag is set to zero, we shift the high nybble of sample down to
the low nybble so it's ready to be played next NMI.

;2) get a new packed sample
; then point to next
lower ldy #0
lda (ptr),y
sta sample
inc ptr
bne checkend
inc ptr+1

When flag is set to one, we load a new packed sample into sample, and
point ptr at the next packed sample.

;if end of sample, point to
;beginning again
checkend lda ptr
cmp # bne exit
lda ptr+1
cmp #>end
bne exit

lda # sta ptr
lda #>start
sta ptr+1

Simply check for the end of the digi, and if we've reached it, loop
back to the beginning of the digi.

;toggle flag and exit NMI
exit lda flag
eor #1
sta flag


;sample's lower nybble holds
;the 4-bit sample to played
;next NMI - the upper nybble
;holds the next nybble to be
;played on "odd" NMIs, and is
;undefined on "even" NMIs.
sample .byte 0

;flag simply toggles between 0
;and 1 - used to decide whether
;to play upper or lower nybble
flag .byte 0

Improving D418 Digis

D418 digis tend to generate a lot of noise, because, of course, the 4-bit
sample resolution. Over the years people have come up with numerous tricks to
improve the sound of a d418 digi; here are some that we know of and have tried.

The first, and most obvious, thing to do is to use the low-pass filter, since
a lot of the noise is at higher frequencies. Unfortunately this won't work,
since the filters occur in SID before the volume amplifier -- all the filters
can do is change the DC offset that makes the digi possible. This trick
will work for methods that use SID voices, however (such as Pulse Width
Modulation, discussed in the next section).

Another trick is to "dither" the sound, as discussed in C=Hacking #11. The
idea here is to generate an intermediate "average" value by toggling between
two values. For example, if d418 is set to '8' half of the time, and '9' the
other half, its 'average' value will be 8.5. So this is somewhat like adding
an extra bit of resolution. In principle, you can extend this further: if it
is '8' one-third of the time and '9' for the remaining two-thirds, the average
value will be 8.66. And so on.

Now, we aren't _really_ increasing the sample resolution here, but are instead
increasing the sample playback rate -- we're playing two samples ('8' and '9'
for example) where before we played just one. Don't get too carried away
thinking about "average" voltage levels (after all, there is an average
voltage for the entire digi but that's not what you hear!) -- what's important
is how well the sampled signal represents the original signal. If the
original signal is rising from 8 to 9 during the sample interval, this type
of trick will work well.

Which leads us to another trick: interpolation. This is really a compression
trick, more than a 'resolution' trick. Let's say that one sample value is 5,
and the next value is 9. It might be reasonable to expect an 'intermediate'
value of 7, to play right after the 5. Once again, the idea is to increase
the playback rate to better-represent the original signal. This type of trick
increases the playback rate without increasing the amount of data -- and as
always, your mileage may vary. Many modern soundcards and CD-players use

Another curious trick is to add noise to the signal -- that is, the 4-bit
sample corresponds to the original signal plus noise. Sometimes, by adding
noise to the signal playback the noise can actually cancel! The 'dithering'
trick above can be viewed in this way.

Boosting 8580 Digis

As most people know, there are 'old' SIDs (6581) and 'new' SIDs (8580), and
$d418 digis do not work right on 8580 SIDs, (such as in the 128D, most 128s,
and the 64C) for the reasons discussed earlier -- the 8580 does not have a
residual voltage leading into the amplitude modulator.

The software fix for this is pretty simple: have SID generate a signal, and
hence a voltage, for the volume register to modify. You can actually use
pretty much any waveform to do this, but a pulse is the simplest, since a
pulse wave just toggles between two voltage levels. Moreover, page 463 of
the PRG says, "The TEST bit, when set to a one, resets and locks Oscillator 1
at zero until the TEST bit is cleared. The Noise waveform output of
Oscillator 1 is also reset and the Pulse waveform output is held at a DC
level." So it's not really necessary to worry about the frequency or pulse
width, by using the test bit.

BUT -- it is very important to set the sustain level to $f. The ASDR envelope
generators generate the voltage. A sustain level of 0 gives no improvement.

So, to 'boost' a digi on a later-model SID, you can just turn on a pulse with
the test bit set:

STA $D406
LDA #$49
STA $D404

Setting more voices gives the digi a substantial extra boost:

STA $D406
STA $D406+7
STA $D406+14
LDA #$49
STA $D404
STA $D404+7
STA $D404+14

The moral is: if you're writing a digi routine, and want it to work on all
computers, be sure to boost the digi.

And for completeness, using more channels is a commonly used trick to enhance
digi resolution on the Plus/4. The TED digi resolution (the volume register)
is 3 bits. Fortunately, all channel on/off bits + the volume level are in the
same register ($ff11). If one source is on, the output DC is about half of the
level when both are turned on. This trick can be extended further to results
in a 'semi 4-bit' or 5-bit digi table (the dynamic range is enhanced, but
there are larger steps at the table end than at the start). This trick could
also be used in SID if the sound sources were accurately preset, but runs into
problems due to the non-matching SID-versions and having the control bits in
multiple registers.

SID Type Auto-Detect

The following routine will detect what type of SID is in use. I've
tested it on a fair cross-section of my collection of computers - my
NTSC 128D, two 64Cs, two "breadbox" C-64s, and my PAL breadbox 64. In
all cases the code performed 100% accurately - but still, there may be
cases where it fails. I'd be interested to know if anyone finds any
faults in the routine, so I can improve it!

How does the routine work? I was told that the old SID (6581) and the
new SID (8580) behave differently when set to play combined
waveforms. I coded a fairly simple routine to use the REU to sample
$d41b (the upper 8 bits of Oscillator 3's waveform output) for a full
64k bank. Then I experimented with various frequencies and
combinations of waveforms on Oscillator 3 until I found consistently
different results with the two different SIDs.

When I combined the triangle and sawtooth waveforms and then sampled
$d41b I found that most of the time the oscillator was just putting
out zeros, with occasional bursts of numbers. These "bursts" were
consistently near $ff on the 8580, while the 6581 was always well
below $80 - often $3f was the highest it would get.

So, the detection code ended up being quite simple - I'll explain each
block of code:

*= $4000

start sei
lda #11
sta $d011

Disable bad-lines (by blanking the screen). This prevents badlines
from interfering with the detection process.

;sid setup here!
lda #$20
sta $d40e
sta $d40f

Set Oscillator 3's Frequency Control to $2020. I just randomly chose
this value when experimenting, and it worked, so I kept it. The trick
here is to set a value fast enough that the oscillator will make a
number of cycles (so we can get a good sample of the values coming
out) but not so fast that it might miss any of the "bursts" I was
mentioning earlier.

lda #%00110001
sta $d412

Combine the triangle and sawtooth waveforms and start the ADSR cycle.

ldx #0
stx high

loop lda $d41b
cmp high
bcc ahead
sta high
ahead dex
bne loop

This loop takes 256 samples of Oscillator 3's output, saving the
highest value in location high.

lda #%00110000
sta $d412

Stop Oscillator 3.

lda #27
sta $d011

Turn the screen back on.

lda high

high .byte 0

Return from the routine with the highest value sampled from Oscillator
3 in the accumulator. This allows you to branch based on the high

bmi SID8580
bpl SID6581


Pulse Width Modulation

The primary limitation of using the volume register is, of course,
that it is only 4-bits. Pulse width modulation (PWM) allows us to get
around that limitation.

In general, there are lots of ways of transmitting information.
If you've ever used a radio you've encountered both amplitude modulation,
where the signal is encoded as the amplitude of some carrier wave, and
frequency modulation, where the signal is encoded by changing the frequency
of the carrier wave. In both cases, the idea is to strip out the encoded
information and throw away the carrier.
Yet another possibility is pulse width modulation: use a pulse
wave at some carrier frequency, and modulate the pulse width. Pulse width
modulation has several nice properties for transmitting signals; we can
take advantage of it to play digis.

Pulse waves, of course, take on only two possible values: zero and
one (low and high, etc.). Over a single period, a pulse wave will in general
be low for some amount of time and then high for some amount of time.
The _duty cycle_ of a pulse wave is the amount of time it spends in the high
state compared to the total period. For example, a square wave, which is
low exactly half the time and high the other half, has a duty cycle of 50%:

______ ______
| | | |
| | | |
_____| |____| |____ ...

Remember that, regarding SID, a signal like the above is simply a voltage
level. What is the _average_ voltage over a single period? Since a square
wave is zero half the time and one the other half the average value is
just 1/2. If instead the pulse had a duty cycle of 75%, it would be low
for 1/4 the cycle and high for 3/4, giving an average value of 3/4.

So the _average_ value of a single pulse is simply the duty cycle. So if
we change the duty cycle for each pulse we can essentially generate a
series of average voltage values -- and since a digi is nothing more than
a series of average signal values, we can use PWM to play a digi.

To make this more precise, let's say we had a digi sampled at 1KHz -- one
thousand samples per second. Since each sample value will be approximated
by a pulse, we need one thousand pulses per second. The duty cycle of
the first pulse will be the first sample value, the duty cycle of the
second pulse will be the second sample value, and so on. Note that
the sample rate is the carrier frequency -- the frequency of the modulated
pulse train, 1KHz in this case.

(Actually, to be more accurate, we need _at least_ 1000 pulses per second --
for example, we could use 2000 pulses per second, and represent each sample
value using two pulses. So the more correct statement is that the pulse
carrier frequency is the maximum sample playback frequency.).

The advantage for playing C64 digis is that we have much more resolution
for the pulse width, and probably not in the way you think! Because you
are probably thinking that SID has this nice 12-bit pulse width that
we can use here. The problem is that the absolute highest frequency SID
can produce, using the frequency registers, is about 4KHz, which would
be the maximum playback rate.

There's still another catch -- the carrier wave is still there! Imagine
trying to encode a signal that was constant, say 1/2 everywhere. To
generate a "digi" value of 1/2, you'd use a square wave, half down and
half up. So while the _average_ value of each pulse would be 1/2, the
actual signal would be a square wave at the carrier frequency (look at
the little picture above if you don't see it -- its average value is 1/2).

Trying to modulate a 4KHz carrier wave results in a piercing 4KHz tone,
and a _maximum_ sample rate of 4KHz (and this assumes that you can sync your
code up exactly with SID). So that's pretty worthless for digis.

- BUT -

What if we could change the voltage level manually? Let's say some
hypothetical machine language program toggled the voltage level
on each machine cycle -- the result would be a square wave of
frequency 0.5 _mega_ hertz. Okay, let's say it changed the voltage
level every 10 machine cycles -- the result would be a carrier
frequency of around 50 KHz. The point here is that a machine language
program can generate its own pulse waveform, and do so at much higher
frequencies than SID can produce.

Toggling the voltage levels turns out to be very simple. As was
described earlier, the way to "boost" digis on later SIDs is to use
a pulse waveform at frequency zero. Depending on the value of the
pulse width register, SID will set the output voltage to either high
or low. So all a program has to do is set up a pulse waveform at zero
frequency and use the pulse width registers to toggle the voltage --
set $d403 to either $00 or $ff to toggle low/high. (You could also use
$d418 to toggle low/hi, but this method should produce more uniform
results, and unlike $d418 can be filtered).

So now we're cooking -- we've got a program that can generate a pulse
train. The next step is to change the width of each pulse to represent
the sample values in our digi. Remember that the duty cycle -- the
percentage of time the pulse spends high -- is the average value for that
pulse. But also remember that each digi sample represets an average
value over the sample period. If the pulse period is equal to the sample
period, then _the duty cycle is exactly the sample value_!

Example: let's say that we have an 8-bit sampled digi, so that values go
from 0-255, and our program generates pulses with a period of 256 "ticks".
Now pick a sample value, say 56. All the program has to do is hold the
pulse high for 56 "ticks", and low for the remaining 255-56 = 199 "ticks",
and it will have the correct average value: 56/256. So a program to play
8-bit samples might look like

1 - Load .X with next sample value
2 - Load .Y with 256-.X
3 - Set pulse high
4 - Loop for .X iterations (each loop iteration is one "tick")
5 - Set pulse low
6 - Loop for .Y iterations
7 - Loop back to step 1

Let's say that each "tick" takes m cycles, and the sample size is 2^n, so
that there are 2^n ticks per sample. A stock machine runs at around
10^6 cycles/second, so...

(10^6 cycles/second) / (2^n ticks/sample * m cycles/tick)
= 10^6 cycles/second / (m * 2^n cycles/sample)
= 10^6 / (m * 2^n) samples/second

So, for example, let's say we had n=6-bit samples -- 2^6 = 64 -- and could
generate pulses with a resolution of one machine cycle -- m=1. Then
we could play that 6-bit sample at 10^6/64 = 15.6KHz. That is _really
very good_! In principle -- possibly using the CIA timers, possibly using
fixed delay loops, possibly using a massively unrolled loop -- this can
be done on a stock machine. (I did try using the CIA timers, but the
number of cycles to set up the timers was too big, and made it sound poor;
I've included the code below though.)

At this point it becomes a numbers game. As we increase the sample size
(increase m or n above), we _decrease_ the sampling rate -- if, in the
above example, we instead use 8-bit samples, the sampling frequency drops
by a factor of four to around 4 KHz. So there's a tradeoff between
resolution and sampling frequency.

AND... we still have this issue of the carrier frequency. You should be
able to convince yourself that the sampling frequency above is exactly
the carrier frequency. So with the 8-bit resolution example there
would be an awful 4KHz tone running through the playback. There are
only two ways to beat the carrier frequency: push it high enough that
you no longer hear it, or else push it high enough that you can use the
filters to dampen it down.

How high is high enough? You can judge for yourself, but 15 KHz is
pretty tough to hear, unless you have good ears and the volume is really
loud -- so 6-bit samples are within reach on a stock machine.

But add a SuperCPU into the picture, and the numbers get _really_ nice.
Everyone knows that a SCPU can interact with the C64 at 1MHz, and
hence generate pulses with 1MHz resolution, using code like

lda #$ff
sta $d403 ;Set level high
:loop lda $d011 ;wait for C64 cycle
bne :loop

where .X contains the sample value. But what happens if we try to move
beyond that 1MHz? What if we put some NOPs into the above delay loop,
in place of the lda $d011? Well, in principle it means that the duty
cycles won't always be right, which corresponds to some sampling error.
In practice, however, it works _really well_! Consider what happens when
the above code is changed to:

bne :loop

The earlier formula still applies, but now using 20MHz cycles:

20 * 10^6 / (m * 2^n) samples/second

In this example each loop iteration -- each "tick" -- is nine 20MHz cycles,
giving a playback rate of approximately 17Khz for 7-bit samples. Which

And it can even be pushed to 8-bit samples (although I personally don't think
they sound any better, at least with the code I've tried; maybe the code can
be improved). Using loops like

beq :done
beq :done
bne :loop

it is possible to "fine-tune" the loop tick to somewhere between 4-5 cycles,
giving a playback rate between 15KHz and 19KHz, for an 8-bit sample. Pretty
cool. The code is also a little more involved (with 7-bit samples we can
use BMI for the loop branches; not so with 8-bits). But it really is
possible to play 8-bit samples at 19KHz on a C64 (plus SuperCPU).

Using two voices

You may be thinking, Hey, we've got three pulse waves to work with, can
we improve the performance by using multiple pulses?

Let's say we have two pulses, P1 and P2, with the same period. When both
are activated, the pulses simply add together -- that is, the total voltage
is just the sum of the individual voltages, and therefore the _average_
voltage is the sum of the individual pulse averages:

avg voltage = D1 + D2

where D1 and D2 are the duty cycles of pulses P1 and P2. In the simplest
case, this gives us an extra bit of resolution -- if D1 and D2 are both
7-bit values, say, then D1+D2 is an 8-bit value.


Consider, for a moment, what would happen if we were to change the amplitude
of the second pulse -- that is, let's say the maximum voltage it took on
was 1/16 of the maximum voltage of the first pulse. The average voltage
would then be

avg = D1 + D2/16

This then gives us _four_ extra bits of resolution, with each bit to the
_right_ of the decimal place. For example, if D1 and D2 are 4-bit numbers,
with D1=xxxx and D2=yyyy, then the avg will be a number like xxxx.yyyy
(four bits to the left of the decimal place and four to the right).

Of course, we can change the pulse amplitude by changing the sustain
setting, so in principle this gives a very easy and efficient way of
playing high-resolution digis. In practice, I have not been able to
make it work very well. I used a sustain setting of 1 and split an
8-bit sample into two 4-bit pulses; I believe the result sounds better
than 4-bits, but certainly doesn't sound anywhere near 8-bits. My
suspicion is that it is because the second pulse voltage is not really
1/16 of the first pulse, which corresponds once again to adding noise
to the sample value.

To find out, we can just measure the output at different sustain levels.
The following table gives the voltage output for voice 1 using a pulse
waveform at zero frequency and volume 15:

Pulse Width Diff
SU 000 fff 000 fff

0f 6.34 5.29 .08 .07
0e 6.26 5.36 .02 .01
0d 6.24 5.37 .06 .05
0c 6.18 5.42 .03 .02
0b 6.15 5.44 .05 .03
0a 6.10 5.47 .03 .02
09 6.07 5.49 .04 .02
08 6.03 5.51 .03 .02
07 6.00 5.53 .05 .03
06 5.95 5.56 .03 .02
05 5.92 5.58 .05 .02
04 5.87 5.60 .04 .03
03 5.83 5.63 .04 .02
02 5.79 5.65 .06 .02
01 5.75 5.67 .05 .02
00 5.70 5.69

Voice 2 is identical within a few hundredths of a volt. If this test is
repeated using voices 1 and 2 simultaneously, the result is:

Pulse Width
SU 000 fff
0f 7.30 5.25
0e 7.12 5.36
0d 7.09 5.37 (!)
0c 6.95 5.46
0b 6.88 5.49
0a 6.78 5.54
09 6.72 5.58
08 6.62 5.62
07 6.58 5.65
06 6.47 5.70
05 6.40 5.73
04 6.31 5.78
03 6.22 5.82
02 6.13 5.87
01 6.07 5.90
00 5.97 5.95

Note the weird step at $0d -- the response is definitely not linear!

Now, to summarize, when using one voice, the "positive" amplitude (about the
mean 5.70V) is .64V and the "negative" amplitude is .41V, giving a spread of
1.05V. With two voices together, the amplitudes are 1.33V, 0.72V, and 2.05V
respectively. If the two signals were simply added together, the numbers
should be 1.28V, 0.82V, and 2.1V.

What we originally wanted was a signal like

D1 + D2/16

that is, another pulse that is 1/16 the value of the 'full' pulse. 1/16 of
the positive amplitude is .64V/16 = .04V, and 1/16 of the negative amplitude
is .41V/16 = .026V. A setting of sustain level 1, on the other hand, gives
voltage offsets of 0.05 and 0.02, giving approximately

.64V / .05V = D1 / 12.8
.41V / .02V = D1 / 20.5

So, in summary, whereas I wanted D1 + D2/16, I was actually getting something
that varied from D2/12.8 to D2/20.5, even if the two voices summed together

There may still be a way to make all this work right, which would be great,
but I'm tired . The code from my attempts is below.

I also could not get two 7-bit pulses to sound like an 8-bit pulse. I took
an 8-bit pulse and divided it in half, assiging each half to a pulse
(and giving the extra bit to pulse 2, if an extra bit was present).
I suspect that another issue is that it is impossible to update both
pulses simultaneously, meaning some delay between pulses, which translates
to adding -- surprise! -- noise to the signal. Perhaps it would be
more effective at lower resolutions, however.

If someone has some success using these techniques I'd be interested in
hearing it.

SID lockups

Blindly applying these PWM algorithms has a way of locking up SID -- like,
locking him up hard. To be honest, I don't have a good explanation for why
this happens, and I haven't yet found a good method of prevention -- toggling
the test bit, playing a real sound for a short time, toggling the gate bit,
and so on, just don't seem to "initialize" SID reliably enough. Sometimes the
code works, and sometimes it doesn't -- it's the same code both times. Often
resetting the machine will make things work; I'm not sure what hardware resets
take place within SID, but the kernal certainly zeros him out so that's a
possibility. The other observation is that playing a tune seems to 'clear
out' whatever is blocking SID. So there _must_ be some kind of software
solution to the problem.

In the example code pressing RESTORE restarts the code, which will usually
clear the 'blockage' after a tap or two, if it happens.

If anyone has some thoughts on this issue (or even better, an explanation
of what is going on!) I'd love to hear them.

The Code

And that about sums stuff up, we think. All that remains is a zipfile
containing code examples of the things we've discussed. The archive
contents are:

digi-$1200.o pwm-2cia.d.s pwm-jmj pwm8.d.s
digi-$1200.s pwm-cia.f.s pwm.d.s
pwm-$1200.s pwm-cia.g.s pwm2.c.s

The main example program is "pwm-jmj", for the SuperCPU. This file contains
code at $1000 and a sample at $1200 (the sample is a sample I made on my
Amiga years and years ago, of Jean Michel-Jarre; it's really not very clean,
but it still sounds pretty nifty). So, to run it just load and SYS 4096.

You _need_ a SCPU to run it; it plays the sample at 7-bits and around 16KHz,
using pulse width modulation (pwm-$1200.s is the source code). If you want
to compare it to a 4-bit $d418 digi, just load "digi-$1200.o",8,1 and
sys 4096. The other files are different code experiments -- using two
pulses, using the CIAs, 8-bit samples, and so on (all written in Sirius,
of course) and may provide ideas for anyone wanting to experiment further.

If you want to try your own sample with the code, I suggest converting it
to RAW format. RAW format is just the digi, with no headers, and uses
signed 8-bit numbers. It's what I converted the sample to, and what the
code is designed to play!

Okay, enough talk -- go listen to that cool 7-bit 16KHz JMJ digi!

begin 644 digibin.zip
M4$L#! H ! -IQQIT41>R90 &L , 9&EG:2TD,3(P,"YO ""D
M E!(7RH)A?8-+,0OU;]&%:@Y;&1!(H!&%R0^:(3!8B, U!H%"%E XD,#$H,T
M(D -3ZL(T%)LA'E*7Q) 2G(JX4A-E(=6'95!TV=.'[1TYO:5VI<,#+1P+Z$E
M@- ()A8F 0%02P,$"@ 8 _&C'&I6%M,C P+G,,"@$3 @,$4TH%:OO[6P8 1;W]_>W 0)4V5 E2.))CR8%610KU*)2
MDS8MZI2J3I#0KS=O@,W3F2L'&1/F2YDR7*$ 7U#T$^E'@5),B:,YAM"?9K4
M6H.U!GY1[BB3GGM P0* 0 !@#Y:,<::WXHL L" !X P "P '!W;2TD,3(P,"YS3@<(K0/]
M'0,=" 5-!@@M!P,$!0@&" <6" 8%*!T$!00% Q4& P<&! 4D"!0%%@@&!1@-
M&/V-_OY^!/[^"!X(+@@.)P8>!@X'!@!GX$_NX/ 0(# @,"! ,T!AL%N_S
M_%9P3A7U: B<9J4AKS(-)IUS/=Q'O-X(/ K^RJ7S:.B4TO72>=S,DX_C" P=
MRJ;?SR;JF57A6-7#7%!+ P0* 0 !@#:,<:]D)"*[$" #P
M!@ # '!W;2TR8VEA+F0NM!Q@>! 44 P0&!0,'" 0%) @4 P87!@4^"/YN__^?!?__.#8#P@''P8?%Q'
M?P7_[PXB(Q(#)0P%!PP$!NS]W04+$003! 8#1F<&]_>G4:-&^5%>H"?NO!O3
MW/KD;K?C7W3(,!_V0@<4%LB)T5>%X-E3_5"W?KZK3=BZUN]7;^OL "":)Z
M!XL$7)M%UA+D*SAZ1L-4R:549+;,W $+BWI8G1L7UV37B)0WK*8]Y+P+887U!RAZ=NP
MY=?[=;GS_[[51EZ15:))7B$I[_U/X/MT /'"#>JYI'[Z&2DSEKW,U)]T,64A
M,*S:,0ANR^DB3&C^Q.79] ?XQ1=E&GP6HE;O"2LMY?>C&I;SCB*'&&2#L[6O
M'(;0#,9@Z*@U,7L!RUNID1R,TU:(A;@M"C][i]!@L P<3!0,G%O?W]S>1
MK.OZ?[=/WZ1#2*>.V_G?#=<3%WC5MT.MZ:$TOY#!KRNYV][FQ>XSW;?=-O,+[547:L?V:HK9?2HV_ OFG69:XKX;)M
M?7^:4MW"Y?X^C+ K)4%<+'G*=SR.!JZ-<(N;>]+*=H-<;[ /RYAP[BL9^T'#
M9DA$-H-)$Z',8$;A'W1/I-(44$L#! H ! & /=HQQJHW6A*AP( .0% +
M <'=M+6-I82YG+G-&![T#_1T#'0@&30<�@-!Q06!387!"@=! 4$!0,$
M%0,'" 0%! ,%" 44!28%/0C]/?[^S@7^_D@N& X(!QX&'A<>!WX$_NX0 0,"
M P(3 C4'%@P5_ S]O08, ,' P8"%C<&]_?W)Y$C1_J17A"G=-Z-SM_<*=RN
M3/4<+MLV[W1OG-I+4(I+M8N%E=&)%*JP)AA49/HP)M?.?['6,57XXP*S( >5YU=B*EXWV#8JV&%:Q,"?7<&#CG7E!OW-FN$3*_FZE_
M>8D4R-$MYNG8GZUU.^IG+* #M G,RILX>=BF>4O'+5,%:"!>UR&;.2_6-F;&',VJT5(6J6?AMKDG>=SN/"'0CL7$&(0D?,YTF#>6JC9NVN+-]^56HY7>[G=5X
MJC?8!V1(./=E#/V@H=(GGDIOTD2HT#D8_+WN24JJ E!+ P0* ( !@ *:<<:
MTV5I'GL[ "4 !P '!W;2UJ;6H< $" P0%!QD'"0LN"QX?"P+7PD+
M"0LO"P*_X< @,")*4$!01%!@<&!R8'%@=F%P9'!@MZJGQ-L8X,#7$QAD('V!A_:DE%MYWN/D-?F. U!L'$/P"H/^_L0'"#Z(Z/U!]
MZGA;1X2> O$(_[3^I("5JD[Z%S5!:);('7UZA%#VUV)8^40]YO7#[V[^?VE
M]R<'"[VZ>Y#0:G=""+4;*].'$%L'Y YS,)?_'PB2_']XH.4NF/.HB."]!C1
MM42(OR[M3X(_$#W[BA ARV_L%WIJ+HA^6O4..&W4%D#X QL/G-[X+W3A(%,W
M!/@(]0D^%C"X"0QN X,;P>!6,+@9#&X'@V=[MVX9^H A9^H!4/N.M)M@8<<[&BP3?<4[L./>+_J9Y.C^("L(_M9_F;/ U#8+!*M'*)XD**&;])#F+1:/7KP *%,>C"H-M>>$0M(T(@7>L/$O+-R5.S3@5)DNA,&(Q/]2E(J45;%G5*M:A4@*EOF#]G@ B&/4CI
M_T'^'@]R*CG$J_Y)U8-Q&*?BYTJ7-,# K3 ;?DKA,%L_MM@86?2#;!WI)5'
M;-#X#2%;A!]ATQB@@$VK?TNV"&W3S1KPO81]9#-8CU7@9#I[V>2^*W+WT>M&3K#U@I^F^; U@L*O^9 L50K7OSHT"-#BPK-ESIL^G3D /9OV>_GKSX.'3
M?R]?'OWY]^C?V[^_?_]^@/L#_L]'^ 4"OZ7,B_/?I]M@@L3/HR8<6)'C1Y-;DS9,>3'D" [G@1:=FO*A?7GMZ__ORWP!]7^.G'QR]/
MXL2-%"]:K#@18T2,%F=V]2I3X;[>?5W>_;C G3[]^_;RU=>7_QY_
M_7^:'F#"B"QI+@PHGSSPX>-6?;])7S@__T&^R<,N- @PH<)+S:D6)'BQHH;
M/?[V[^<);G:)/[]>N)O?WTX8YW^//GR??R!&C?OG=Q^F?/;NTF5_0 '@
M'N'"A0;/GP0^ R:M2&$2M<./KS_TT2[%/MRX$/]WY,6SF3]X,Z':1]@[8@50+L":KX [B=$2IG^X,:>M/SONEZ?9[=E9^_/CRX_#].X0'7V^I^R,#[7[V1>U[]]_8<:+_M-+;]YMU^_/
M![[S^<(#'FQX&%!A@V_4**#RP?X5V[_'G4YX@%28D> "UW[=Z?U*),C
M/$T1XJMC]_5T[SX;-,BP [u]0*W@83+#K.0O05*SCZ"+$U+A<4/[^Q^>%*E1P6,[/WX M=A[]>'
M[??5ZO?G/2]?/=_R#>KSW;7Z_ D9&EP?GARXB_]^MW]@>3'?M?R 6,-/XA+S
M-5^C3R#+B^SX4$#OG3?[=(:B0U&AV%[QHOT RC[A ?F)M?E]P779?NK=Z)
MOKK/M#U% <,D"P_]"]OJ"A]0VNY*O 8=> .8RW 3H[8(%"O6,
M(Y:_Y,8(MQT@TZEV/$@977XZ95['?V/'[^^><_/[=L M# >LJ0D"=M^5_@
MM?+^ ?[KCS2E64[<8M^+(_V ^H;[CY$1_B>?,0G+T$^%@AP@.D)=_[-I5B/8'@EDA1(@/4]_ML3W[TUR)+$&5Z.H$?A=XSW^/>OULSQ%]J[Y%3(8YRSY!H%C!XDK/TD>;L6R
M*;#R_09%CM:C.ZU')[OSTM-A4E7,MP%8M/Z+:_,;2]SQ)GMQ@MW^4S$(, ];'"Y3';P+'] A]OU#SOU4390=8-1*UZ6GK^I*O/45.BZ#Q
MUV.[;6+MIVU9[#9"P)?H8+ 3V"])F7__I9GA0W639=KM5='6?H&^UM4JK>2]P%H"]1@@P:(XX ![+XLUZY%FRX7C1KX[M6NG@2S?Y,
MXX5ULI0E:E.C);LZ8X,$ 80"H(>G-?_^TA&[^.%$"CG/$2H!<=H#
MJ(H7*IYKC^#C^?/@HW3C?[DK^1 PM(C0,*QD*&P"U,K>^5E KR%AZ(4+
M4@XS3-"YX%MF%^O+B>BE]1K%!WR%A@?:F4IM_/XZ/5#U 800*4*Z/D]A!=E*C$^0(('+
M+4 [&K24-[["T?/S[9"A?-YCVYS@*S/ 0*GWX1O18L%#+/4!50M-+CJME;*1R#>)ZO0[$@)B^"1#.!M(9S=K^?E&S%&]G0 ;P &IT]Q ]14.ED:
M;0PU7M#1OVAC4<+3]]NW;U_'0/LJU51N!] V_E?,J!KX@*%B!-5 M"Q(T;>E.NMC
MP ?OIT[N*"UN+@M@]W">0U=M%A['*%R1VG29?(DR9,C;#OE"KI=Z'?TP'3W
-email-=KV:->K4I4F+%@T:U&=-FBP876MZM&-)_?]NW9MV*U7DSZEJV>V7-GQXT6!CSCQX$*MZ35 "B9&''DQYDO96NI
M;AJA4S)EN0:?US@"*[*;RIK=[ ]KQXHZ1O?V'. K"N"'L$BJQ2PG"'P-0@N
M9KXM/W[<6. 7+Q8X4./&C15.L+^MJ'E=G-7B,>YU6:X03ZJII8Z/YO* @TX;"V%=35Q'R,*F",(I[A"X.005X7:(
MN9!%H>$1=?8;1M--H1V0/&H1D)R0$!,)J&FA^$588@7"E3,)OS 21JMXXI_YZX-LG +,V?/%CAB]]T:7H8B=??YYP('C!A["0<5
MH9I& ],&"!87($GHJ9!1(0O7%2T(%X+[MG$N/-(@87W%C!NS&(/6DR(-@
M/+RGP6S!H+I"X IQ]+K&P21+EBP!.U+D2-D%VI;I&#,II :*ZCI"#4<,$!$
M)-7 #^*J4!M!*J&4B0'ZXRI4]7,7*C;MZ^IV8W(E4>+&[P(7TDAIB-QT*37.
MLB/X.(+(HK&U^@+Z'&$DZCUMUMJP +V*+(N.-
M$+)%)"8OCT_#*[GC()W0QD+ (AR:/1N$997462[^Q365VWNOR^H %/W]_(*
M!>@.XO]TB9"*'50T#WA)9N"2D)S+#1J#2(5^&LFB$!K?QP=4D2IK+ JJX ,6
M ]&WV#1JA@YTB@_@7<.L:<_X#R)71
M8B^ 1FIU5K;KV?OVM'NCU3]K3^>?%DS)^>.W7BI"E#Z7NE"4V8PVJ;7M"[
M,=:<:I."O%T P?0_:/&]$+WUL[)^)Q)Y??Z0#>G B;&73SY]._H4OV!.'L1
MWKBUK%$R-$$&EWYGB>Z>(*=^L@7 #9<*_"808[)R^Q C(/<(_IV2=Z[9FF
MW;*P?M(P.*E0HUO%+F6!I@9G5F5THY[N_:M@0L%/F34MUUWUKQY=.I4!*-H']M6-'[,9AM37)JZ !)TY QM7X(>HWF+]$"-R5F*>HKDBLX$ N7^%5/.W-$U:_93JU[5FD42>3)9.);LX"5
M1;%MTK40<=2G:K7 '_V9MZEXM@UBRFYEM2LH:LYB3V"1M3&Z),^A2)V"ERQ9[UHQ2B;#9JE6;ELUB' <8IUM7CC$FN.O>MY;,J[%>/XL^-$[CGOFWS*H65L5ZUFF4B_[7J4Z- >2!4N4*5IE/B'1>#:[XH
M1O%_A[OM#)]*[O !,99"MDC=A'I[CS82)UYLW/?6O:L2,1;S;-9
ME96$L2"G2J*Q0DHZ+URP@M:6*3H4*)6D2A0E Z[.9(<,Q PTL.:'-?WN85*X
M]#(,<$ NX@?$)DJD2J3$E_!LO0N]NT>1O7 )X008]K"-M!1] G+"N!4XLQ@&
ME[AM$T"1X80(UF0,( =%9FB(7HU.*GE=X*H0L/U[I@0,?DYB>[G)%$JD1U*L'?#
M1^5Z4#HM+Q>43JJ*-/0BR MEA VF4+Q@D/ !)YWF!+1M9B*C3%4([HMIN*0
M'.(2]16Y<&E(6AOR)?(=5:,5J++FTSFD:1&*3#Y(A&Y1$VI>$ P$3A/0!0)
MJ3*_*9D)Y&D(&G7H;K4QN&HG %'$*N,[L>]')Z#!18ATE>A,@_,Q6RT(I#L#
M^$,2OZH_ X!KOB?!*Z"JK]O].E?"Z'#_'%&TN(:^-ZRY*SZ[7!13%A)H[*3
M F?TZN?OH]-D EL@/YC7@&1_/IR$T?TTD C7(M__'!=8?4L@<@:33I^P(
M$Z!87E*LZW!5>A2V"?:"$T0K,D-S4.=4E"+299VTGYF++UZ]?G)UE @X@'
M'&3L@$I!I4)"CONO0Z3GJ2]FQA GD!U1 @UKEF6: <;QDZEB@RP22*9MT=?
M#AXF-E*[+,_,10@8 1B_#%HQ7CA$XO#M:M,0VYWP9]&._[A$X97)?QO"VKMX^E,L%3)=B_/A>>-0T?PXNQTL(Q^=V3@
MDM)*RJ'9J.K .J!#7[@DB2/_$!:35,CW"&#MAW"!OGC4AGA;S$@^&L;
M3'C G9M-K<?]OGI8-!>A_<_[VZ,V^#*H!W;:XMCS<'NOCEW>1*N %6#'"5
M9W@>8"/,.//#E?(66!V1*WO'QB_X/]S>?F-!3OR&VV '/59^Y(9$VI4J/+E
MSY4),38%&D%7]W?_?;TU=>IPXYM>J]UTNI<;8^/LT#XU*Q73# (P_3_&'
MSYY^[Y&EK:+ ^1K5/Z'K14$6_#7&VHD*@-27OK3 P@^ LQ^3T]%I$47N# =
M(RM9)L II?@"7^/)"*'=3DIU-/1QTDW/EOX @&DMO($(.$0JL"J[9 8.T[T
M.).(P'[JSY$)!YP[UM.@2^9J-72V>7%(V_'V0+X7]*7?"56.Z*P-=O[RB>?>MMNE,L PE"L#!D$55#"D.,&V>2^Y8DI>W#LG7!0H8&RUW8U",GGG"HKZ)
M]+B6'P=F?#0@M3!$)?XPP #(9'OKO[>GS;P9+##+*EOR2C70*:3+8?8CC)
MSS0Z^*^LN=S88N*O]S*<[?E1U>OA**H"JDS:HHQ&O :KNU75[Z]'@$M-=<'
ML-R*H?TY/ D)8/R6&'"/[:L*51F!<#J>4URYKPATA&)KTA1'Q=A.U9/6G+
MWYN)G[_@.3;P-VG- XJ *,I$#=8UBZSU#&IC9PIW0= (84HWNCDC-]O,!
M63B"@I:"KY@'%PDS.-U=#:IV3.)XZH#0"8-RM$9]!ZJ^2 5)5SBV[#A4IJ'@
MTW&BN528$HG:'*6JR/"BU;#=E56OJ^?3WR$1#M?D^JP�!T%F&KDQFS 2
MX_,:8.B&)G7NVQP_7HW![:@60F+)M79!9_;UI'CG.V"A)A ;MB7Z'(](-VC#.MT'=CF$HE; [&IT.=/I5YYNV<&_**"R7=TK;E'8$HU&RDHC&
M!/B@J I,AMJV](1-@*^(=/UXJD$X( UJ 8.X=$DP3^J-"0YQ,
MHFD.(AZ* =B!R8U%G& *"C>47VOKFZ'A_/D6NOGGFU:$612=:D!$#%JR?EAP
MOST 3PJ3!C(2>,!:QWU# 7J!MX777E"=>_[:% :B/:Z[8DP2,(@) J1[4XO
M#_+^>8 $X1DL -$@(.C"M,1&RP%^BJ6+52S7 ?L*=]4%1+*]/@^7=<9HR
MC'_?44<@I/=Y3C6<_R6@( 2#G40&C-0S%<_IS&;JR&]^TGH*).EHF)V!X%:
M4*![V(Y$0F@IH"E@X +1@DYDA,J@KJ%IK2I0GH?Z!O?OE?1-7#>30TM,/R
MO]?IUR?XH%*@H&B !ZPQT'L4!;)_?^(+3L8,E+ "5P[P1"!7EA+K>X*3.XM,
MHPD9?1'BHUA__W]O#)22($1!!/H8F$#&P'*(.$"<@P%D(PO!P',3F( &3A"
M8>%Y"@%J&RH($AF06:;IHV%D0R,3 OB_'1H<[SX0'$-YFBHT9"EJM;XT.1*Q
M,W$RW='XX("F"*502(: )*U9LKW4"$3A>0*MQ0B D)3*8D7AB!8H .:# 1@;UZ]?CSY4;J2O%;(J50<$@2(D:'*=#QZPR?C@
M@#(:*I'YWR9 &Q43.)+0?>)HHGC*5/K7VL/]QM24"R3QMMOUGE =.S/Q.37A/(M8$$GLQ'8L4 QB@3.#2$05(DP/[&E9Y(*B+IB(0N,&0E
MTC.K'4ZO$5*NJA! J8SOXRN0D:,]7&5(J'+3<#F$CD+-C>XR/C K
M*:(>0#6H"4*1:H0%Y!%%+$XL/ %I"RAJ,U9XE.N)P72ZP1#P+I@RH?MB/!
M[HT$&Q:F"2XOE)LY86YF8$^]FI;_+8!I8*9AQZ$',H^WH9$*56'4(]0U2M2X]T@Y6;(NCQ)81M4VR/_/Q%JEYEE/&"NN-$PQ,HCC-*6Y8 4QP@XMU>OT"#*%"= 0(OX#PDM)DJ]9G1P1YXA :#09"#+J:_HT*VX-+BV^_=F!Y
M2W^+$/M?%S_PHLRE/55^N/HKG% ",8:Z%^AOO'!8-V*%OW!_^@ C_P=(U^T+
M8D<+:"L2H7M$OZU)N(!ZI[_6 _#Z0)$$J6?E^"VYMP0E!>7$4SM8N4$_CD ?_3?'.3)F@=K^.;="!N[MA[?=..;M$L<"L"K8+;Z'4)=DZVM_+T+G^.'L.NW%&GA HFB"MV8F2D+P@,I WARA
MQ% WD#AA7G$Z=#Z*3HL,D)/8)Z$^-IU=9O;MC+?#YM3G7Z2[^93+C:.L
M>@V]HK@Z!*Q@7192>Z*2M7W>'V]0"U VAQ=;X)H^PXOF+MTM?P&7)(&8XH&
M!O8 $EVX#$+'.D07)!6&0+M"-ZEFDS_'P"<*)J0^?K]"BZA0'G_@)!G?BY'
MVE#C8/P &?S$&_JO]_24V.R,!DESLO+_=U2NP.7MVKM=<5F 5()N6%MQHC/-
M#@WN "4GK9$:2*'<757&-X%S%#.L-Z:0#(FJ21IFZ?U%P$P +MO!/A=:LOX
M1Q-K=90<' T(CF#.6AKB F-_2)WO!8X("87Z 15#SJ?4LJ;WTW^78T!PUN/-
M7;($N([X(*JR25PU@_V# TCUP _2+$4XDO@&". 9@<4<0M^A;@L.4#5[!WB "BMZJY'2:[/GW@$U)3>,JIBT0D'A++=50'#S2
M+Z(2B0&8FA(AR4-S0:4P(347"[$(+F4;N1E42#K6B6%(268D 1E'>E=2COT
M,#B >TB,Q!$P&&"3:Z4P)76K>KY08B[!R992HP_0$'Z<]OF8E4-@W1')$#
M1V>'[2TM:B8#H##%H !S4$2B<((%@S1 B!E+[:@8XM%(T&(&[b]:E?:_<2-0
ME<34Q-1#"6F?4,&*#+R!48$68;"B?V)_4A,3F,LT ^,)3,$*=C(=J""I[H$"
M5@SD3"36^,#= NTP[/]?YA!%MWQYJ(&4$IJ=[FH%")*-5VN>Z5D(PV&&HI^
M4$R0(,$"%!.R:GR U% 9C30:^2')("!NY@*A:Y- ED:WQZMUJ(YWT#"_[!C!
MBH(+S$Q8P)>._ IY&1!<0,&Q/@F/W;>KHZ!^%J^11IQE:63,G3#!CN%#Z@%
M)&H2Z(AP"QP@:N0FP@]F OZGYM#E4.5RYJ@JA3+KNV.06*--0GP#R9#(4ID_
M4 FO:)@+Q@(%Y)(HJK"ZA)6,+MW@R)J0'4Q)&M9'/"2F*!*A#9(J(A5AN5X&
M@1Q0Y.<@J$:Y)FG%ZBHG<+"_360$M+$Z"(P/2G-Y? STG5M#U"A$$>A[EB@/ZV,%#XKD%:8@#YB_?I6#=S?)_,^Y:!G1?V;'89,@(;["R!$
MY*8((K/>1$9W ;D39B @APPG*AAHKY[UN3T;((5 @CT=&')"%X@5ZC7;1^
M'L&' Y@A@2LL%]9*IRWH[3>H/,4@[*'K[#&J4Y$'BC(.@ EA ]#'.=S%+(,
MG#9RK++X48#5<69X## =+N?;AJ1(%+WP4-DP'.TM [4%WN5*E"0>@B5LA0CV^8IZR*Y"/63#]-:E68![ *L(-O'>MEN;[FPYMC 3?,>3(D1_CBQY$N%W?NSX>3%G0U'ODRYM(U9'6#$K&27C1HK"*XOB]*D4*=DE4>$W,LQYQ^;%(^8!])_ @<_]0P&Z[%:G
M3Y>Z['G2I38^G7_PW[MBC.X^./#FQ9$,8P8>D/( %%#A
M>"&&H*RILI I^9(:]&YW-RKE!Q>"6.![&//.X*AZF*33]"&7N>+*FB7QS=V
MD%1%2'GQ;IA1 JH>F()Z_Y ^!5%7B@0(OT.%]PO<;L>3-HC1ANG4%]-/Y(
MR9@1/R[4XA^,B' ?%CRH- Q6M%Y4)E'GKERY]+[P:.G+AN8 ^X51V%3Y=^
M7=K555BV[UPK8>#):#.TE7AW:]@8)K73H8UB3&IMZ.)#IN D$7DLM)-?ES
M+U_NC-ES)458/M]9-*DK7['L^M7JM=^_.M>;Q;E>^,(RF.2M'R^D1B]+3%]C!MFT@I-L*V!(KD##B;9&0AVABV >87Z=.C!"N!&8'^C/GS_*
M4R5,8:)#WGQ+X9LXRH)QU/EJ$*]4T9?N /=[ZU+C':!)(K?3FIS8EEDF'<
M;=$A"KC%EM>: -#1#[PDIZ1;#^(&ND- 8Y'MEBY4O.7J,"_ 0)^Z,Z7*IJ@
MDW11Q??C@_-!+GNYZ12V'V(W <%WFM0((!^UZ1'"VVRD/VV<=X]>L8W*^&7-
M'!.X$.#=W&:_98O1,GR6*4=V #GP!():.*%"R% _/8LK5FM6R>$4AP_?CPLCN6)')^[2NJ%H^NC$$^@'D>4MVP1(VETS83)B_>NO;JT]Z+RID:"1Q-H2M"NUJ6IX454Q#<]G5J/'B">C3!
MM2XUF4:?CH3DM%T$0Q=)ON8+T)<7J=_[N!7?*E"I9N.#Z(Y;A1U2Y+!< ,I;Y"/-*N7?@6>J!
M4F/9,#(AW;%C!PP<,U!I: "=8&6424QA 18<61WPZV22^-].!^Q,1N%_A
M4!&6HKJL,G25)34)"DYG'AKQJ,1%)DB6IV(Y?OQX 1W481+MM]OET20&%Q^-,AL4]3]UM3CQIKS@PKPL2_M)Q@+V/__XY$-+'[L<^P@>,.@:.4M$C4CRJE"%++P,FD-$D1X@)='?#RAB* ;%70G(G#D $0)[i]D10L9$!$@D4"/ B82R [#_0R0G)A>Y.#KJ,^*&5&N)WNF% 3A+9C
M=Z1!M",& 0JID*>9P(@$&_@TPB)A 3X2#, CL0#'0?)H?RR.[R5(B-[T@T'5
M5>?RA!>'?@CZBN $M20?2"U31X5_,VC0#WA&#J4[A]^Y4!3'[A3M'//]_@$Z,,B%]- L=$IZ/$Z04GSP8E2?$6H@U^OPF'T[PD"!W@ '^ %ZM-]9
MCKI87K^^?.O/S^--':%Y5^BS'2+P1_X4._0#O=I!B$6#K7%I3 1B/-=;R1 6
M##W;_56V+" ":K[#M:M2D0XK.-%W$@$Z[M., EC,]%5I2,EJ3/C[]RZK=7/VS5-;EAS9>+#A0DM
M=*"7A)HE6]X673MS;I7A:RM]Z?^/#9S9G?7UMWDR%3(RS"-)W*@FP?P('?!YE!/!_ N>]=M4[JQ$9M8K//X7)=R ]3>ZNR
M#@9417F] 9ZMR1*@X)(F-^RI$Y&@C?R!)KR@MOTA;VHKY/&/>*!3;F?0#VDR9,J%KSD9FJS
M7XHLZ&[8G2@AS Z2AP/C5;].7?ISI[69]JW.2=:#>" =#%P!2[X]*C7@0M7!A1-<:3/)E2,1VJ6"[F(RY<%[Q^O-A>9V2DOKDX.*0"9Z
MSJ@DZ3E2D' UL-HR6'%M0(?&BL$$$ &B(%@J,,LJ70HC=3FB1!A3)(D!]!
MAC!]@1%+TLQA24YR-;^*I1#YS"6^YI0U5$XC5S9K=D[b]._=/Z> SP1AFKH+]/ID5 5NKEI*DG8:1.4<5&D3Z4>S?F";2B
MJ&:W_]@@#HV %,UF[-.?+]OEBQLOMBT?C^;/-_=]>_9K5KP=^O.E<6'$DH+Q
MI"H5-&E.@EP GQ4$GHPK> "KB[1!D0,(Q1PM:OA?U Y ?@0C,0J_HZ9
M8D7O,F#T<@H.BB29-L U'D9/&9+TC1+0*?98M8,@W0OVG3QB^6V4-*^R8-
M5=(Y](?'/HEBF.2,1$P2IE^ZN":O"/P6R$3:](IN5"P5 .] Z$90SQ231P5=
M@HMBZJPV] JN.*E&'-PQC*R1,@YNIFO;I#)U[!!$72.:19JVT95 DRQ:[([3
M)>LBO^PC^_DSF:R6W)O5E/TWE.-J.YF=*]-<)%DM%VAQR*(R/.^?0*$+ RF_"77:_.!H;*"&0E24U)#[X*E4Z"U_H9%0IW (462
M-(G"VS+W+UTV,+A"9*FD(KT2(1*J!CXXP?/+J&,HB4J; @/PQ4^)^#S?1$Y
M2"63,P0NR.= 816B"[E/L.:(#+YDR$0@)PEYZ2 '4HD]*Y!YG0G*ETIU-:I
M!N5Y.!/CFQ%0@5(95#9"=+Q8H&=S@;Y]VT+>&1@<9SHML?%#%E>>V=%(^%W@4 M!, C^9X>@,.]XD4""*F;$28JVI+1C&!_1PT&@-50
M078 X43-"5&<-8)1_(#8R0"C4>.!'&8&G:::(,&Y"CZ4F &HR,JA#KC#'BT
M^B07&!$0$=P/(5 C?G!RT4)&"EF!JB9MBQ&^X,)34$3C +#QO!A?S@BE4@4
MR)8W&/1%HBM%U(SGQR/ P?DH%-!=1I>& 9 D"!?Y'PB"O"IJ5V)UZ*BB2C,(
M7(#:'.!)II(,0BFP0 %D'G"DBSS4)T,U2-3'R0="V&EZ+M AJ 4YP7]+)$UA
M(6 F!YMYM7W9YLQ*82S.8:J'3<:9'63[]>H!!4YD!"+AH*J%=%3Q+:STTZLJ& ^H(
M$H/Q]M3+^QDZ0TA:E(R5$.$B18!"=T!SI_!1P KR"/(4DBN80$<"ML]L0!W^
M61$>B)+/,[7TH&E!>YIAA>X)"SN'FX,S.@R'&C2U"""5B-VH0$<.Z TT=L3
M:2IUP>M _4"V"<@$HKN@OL/X,X$^T$>J1[_8 :-_&_K^RM%EM#3?T83BB+=9(+^1$M!R?K$/9M/LXB(HMQM2,5^/G]V3R-$':0,!_)WUV'XVXCEKMUW1R=D/ V"*MK+"=,+DQK
MX)]^GI:F8(UNU,S&UZ*3 IZV?U!)[& B"&1O089,$E1'ARY.6/%D#<>KUHS.
M"""04_[V_.(#5MX-VB'8 :KL4;%N4T..(7C:0=C0'(7;-27F &!;=P.61
MBT(EMR0!M"W?3'FT9(#XU&6HD.6(/K.D4T+3QOHA]_628W<787 7/^__F
MGOO7 TCS0Z(E]L^'1 @HGA^ G"JIKV)51"#1I$MQ-]@0X01!DRNR""&(,%@AU0"YVFTDHO9+$ #MS^&@B9X ?(OJ>>TY/@ 7;^
M@0Q-L@RY$%_%QN*6MM!4KO [Q:L3>O?1+;2$%*;6>!Q6FQJM1W ?J(#(*ZO"U5XXU/=Z);!!&XA24SOV&_O;]@9ZA^]@=,X0K$JS7X"$
M567A$!<,8 *#FC>!&#@_>#5'R+$=(#?Q ]5;"T2:L@0?802=6L.MZ?C03N=ABHSJ[BL%NF7@2/F&9P/C3:^.JJ0O T)!EK'3]31FX1B"*9]$#
MDM9%;/,48)TLQI]*$5)%% X0A3M!Z"3PY]"2=$.(X6OMZ^1]X"EXP'9_@ 4
M(658M;0&HY1[ +&3W.GZ'50- 7<."W)W)H+W.2&T>=HX 3GN#Z^GTU9
MM/W5/60(/& *I">H6*2X+7"W>.7W^1^]*?P!]$.Q:D'W%<'1CE; -#VE@H
MA>8$4F!@.LABBT)#EV89 ,A>R>%%IA,J:+"J[i],&D <$,'1!QM*V"53-$+60*=0#(1X:
M64)56BBTO"9I1?CA@Y*O2? , JX_GX- J%1--5)B(: 6:OP*K3LJKGOH[!
MH,$)I OL**&SO-O1N;,&M&UDM,A:)P!U;:"(5+V51AS0P->NY4H-K#A1JTJ>M&8&MH@+2_F 7@FE^Q>E71&@X0 J.K@GC(V,1V91$(']!)H&<*,>7
M-V6"Z]>7EVENETC<7EY4X/W]Y'2T-M$M2IV'Z(#+((;I!$P+& "CW6PPH#]
M EF$38@3E>=3-M EHX(#"- -0:0AT+.$PZ"G"ATSPD,Y*"A=!M!2DMS^-K/(_-0PV-Y@;4IL#$#1H7-R/W(PP <6E!IH3)%4[". 5ZA"L(^X3M'N%2V/^C._[7TR1Y M?OEW/]D!T 8Y6YF'K%7*"1":_85.4@R#,X*T!:UD4+E(VOLK9/1@"XRE86@#
M?)]1:.FGF%^;PJZ41#*A!M < )K J!0O#4H_4;T*JNN6.@#M4J[L()?R(YV
MXG3P1KV*N(4.4X**QH7")5)$J^Q]"CB[ _,HK&+[]^@:ZL 1/D"I2G0#XH1
MJ*C('%+DD"(DI4%O%": )D*4V@9!07)$V '^%7^%R7# 0/T"N)'KI]/3R-*
MF4&".* B&EJ>A#9GG RNYB.N>3D"#<]^?.E/39((($B:@&OOCGDAM!1.%
M'9"S"5($NL.ZWB7+=UP@@,0&[*#LH*[[ :E1:MM;%6TX$C<)
M(V%,'CC 1$2,RQ9N("XS?OKOOGB>/P]B<3NR(TP("QA-3/L+8]$9,A DIO_Q
MYW5P/#3.N/_[W. $,#_04M15O>#AX@8SL/A!"::6KXSG#E2HAW:DP,;?,ZH+
M$S589G187]-WX8#1WQPN5A*15V[YC]/>WI,I!]*_@3H$3- F3'LFOH5$A!L
M $H0^!_TF74%S(K37^Q9TO^Z;03%,M^SGN!@E(= 0P[]M4D#3TASXKN4T9[^
MONEBA(W99QBELG0%-17@:8M!)EV;DP&O*_^6( NNXX!69)T^>WF KU!+ P0*
M 0 !@#Z:,<:33MY=.T! !4 P !P '!W;2YD+G-*!QB= _T= QT(!4T&
M""T'% 4(!@@'%@@&!2@=!"4#!18#%@0%) @$ P0%!@@&!1@-%_V=_OYN!/[^
M+A<>!PXG!1X&'@8''@=^!?[N#P$" P(# @0#- 8;!;O_#P& 42]_?WMU&C
MTF_NT.F?XO;3[C+5[!Q_7^17.>W^33O' CNUR-E#-PUL?MI_^<:8:[>2#^PEGJ1$C;B6J3K=)0MB7V%-GI9F'/J/F-+-<?C'^UC_)#XV
M+K"&?@T=7REG]"GO32,U^$/6]ND'CYFF94&MCX8-)RH3=P-KPW @^;^]IJ
MY4)#IU27UMY4!WL@( (<% ( <'=M,BYC+G-,!QB=!/T= QT(!BT7)@@6% 46" 8(
M!@@6*!T$!10#)@,&" 0&) 8%! ,%%A08#1C]_3W^S@7^_@X(#A<>!PX'#@<&
M'@8>!@!WX&_NX. 1)#! ,'%0P$/ :L_?T%#0 " P8#!@<&%P;W]_='D2,7
M[ 4_PDVY_S7=*]_$-YST'Q,J=H=M=)BP?]URJM6<;0--Z.3;_OA7;F__%+[
MA:D$XTQ4K:+BB5JRUJBT&" W_2 4(+5LJ:I"DRU_E]8+IVV5ZHN5;65"[5[0
MUL/O^#2//2HM?? D=P$MA=?7]8_ ZF?I<:8SM)$I>4V1-9*.%[%5JKU-,K7
MK)E>@VSC*N$3@V;%SY/*,SSIX^]M;T!P5[.-YY3*BONREKWK1F6EXCQZ."M 8 ^FC'&LJ@5',0 @ _@, @ !P=VTX+F0NM!RX&) <&!P8'!@<&!2<> P85 R8#%@0&) M!PG!A&'Q8?!G%_^/ 2(3! ,$ R4,!WP&7/W]'0H $@87!@<&]_?W9]&B
M,+OFK+K9XVY^/97OBVIZL=J=]C0O:=B5Y9?MU]A>6->C:WC@P.H:>MU;"N8(2?(+FY;5QW:7%FA+%8-S@I5Z!:N]@A3(J50) E?,C-1.1=5I9B
M-3YY:L;1AF?]'PQ9Q5_R^F=6%Y79#^2CE6)M3^@C9QK+PGN#2/ VKM'5+/
M$D0R?US_>@-Y*WBAM8XGK#C*HI4Q<26EUW(;U!L&-Y#]>55QX:'3M*Q.=>QK#&YCS:R90 &L
M , "D@0 !D:6=I+20Q,C P+F]02P$""@,* !@#
M:,<:E85SFV$! !R @ # I(&/ 9&EG:2TD,3(P,"YS
M4$L! @H#"@ $ 8 ^6C'&FM^*+ + @ > , L *2!&@(
M '!W;2TD,3(P,"YS4$L! @H#"@ $ 8 _&C'&O9"0BNQ @ 8 P
M *2!3@0 '!W;2TR8VEA+F0NM:P( &D% + "D@2D' !P=VTM8VEA+F8NM! & /=HQQJHW6A*AP( .0% + "D@;T) !P=VTM8VEA
M+F>SL )0 ' "D
M@6T, !P=VTM:FUJ4$L! @H#"@ $ 8 ^FC'&DT[>73M 0 5 , <
M *2!#4@ '!W;2YD+G-02P$""@,* 0 !@#V:,<:M!0 " I($?2@ <'=M,BYC+G-02P$""@,* 0 !@#Z:,<:
MRJ!4/ H "@ O @ +4


Please log in to post comments, if you are not registered please sign up now
Render time: 0.1760 sec, 0.1094 of that for queries. DB queries: 53. Memory Usage: 1,485kb