Here's the original code and theory...
Code: Select all
15 NEW WAVEFORMS FOR THE VIC-20
Written by viznut/pwp in the early June 2003
Most VIC-20 people assume that the waveform of the VIC-I pulse channels
($900a..$900c) is generated by a simple flip-flop. This does not seem to be
the case.
By changing an oscillator's "on/off" bit very rapidly it is possible to get
it in states that give out waveforms different to the normal 1:1 pulse
waveform you have learned to expect from the VIC-20.
An example:
; assume that the content of $900c has been $7e for a while
; (at least a couple of hundred cycles)
ldx #$7e ; oscillator off, maximum shift rate (4 clocks)
ldy #$fe ; oscillator on, maximum shift rate (4 clocks)
lda #152 ; the initial frequency of the sound (can be any)
sei ; the following stuff needs exact timing
sty $900c ; push 1 to oscillator
sty $900c ; push 1 to oscillator
stx $900c ; push 0 to oscillator
sta $900c ; and let it rotate on its own
cli
This gives out the waveform later referred to as the "110" wave.
The following is my current theory about the VIC-I sound:
Each VIC-I voice has:
- an 8-bit shift register
- a 7-bit counter
- a 7-bit frequency value
- on/off bit
The clock rates for each voice:
- $900c: cpuclock/4
- $900b: cpuclock/8
- $900a: cpuclock/16
- $900d: cpuclock/32 (?)
When a voice gets a clock cycle:
- The counter value is incremented by 1.
- If the incremented value is all ones ($7F), the counter is reset
to the frequency value. Also, the channel's shift register is shifted.
The shift function for pulsewave channels:
- Shift all bits left by one position.
- If the voice is ON: the lowest bit becomes the complement of the
previous top bit.
- If the voice is OFF: the lowest bit becomes zero.
- The lowest bit of the shift register is the output
- In formal C-like code:
reg = (reg<<1) | ( ((reg>>7)^1) & voiceon);
The shift function for noise is probably something akin to that of the TED
chip used in the C-16 and the Plus-4.
Waveforms:
These are the 16 possible waveforms according to the theory:
NAME SHAPE
default 0000000011111111
"10" 0000001011111101
"100" 0000010011111011
"110" 0000011011111001
"1000" 0000100011110111
"1010" 0000101011110101
"1011" 0000110011110011
"1110" 0000111011110001
"10010" 0001001011101101
"10100" 0001010011101011
"10110" 0001011011101001
"11000" 0001100011100111
"11010" 0001101011100101
"100100" 0010010011011011
"101010" 0010101011010101
"101100" 0010110011010011
A short generic routine for setting any shift register value for any pulse
channel in about 150 cpu clocks. Use it freely.
setwave:
; USAGE: y = channel ($0a..$0c)
; x = initial frequency
; a = shift register contents
;
; WARNING for purists: self-modifying code, illegal opcodes.
;
; code align assertion: make sure that the loop is within a page.
; oscillator assertion: make sure that the channel has been at $7e
; for some time before calling this function.
; put TMP and TMP2 in the zero page.
stx .initfreq ; 4
sty .ch0 ; 4
sty .ch1 ; 4
ldx .ldfqmasks-$a,y ; 4
sta TMP ; 3
ora #$7f ; 2
axs $900c ; 4 [$900c] = a AND x
.ch0=*-2
sty TMP2 ; 3
ldy #7 ; 2
.l0: lda #$7f ; 2
aso TMP ; 5 asl tmp; a = [tmp] OR $7f
axs $900c ; 4 [$900c] = a AND x
.ch1=*-2
dey ; 2
bne .l0 ; 3
lda #128 ; 2
.initfreq=*-1
nop ; 2
ldy TMP2 ; 3
.noset: sta $9000,y ; 5
rts ; 6 total clocks 11+4+3+2+16*7+16+6 eq 154
.ldfqmasks:
!byte $fe ; $900a - 1 x 16 clocks/bit
!byte $fd ; $900b - 2 x 8 clocks/bit
!byte $fb ; $900c - 4 x 4 clocks/bit
All of his documentation state that the sound channels use an 8-but shift register. The waveforms that he provides are all 16 bits long.
Are all 16 bits necessary to pound the 8-bit shift registers?
It looks like the second byte of each form is just the.
inversed form of the first.
Using all 16 has an effect as well as does using each half.
alone. I just wanted to make sure that I am achieving the.
desired effect.
Why did Viznut never implement the noise channel in any of his code?
Could he not get it to work?
Did it not produce his desired results?
Did it just not fit into his code format?
This question is on the Vic chip itself.
Why use 8- bit shift registers if your not going to make.
them controllers. Why not use a simple on/off switch?
Is it possible that control registers could have been.
intended but never implemented? Or implemented and.
just never documented?
documented?
Edit: this document had a little more detail. I found these documents while digging around in the midicart documentation
Code: Select all
> Users want to be able to use your waveforms over MIDI, so I'm
> implementing them as a Program Change. So here are my questions about
> your setwave code...
>
> 1) What exactly needs to be passed in A? The comments just say "a =
> shift register contents". Should A be the value represented by the
> binary value of the "waveform name"? i.e. if I want the "11010"
> waveform, do I pass in $1A?
>
> Is it valid to pass other values, or should I force it so that only
> those waveforms listed in your document are allowed?
You can pass any values. There are 16 waveforms, and each waveform cycles
thru 16 different shift register states, so each of the 16x16=256 possible
shift register contents is a valid state in one of the possible waveforms.
The "waveform names" I've given are just the shortest possible binary
sequences that set up each waveform.
And yes, you can put these binary numbers directly into A when using the
routine.
> 2) You have a comment "make sure that the channel has been at $7e for
> some time before calling this function.". Does that imply some
> silence before changing waveforms? Does this have to be repeated for
> every new note?
It implies that the shift register must be cleared before setting a new
waveform. The easiest way to clear the shift register is switching the
channel off for a short while. It is also important that the shift rate is
fast enough ($7E is the fastest setting).
Of course, it IS possible to change the waveform without fulfilling these
requirements, but in this case the exact change is not predictable. Still,
there is some VIC-20 music (e.g. Orb Megademo, Summer Lameness) that do this
kind of "random unpredictable tweaks" constantly in order to create a unique
kind of sound, so you might want to give the users this possibility as well.
When changing the note: if you just change the frequency (without turning
the channel off), then it is not necessary to set the waveform again.
However, if you have any silence before the new note, then it is necessary
to call the waveform routine again.
viznut
--------------------------------------------------------
> How long should I wait for? "A short while" isn't very precise ;-)
> (How many NOPs would I need?)
It depends on the channel and the pitch it's playing before setting it to
$7E. I once calculated the worst case as being 2160 clock cycles (for the
slowest channel ($900a) on the lowest pitch), but I haven't verified it in
practice as my players never need to change the waveform very often.
Anyway, if you want to be sure you don't wait any longer than you need to,
here's the formula I used:
offtime in clock cycles = clocks_per_shift * (wavelength + 7)
where clocks_per_shift is 16, 8 or 4 depending on the channel (alto, tenor,
soprano) and wavelength is ((126-PEEK(3687X))AND127)+1.
viznut