Welcome Guest

Username:

Password:


Remember me

[ ]
[ ]
[ ]

BitJam

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

Search BitFellas

Search BitJam:

Search Modland:

Scene City

content search


breadcrumb

Rob Hubbard's Music: Disassembled, Commented and Explained - C=hacking issue 5

on Mon 21 May 2007 by Anthony McSweeney author listemail the content item print the content item create pdf file of the content item

in Tutorials

comments: 0 hits: 2715


Rob Hubbard's Music: Disassembled, Commented and Explained
by Anthony McSweeney (u882859@postoffice.utas.edu.au)




Introduction:
************

How do you introduce someone like Rob Hubbard?? He came, he saw and he
conquered the '64 world. In my estimation, this one man was resposible for
selling more '64 software than any other single person. Hell! I think that Rob
Hubbard was responsible for selling more COMMODORE 64's than any other person!
I certainly bought my '64 after being blown away by the Monty on the Run music
in December 1985. In the next few years, Rob would totally dominate the '64
music scene, releasing one hit after another. I will even say that some really
terrible games sold well only on the strength of their brilliant Rob Hubbard
music (eg. KnuckleBusters and W.A.R.).

So how did Rob achieve this success? Firstly (of course) he is a superb
composer and musician, able to make the tunes that bring joy to our hearts
everytime we hear them! (also consider the amazing diversity of styles of
music that Rob composed). Secondly, he was able to make music which was suited
to the strengths and limitations of the SID chip. Just recall the soundfx used
at the beginning of Thrust, or in the Delta in-game music. Perhaps the biggest
limitation of SID must be the meagre 3 channels that can be used, but most
Hubbard songs appear to have four, five or even more instruments going (just
listen to the beginning of Phantoms of the Asteriods for example... that's
only one channel used!!). I could really go on for (p)ages identifying the
outstanding things that Rob Hubbard did, so I will finally mention that Rob's
coding skills and his music routines were a major factor in his success.


The First Rob Hubbard Routine:
*****************************

Rob Hubbard created a superb music routine from the very first tune which
was released (Confuzion). Furthermore, Rob used this routine to make music
for a very long time, only changing it _slightly_ over time. The sourcecode
that I present here was used (with slight modifications) in: Confuzion, Thing
on a Spring, Monty on the Run, Action Biker, Crazy Comets, Commando, Hunter
Patrol, Chrimera, The Last V8, Battle of Britain, Human Race, Zoids, Rasputin,
Master of Magic, One Man & His Droid, Game Killer, Gerry the Germ, Geoff Capes
Strongman Challenge, Phantoms of the Asteroids, Kentilla, Thrust,
International Karate, Spellbound, Bump Set and Spike, Formula 1 Simulator,
Video Poker, Warhawk or Proteus and many, many more! All you would need to do
to play a different music is to change the music data at the bottom, and a few
lines of the code.

This particular routine has been ripped off by many famous groups and
people over the years, but I don't think that they were ever generous enough
to share it around. Can you remember The Judges and Red Software?? They made
the famous Red-Hubbard demo, and used it in Rhaa-Lovely and many of their
other productions. I'm sure that the (Atari) ST freaks reading this will love
Mad Max (aka Jochen Hippel), and remember the BIG demo which featured approx
100 Rob Hubbard tunes converted to the ST. Although I hate to admit it, I
decided to start sharing around my own sourcecode after receiving the amazing
Protracker sourcecode (340K!) on the Amiga (thanks Lars Hamre). That made me
shameful to be selfish, especially after I learned alot of from it. Why don't
YOU share around your old sourcecodes too!

The particular routine that is included below was ripped from Monty on the
Run, and it appeared in memory from $8000 to about $9554. The complete
routine had code for soundfx in it, which I have taken out for the sake of
clarity. Although the routine is really tiny - a mere 900 or 1000 bytes of
code, there are some amazingly complex concepts in it which require alot of
explanation if you don't know much about computer music or SID. Fortunately
for you, I have put in excellent label names for you, and also alot of really
helpful and amazing comments. In fact, I think this sourcecode must have a
much better structure and comments than Rob Hubbard's original!!! I think that
the best way to understand the sourcecode is to study it, and figure out what
is going on using the comments.

In addition to the comments in the source, there are *3* descriptions of
the routine in this article. The first tells you how to use the music routine
when it's viewed as an already assembled 'module'. The second goes through an
overview of the music and instrument data format, and is great for getting an
overall feel for what the code is doing. The third description looks at the
various sections of the code, and how they come together.


How to use the sourcecode:
*************************

jsr music+0 to initialize the music number in the accumulator
jsr music+3 to play the music
jsr music+6 to stop the music and quieten SID

The music is supposed to run at 50Hz, or 50 times per second. Therefore
PAL users can run the music routine off the IRQ like this:

lda #$00 ; init music number 0
jsr music+0
sei ; install the irq and a raster compare
lda # ldx #>irq
sta $314
stx $315
lda #$1b
sta $d011
lda #$01
sta $d01a
lda #$7f
sta $dc0d
cli
loop =*
jmp loop ; endless loop (music is now playing off interrupt

irq =*
lda #$01
sta $d019
lda #$3c
sta $d012

inc $d020 ; play music, and show a raster for the time it takes
jsr music+3
dec $d020

lda #$14
sta $d018
jmp $ea31

If this method is used on NTSC machines, then the music will be running at
60Hz and will sound much to fast - possibly it might sound terrible. I'm
afraid you'll have to put up with this unless YOU are good enough to make a
CIA interrupt at 50Hz. As I havn't had to worry about NTSC users before,
perhaps someone will send me the best way to do this...

[Ed. Note: You could also keep a counter for the IRQ and don't execute it
every 6 interrupt. This will make it the right speed although the best
solution is for modifying the CIA to 50Hz like he mentions above.]

How the music data is arranged:
******************************

1. The music 'module' contains one or more songs.

Each RH music is made up of a 'bunch' of songs in a single module. Thus
the 'module' can have the title music, in-game music, and the game-over music
all using the same playroutine (and even the same instruments . The source
that appears below only has the one song in it, and the music number is
automatically set to 0 as a result (line 20). The label 'songs' is where you
want to look for the pointers to the songs if you want to change this.

2. Each song is made up of three tracks.

We all know that there are only 3 channels on the SID chip, so there are
also 3 tracks - one for each channel. When I said 'pointers to the songs'
above, I was therefore referring to 'pointers to the three tracks that make up
the song'...hence we are looking at the label 'songs' again. Each track needs
a high and low pointer, so there are 6 bytes needed to point to a song.

3. Each track is made up of a list of pattern numbers

Each track consists of a list of the pattern numbers in the order in which
they are to be played. Here we are looking at the labels 'montymaintr1' and
'montymaintr2'and 'montymaintr3'. Therefore I can tell you that the initial
patterns played in this song are $11, $12 and $13 on channels 1,2 and 3
respectively. The track is either ended with a $ff or $fe byte. A $ff means
that the song needs to be looped when the end of the track is reached (like
the monty main tune), while a $fe means that the song is only to be played
once. The current offset into the track is often called the current POSITION
for that track.

4. A pattern consists of a sequence of notes.

A pattern contains the data that says when the notes should be played, how
long they should be played for, at what pitch, with what instrument, should
there be ADSR, should there be bending (portamento) of the notes etc. Each
pattern is ended with a $ff byte, and when this is encountered, the next
pattern in the track will be played. Each note has up to a 4 byte
specification.

- The first byte is always the length of the note from 0-31 or 0-$1f in hex.
You will notice that the top three bits are not used for the length of the
note, so they are used for other things.
- Bit#5 signals no release needed. - Bit#6 signals that this note is
appended to the last one (no attack/etc). - Bit#7 signals that a new
instrument or portamento is coming up.

- The second byte is an optional byte, and it holds the instument number to
use or the portamento value (ie a bended note). This byte will be needed
according to whether bit#7 of the first byte is set or not...ie if the 1st
byte was negative, then this byte is needed.
- If the second byte is positive, then this is the new instrument number.
- If the second byte is negative, then this is a bended note (portamento).
and the value is the speed of the portamento (except for bits #7 and #0)
Bit #0 of the portamento byte determines the direction of the bend.
- Bit#0 = 0 then portamento is up.
- Bit#0 = 1 then portamento is down.

- The third byte of the specification is the pitch of the note. A pitch of
0 is the lowest C possible. A pitch of 12 or $C(hex) is the next highest
C above that. These pitches are denoted fairly universally as eg. 'C-1' and
for sharps eg. 'D#3'. Notice that this routine uses pitches of higher than
72 ($48) which is c-6

- The fourth byte if it exists will denote the end of the pattern.
ie. If the next byte is a $ff, then this is the end of the pattern.

NOTE: I have labelled the various bytes with numbers for convenience. Bear
in mind that some of these are optional, so if the second byte is not needed,
then I will say that the pitch of the note coming up is the 'third byte',
even though it isn't really.

Okay, here are some examples:

eg. $84,$04,$24 means that the length of the note is 4 (from the lower 5 bits
of the first byte), that the instrument to use is instrument number 4
(the second byte, as indicated by bit #7 of the first byte), and that the
pitch of the note is $24 or c-3.
eg. $D6,$98,$25,$FF means that the length of the note is 22 ($16), that this
note should be appended to the last, that the second byte is a portamento
(as both 1st and 2nd bytes -ve!), that the portamento is going up (as
bit#0 = 0) with a speed of 24 ($18), that the pitch of the note is $25
or c#3, and that this is the end of the pattern.

It doesn't get any harder than that!! Did you realise that this is exactly
the way that Rob Hubbard made the music!! He worked out some musical ideas
on his cheap (musical) keyboard, and typed the notes into his assembler in
hex, just like this.


5. The instruments are an 8 byte data structure.

You are looking at the label 'instr' at the bottom of the sourcecode. The
8 bytes which come along first are instrument numnber 0, the next 8 define
instrument number 1, etc. Here are the meanings of the bytes, but I suggest
that you check out your programming manuals if you are unfamiliar with these:

- Byte 0 is the pulse width low byte, and
- Byte 1 is the pulse width high byte. (also see byte 7).

- Byte 2 is the control register byte.
This specifies which type of sound should be used; sine, sawtooth etc.

- Byte 3 is the attack and decay values, and
- Byte 4 is the sustain and release values.
The note's volume is altered according to these values. When the attack and
decay are over, the volume of the note is held at the sustain level. When
length of a note is over, a release is done through the 'gate' bit in SID.

- Byte 5 is the vibrato depth for the instrument.

- Byte 6 is the pulse speed.
Timbre is created by changing the shape of the waveform each 50th of a
second, and this is the most common way of achieving it. The shape of
the pulse waveform changes from square to a very rectangular at a speed
according to this byte.
N.B. if you are interested in how the pulse value number works, then
e-mail me sometime, as I found this out (exhaustively) a few days ago!

- Byte 7 is the instrument fx byte, and is the major thing which changes
between different music routines. Each bit in this byte determines whether
this instrument will have a certain effect in it.
- Bit#0 signals that this is a drum. Drums are made from a noise channel
and also a fast frequency down, with fast decay. Bass drums use a square
wave, and only the first 50th of a second is a noise channel. This is
the tell-tale instrument that gives away a Rob Hubbard routine! Hihats
and other drums use noise all the time.
- Bit#1 signals a 'skydive'. This is a slower frequency down, that I think
sounds like somebody yelling as they fall out of a plane .. AHHHHhhhhgh..
..hence I call it a skydive!!
- Bit#2 signals an octave arpeggio. It's a very limited arpeggio routine in
this song. Listen for the arpeggio and the skydive when combined, which
is used alot in Hubbard songs.
- All the other bits have no meaning in this music, but were used alot in
later music for the fx.

A big reason that I presented this early routine, was because there was not
too much in the way of special fx to confuse you. As a result, you can
concentrate on the guts of the code instead of the special fx


How the sourcecode works:
************************

The routines at the top of the sourcecode are concerned with turning the
music on and off, and you will see that this is done through a variable called
'mstatus' (or music status). If mstatus is set to $C0, then the music is
turned off and SID is quietened, thereafter mstatus is set to $80 which means
that the music is still off, but SID doesn't need to be quietened again. When
the music is initialized, then mstatus is given a value of $40 which kicks in
the further initialization stuff. If mstatus is any other value, then the
music is being played. For any of the initialization stuff to have any meaning
to you, you ofcourse have to understand the rest of the playroutine

After we have got past the on/off/init stuff, we are at the label called
'contplay' at around line 100. The first thing you should notice is that this
is the start of a huge loop that is done *3* times - once for each channel.
The loop really *is* huge, as it ends right on the last few lines of the code


Now that we are talking about routines within the loop, we are talking about
these routines being applied to the channels independantly. There are 2 main
routines within the loop, one is called NoteWork, and the other is called
SoundWork. NoteWork checks to see whether a new note is needed on this
channel, and if it is, then the notedata is fetched and stuff is initialized.
If no note is needed, then SoundWork is called which processes the instruments
and does the portamento.

NoteWork first checks the speed at which the notes are fetched. If the delay
is still occurring, then new notes are not needed and soundwork is called.
N.B. that the speed for Monty on the Run is 1, which means that a note of
length $1f will last for 64 calls to the routine (ie just over a second). If
the speed of the song is reset, then NoteWork decrements the length of the
current note. When the length of the current note hits $ff (-1) then a new
note is needed, otherwise SoundWork is jumped to.

The data for a new note is collected at the label 'getnewnote'. In the
simplest case, this involves getting the next bytes of data from the current
pattern on this channel, but if the end of the pattern is reached, then the
next pattern number is fetched by reference to the current position within
this channel's track. In an even more complex situation, the end of a track is
reached, and the current position needs to be reset to 0 before the next
pattern number can be found.

You can see quite clearly in this part of the routine where the length of
the note is collected, and it is determined whether a 2nd byte is needed,
where the pitch is collected, and the end of the song checked. You can also
see where some of the data is collected from the current instrument and jammed
into the SID registers.

SoundWork is called if no new notes are needed, and it processes the
instruments and does the portamento etc. This part of the routine is neatly
expressed in sections which are really well commented and quite easy to
understand.

- The first thing that occurs in SoundWork is that the 'gate bit' of SID is
set when the length of the note is over - this causes a release of the note.

- The vibrato routine is quite inefficient, but it's pretty good for 1985!
Ofcourse vibrato is implemented by raising and lowering the pitch of the
note ever-so-slightly causing the note to 'float'. The amount of the
vibrato is determined in the current instrument.

- The pulsework routine changes the pulsewidth between square wave and very
rectangular wave according to the pulsespeed in the current instrument.
(ie. it changes the sound of the instrument and thus alters the 'timbre')
The routine goes backwards and forwards between the two; and switches
when one extremity is reached. It's interesting to note that the current
values of the pulse width are actually stored in the instrument

- Portamento is achieved by adding/subtracting an amount of frequency to
the current frequency each time this part of the routine is called.

- The instrument fx routines are also really easy to figure out, as they are
well commented. Both the drums and the skydive do a very fast frequency
down, so it is the most significant byte of the frequency which is reduced
.. and not 16-bit maths (math?!) The arpeggio is only an octave arpeggio,
so for the first 50th of a second, the current note is played, and for
the next 50th of a second, current note+12 is played, followed by the
current note again etc.
( If you don't know what an arpeggio is..it's generally when the notes of )
( a chord are played individually in a rapid succession. It produces a )
( 'full' sound depending on the speed of the arpeggio. In most cases the )
( note is changed 50 times per second, which gives a very nice sound. If )
( you have listened to some computer music, then you will have definately )
( listened to an arpeggios all the time, even if you don't realize it! )


Final Thoughts:
**************

*Bounce* I'm finally near the end of this article! It has been alot of work
to try to explain this routine, but I'm glad that I've done it *grin* If you
have any questions then please feel free to e-mail me, or even e-mail Craig if
it's after August 1993 and I'll make sure that I leave a forwarding address
with him. Also, please feel free to e-mail me and tell me what you think of
this article. I will only be bothered writing more of the same if I know that
someone is finding them useful/interesting. Also e-mail me if you are
interested in Amiga or ST music too, as I've done alot on both of those
machines.

I'm not sure whether Craig will be putting the actual sourcecode below this
text, or in some kind of Appendix. In either case, I SHALL take all legal
responsibilty for publishing Rob Hubbard's routine. Craig was quite reluctant
to publish the routine in his net-mag because of copyright reasons. As a
post-graduate law student that will be working as a commercial lawyer
(attourney for Americans specializing in copyright/patents for computer
software/hardware starting August this year, I don't believe that there are
any practical legal consequences for me.

I would have given an arm or a leg for a commented Rob Hubbard sourcecode in
the past, so I hope you enjoy this valuable offering.
-----------------------------------------------------------------------------
;rob hubbard
;monty on the run music driver

;this player was used (with small mods)
;for his first approx 30 musix

.org $8000
.obj motr

jmp initmusic
jmp playmusic
jmp musicoff


;====================================
;init music

initmusic =*

lda #$00 ;music num
ldy #$00
asl
sta tempstore
asl
clc
adc tempstore ;now music num*6
tax

- lda songs,x ;copy ptrs to this
sta currtrkhi,y ;music's tracks to
inx ;current tracks
iny
cpy #$06
bne -

lda #$00 ;clear control regs
sta $d404
sta $d40b
sta $d412
sta $d417

lda #$0f ;full volume
sta $d418

lda #$40 ;flag init music
sta mstatus

rts


;====================================
;music off

musicoff =*

lda #$c0 ;flag music off
sta mstatus
rts


;====================================
;play music

playmusic =*

inc counter

bit mstatus ;test music status
bmi moff ;$80 and $c0 is off
bvc contplay ;$40 init, else play


;==========
;init the song (mstatus $40)

lda #$00 ;init counter
sta counter

ldx #3-1
- sta posoffset,x ;init pos offsets
sta patoffset,x ;init pat offsets
sta lengthleft,x ;get note right away
sta notenum,x
dex
bpl -

sta mstatus ;signal music play
jmp contplay


;==========
;music is off (mstatus $80 or $c0)

moff =*

bvc + ;if mstatus $c0 then
lda #$00
sta $d404 ;kill voice 1,2,3
sta $d40b ;control registers
sta $d412

lda #$0f ;full volume still
sta $d418

lda #$80 ;flag no need to kill
sta mstatus ;sound next time

+ jmp musicend ;end


;==========
;music is playing (mstatus otherwise)

contplay =*

ldx #3-1 ;number of chanels

dec speed ;check the speed
bpl mainloop

lda resetspd ;reset speed if needed
sta speed


mainloop =*

lda regoffsets,x ;save offset to regs
sta tmpregofst ;for this channel
tay


;check whether a new note is needed

lda speed ;if speed not reset
cmp resetspd ;then skip notework
beq checknewnote
jmp vibrato

checknewnote =*

lda currtrkhi,x ;put base addr.w of
sta $02 ;this track in $2
lda currtrklo,x
sta $03

dec lengthleft,x ;check whether a new
bmi getnewnote ;note is needed

jmp soundwork ;no new note needed


;==========
;notework
;a new note is needed. get the pattern
;number/cc from this position

getnewnote =*

ldy posoffset,x ;get the data from
lda ($02),y ;the current position

cmp #$ff ;pos $ff restarts
beq restart

cmp #$fe ;pos $fe stops music
bne getnotedata ;on all channels
jmp musicend

;cc of $ff restarts this track from the
;first position

restart =*

lda #$00 ;get note immediately
sta lengthleft,x ;and reset pat,pos
sta posoffset,x
sta patoffset,x
jmp getnewnote


;get the note data from this pattern

getnotedata =*

tay
lda patptl,y ;put base addr.w of
sta $04 ;the pattern in $4
lda patpth,y
sta $05

lda #$00 ;default no portamento
sta portaval,x

ldy patoffset,x ;get offset into ptn

lda #$ff ;default no append
sta appendfl

;1st byte is the length of the note 0-31
;bit5 signals no release (see sndwork)
;bit6 signals appended note
;bit7 signals a new instrument
; or portamento coming up

lda ($04),y ;get length of note
sta savelnthcc,x
sta templnthcc
and #$1f
sta lengthleft,x

bit templnthcc ;test for append
bvs appendnote

inc patoffset,x ;pt to next data

lda templnthcc ;2nd byte needed?
bpl getpitch

;2nd byte needed as 1st byte negative
;2nd byte is the instrument number(+ve)
;or portamento speed(-ve)

iny
lda ($04),y ;get instr/portamento
bpl +

sta portaval,x ;save portamento val
jmp ++

+ sta instrnr,x ;save instr nr

+ inc patoffset,x

;3rd byte is the pitch of the note
;get the 'base frequency' here

getpitch =*

iny
lda ($04),y ;get pitch of note
sta notenum,x
asl ;pitch*2
tay
lda frequenzlo,y ;save the appropriate
sta tempfreq ;base frequency
lda frequenzhi,y
ldy tmpregofst
sta $d401,y
sta savefreqhi,x
lda tempfreq
sta $d400,y
sta savefreqlo,x
jmp +

appendnote =*

dec appendfl ;clever eh?


;fetch all the initial values from the
;instrument data structure

+ ldy tmpregofst
lda instrnr,x ;instr num
stx tempstore
asl ;instr num*8
asl
asl
tax

lda instr+2,x ;get control reg val
sta tempctrl
lda instr+2,x
and appendfl ;implement append
sta $d404,y

lda instr+0,x ;get pulse width lo
sta $d402,y

lda instr+1,x ;get pulse width hi
sta $d403,y

lda instr+3,x ;get attack/decay
sta $d405,y

lda instr+4,x ;get sustain/release
sta $d406,y

ldx tempstore ;save control reg val
lda tempctrl
sta voicectrl,x


;4th byte checks for the end of pattern
;if eop found, inc the position and
;reset patoffset for new pattern

inc patoffset,x ;preview 4th byte
ldy patoffset,x
lda ($04),y

cmp #$ff ;check for eop
bne +

lda #$00 ;end of pat reached
sta patoffset,x ;inc position for
inc posoffset,x ;the next time

+ jmp loopcont


;==========
;soundwork
;the instrument and effects processing
;routine when no new note was needed

soundwork =*

;release routine
;set off a release when the length of
;the note is exceeded
;bit4 of the 1st note-byte can specify
;for no release

ldy tmpregofst

lda savelnthcc,x ;check for no release
and #$20 ;specified
bne vibrato

lda lengthleft,x ;check for length of
bne vibrato ;exceeded

lda voicectrl,x ;length exceeded so
and #$fe ;start the release
sta $d404,y ;and kill adsr
lda #$00
sta $d405,y
sta $d406,y


;vibrato routine
;(does alot of work)

vibrato =*

lda instrnr,x ;instr num
asl
asl
asl ;instr num*8
tay
sty instnumby8 ;save instr num*8

lda instr+7,y ;get instr fx byte
sta instrfx

lda instr+6,y ;get pulse speed
sta pulsevalue

lda instr+5,y ;get vibrato depth
sta vibrdepth
beq pulsework ;check for no vibrato

lda counter ;this is clever!!
and #7 ;the counter's turned
cmp #4 ;into an oscillating
bcc + ;value (01233210)
eor #7
+ sta oscilatval

lda notenum,x ;get base note
asl ;note*2
tay ;get diff btw note
sec ;and note+1 frequency
lda frequenzlo+2,y
sbc frequenzlo,y
sta tmpvdiflo
lda frequenzhi+2,y
sbc frequenzhi,y

- lsr ;divide difference by
ror tmpvdiflo ;2 for each vibrdepth
dec vibrdepth
bpl -
sta tmpvdifhi

lda frequenzlo,y ;save note frequency
sta tmpvfrqlo
lda frequenzhi,y
sta tmpvfrqhi

lda savelnthcc,x ;no vibrato if note
and #$1f ;length less than 8
cmp #8
bcc +

ldy oscilatval

- dey ;depending on the osc
bmi + ;value, add the vibr
clc ;freq that many times
lda tmpvfrqlo ;to the base freq
adc tmpvdiflo
sta tmpvfrqlo
lda tmpvfrqhi
adc tmpvdifhi
sta tmpvfrqhi
jmp -

+ ldy tmpregofst ;save the final
lda tmpvfrqlo ;frequencies
sta $d400,y
lda tmpvfrqhi
sta $d401,y


;pulse-width timbre routine
;depending on the control/speed byte in
;the instrument datastructure, the pulse
;width is of course inc/decremented to
;produce timbre

;strangely the delay value is also the
;size of the inc/decrements

pulsework =*

lda pulsevalue ;check for pulsework
beq portamento ;needed this instr

ldy instnumby8
and #$1f
dec pulsedelay,x ;pulsedelay-1
bpl portamento

sta pulsedelay,x ;reset pulsedelay

lda pulsevalue ;restrict pulse speed
and #$e0 ;from $00-$1f
sta pulsespeed

lda pulsedir,x ;pulsedir 0 is up and
bne pulsedown ;1 is down

lda pulsespeed ;pulse width up
clc
adc instr+0,y ;add the pulsespeed
pha ;to the pulse width
lda instr+1,y
adc #$00
and #$0f
pha
cmp #$0e ;go pulsedown when
bne dumpulse ;the pulse value
inc pulsedir,x ;reaches max ($0exx)
jmp dumpulse

pulsedown =*

sec ;pulse width down
lda instr+0,y
sbc pulsespeed ;sub the pulsespeed
pha ;from the pulse width
lda instr+1,y
sbc #$00
and #$0f
pha
cmp #$08 ;go pulseup when
bne dumpulse ;the pulse value
dec pulsedir,x ;reaches min ($08xx)

dumpulse =*

stx tempstore ;dump pulse width to
ldx tmpregofst ;chip and back into
pla ;the instr data str
sta instr+1,y
sta $d403,x
pla
sta instr+0,y
sta $d402,x
ldx tempstore


;portamento routine
;portamento comes from the second byte
;if it's a negative value

portamento =*

ldy tmpregofst
lda portaval,x ;check for portamento
beq drums ;none

and #$7e ;toad unwanted bits
sta tempstore

lda portaval,x ;bit0 signals up/down
and #$01
beq portup

sec ;portamento down
lda savefreqlo,x ;sub portaval from
sbc tempstore ;current frequency
sta savefreqlo,x
sta $d400,y
lda savefreqhi,x
sbc #$00 ;(word arithmetic)
sta savefreqhi,x
sta $d401,y
jmp drums

portup =*

clc ;portamento up
lda savefreqlo,x ;add portval to
adc tempstore ;current frequency
sta savefreqlo,x
sta $d400,y
lda savefreqhi,x
adc #$00
sta savefreqhi,x
sta $d401,y


;bit0 instrfx are the drum routines
;the actual drum timbre depends on the
;crtl register value for the instrument:
;ctrlreg 0 is always noise
;ctrlreg x is noise for 1st vbl and x
;from then on

;see that the drum is made by rapid hi
;to low frequency slide with fast attack
;and decay

drums =*

lda instrfx ;check if drums
and #$01 ;needed this instr
beq skydive

lda savefreqhi,x ;don't bother if freq
beq skydive ;can't go any lower

lda lengthleft,x ;or if the note has
beq skydive ;finished

lda savelnthcc,x ;check if this is the
and #$1f ;first vbl for this
sec ;instrument-note
sbc #$01
cmp lengthleft,x
ldy tmpregofst
bcc firstime

lda savefreqhi,x ;not the first time
dec savefreqhi,x ;so dec freqhi for
sta $d401,y ;drum sound

lda voicectrl,x ;if ctrlreg is 0 then
and #$fe ;noise is used always
bne dumpctrl

firstime =*

lda savefreqhi,x ;noise is used for
sta $d401,y ;the first vbl also
lda #$80 ;(set noise)

dumpctrl =*

sta $d404,y


;bit1 instrfx is the skydive
;a long portamento-down from the note
;to zerofreq

skydive =*

lda instrfx ;check if skydive
and #$02 ;needed this instr
beq octarp

lda counter ;every 2nd vbl
and #$01
beq octarp

lda savefreqhi,x ;check if skydive
beq octarp ;already complete

dec savefreqhi,x ;decr and save the
ldy tmpregofst ;high byte freq
sta $d401,y


;bit2 instrfx is an octave arpeggio
;pretty tame huh?

octarp =*

lda instrfx ;check if arpt needed
and #$04
beq loopcont

lda counter ;only 2 arpt values
and #$01
beq +

lda notenum,x ;odd, note+12
clc
adc #$0c
jmp ++

+ lda notenum,x ;even, note

+ asl ;dump the corresponding
tay ;frequencies
lda frequenzlo,y
sta tempfreq
lda frequenzhi,y
ldy tmpregofst
sta $d401,y
lda tempfreq
sta $d400,y


;==========
;end of dbf loop

loopcont =*

dex ;dbf mainloop
bmi musicend
jmp mainloop

musicend =*

rts


;====================================
;frequenz data
;====================================

frequenzlo .byt $16
frequenzhi .byt $01
.byt $27,$01,$38,$01,$4b,$01
.byt $5f,$01,$73,$01,$8a,$01,$a1,$01
.byt $ba,$01,$d4,$01,$f0,$01,$0e,$02
.byt $2d,$02,$4e,$02,$71,$02,$96,$02
.byt $bd,$02,$e7,$02,$13,$03,$42,$03
.byt $74,$03,$a9,$03,$e0,$03,$1b,$04
.byt $5a,$04,$9b,$04,$e2,$04,$2c,$05
.byt $7b,$05,$ce,$05,$27,$06,$85,$06
.byt $e8,$06,$51,$07,$c1,$07,$37,$08
.byt $b4,$08,$37,$09,$c4,$09,$57,$0a
.byt $f5,$0a,$9c,$0b,$4e,$0c,$09,$0d
.byt $d0,$0d,$a3,$0e,$82,$0f,$6e,$10
.byt $68,$11,$6e,$12,$88,$13,$af,$14
.byt $eb,$15,$39,$17,$9c,$18,$13,$1a
.byt $a1,$1b,$46,$1d,$04,$1f,$dc,$20
.byt $d0,$22,$dc,$24,$10,$27,$5e,$29
.byt $d6,$2b,$72,$2e,$38,$31,$26,$34
.byt $42,$37,$8c,$3a,$08,$3e,$b8,$41
.byt $a0,$45,$b8,$49,$20,$4e,$bc,$52
.byt $ac,$57,$e4,$5c,$70,$62,$4c,$68
.byt $84,$6e,$18,$75,$10,$7c,$70,$83
.byt $40,$8b,$70,$93,$40,$9c,$78,$a5
.byt $58,$af,$c8,$b9,$e0,$c4,$98,$d0
.byt $08,$dd,$30,$ea,$20,$f8,$2e,$fd


regoffsets .byt $00,$07,$0e
tmpregofst .byt $00
posoffset .byt $00,$00,$00
patoffset .byt $00,$00,$00
lengthleft .byt $00,$00,$00
savelnthcc .byt $00,$00,$00
voicectrl .byt $00,$00,$00
notenum .byt $00,$00,$00
instrnr .byt $00,$00,$00
appendfl .byt $00
templnthcc .byt $00
tempfreq .byt $00
tempstore .byt $00
tempctrl .byt $00
vibrdepth .byt $00
pulsevalue .byt $00
tmpvdiflo .byt $00
tmpvdifhi .byt $00
tmpvfrqlo .byt $00
tmpvfrqhi .byt $00
oscilatval .byt $00
pulsedelay .byt $00,$00,$00
pulsedir .byt $00,$00,$00
speed .byt $00
resetspd .byt $01
instnumby8 .byt $00
mstatus .byt $c0
savefreqhi .byt $00,$00,$00
savefreqlo .byt $00,$00,$00
portaval .byt $00,$00,$00
instrfx .byt $00
pulsespeed .byt $00
counter .byt $00
currtrkhi .byt $00,$00,$00
currtrklo .byt $00,$00,$00


;====================================
;monty on the run main theme
;====================================

songs =*
.byt .byt .byt .byt >montymaintr1
.byt >montymaintr2
.byt >montymaintr3


;====================================
;pointers to the patterns

;low pointers
patptl =*
.byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt 0
.byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt .byt
;high pointers
patpth =*
.byt >ptn00
.byt >ptn01
.byt >ptn02
.byt >ptn03
.byt >ptn04
.byt >ptn05
.byt >ptn06
.byt >ptn07
.byt >ptn08
.byt >ptn09
.byt >ptn0a
.byt >ptn0b
.byt >ptn0c
.byt >ptn0d
.byt >ptn0e
.byt >ptn0f
.byt >ptn10
.byt >ptn11
.byt >ptn12
.byt >ptn13
.byt >ptn14
.byt >ptn15
.byt >ptn16
.byt >ptn17
.byt >ptn18
.byt >ptn19
.byt >ptn1a
.byt >ptn1b
.byt >ptn1c
.byt >ptn1d
.byt >ptn1e
.byt >ptn1f
.byt >ptn20
.byt >ptn21
.byt >ptn22
.byt >ptn23
.byt >ptn24
.byt >ptn25
.byt >ptn26
.byt >ptn27
.byt >ptn28
.byt >ptn29
.byt >ptn2a
.byt >ptn2b
.byt >ptn2c
.byt >ptn2d
.byt 0
.byt >ptn2f
.byt >ptn30
.byt >ptn31
.byt >ptn32
.byt >ptn33
.byt >ptn34
.byt >ptn35
.byt >ptn36
.byt >ptn37
.byt >ptn38
.byt >ptn39
.byt >ptn3a
.byt >ptn3b


;====================================
;tracks
;====================================

;track1
montymaintr1 =*
.byt $11,$14,$17,$1a,$00,$27,$00,$28
.byt $03,$05,$00,$27,$00,$28,$03,$05
.byt $07,$3a,$14,$17,$00,$27,$00,$28
.byt $2f,$30,$31,$31,$32,$33,$33,$34
.byt $34,$34,$34,$34,$34,$34,$34,$35
.byt $35,$35,$35,$35,$35,$36,$12,$37
.byt $38,$09,$2a,$09,$2b,$09,$0a,$09
.byt $2a,$09,$2b,$09,$0a,$0d,$0d,$0f
.byt $ff

;track2
montymaintr2 =*
.byt $12,$15,$18,$1b,$2d,$39,$39
.byt $39,$39,$39,$39,$2c,$39,$39,$39
.byt $39,$39,$39,$2c,$39,$39,$39,$01
.byt $01,$29,$29,$2c,$15,$18,$39,$39
.byt $39,$39,$39,$39,$39,$39,$39,$39
.byt $39,$39,$39,$39,$39,$39,$39,$39
.byt $39,$39,$39,$39,$39,$39,$39,$39
.byt $39,$39,$39,$39,$39,$01,$01,$01
.byt $29,$39,$39,$39,$01,$01,$01,$29
.byt $39,$39,$39,$39,$ff

;track3
montymaintr3 =*
.byt $13,$16,$19
.byt $1c,$02,$02,$1d,$1e,$02,$02,$1d
.byt $1f,$04,$04,$20,$20,$06,$02,$02
.byt $1d,$1e,$02,$02,$1d,$1f,$04,$04
.byt $20,$20,$06,$08,$08,$08,$08,$21
.byt $21,$21,$21,$22,$22,$22,$23,$22
.byt $24,$25,$3b,$26,$26,$26,$26,$26
.byt $26,$26,$26,$26,$26,$26,$26,$26
.byt $26,$26,$26,$02,$02,$1d,$1e,$02
.byt $02,$1d,$1f,$2f,$2f,$2f,$2f,$2f
.byt $2f,$2f,$2f,$2f,$2f,$2f,$2f,$2f
.byt $0b,$0b,$1d,$1d,$0b,$0b,$1d,$0b
.byt $0b,$0b,$0c,$0c,$1d,$1d,$1d,$10
.byt $0b,$0b,$1d,$1d,$0b,$0b,$1d,$0b
.byt $0b,$0b,$0c,$0c,$1d,$1d,$1d,$10
.byt $0b,$1d,$0b,$1d,$0b,$1d,$0b,$1d
.byt $0b,$0c,$1d,$0b,$0c,$23,$0b,$0b
.byt $ff


;====================================
;patterns
;====================================

ptn00 =*
.byt $83,$00,$37,$01,$3e,$01,$3e,$03
.byt $3d,$03,$3e,$03,$43,$03,$3e,$03
.byt $3d,$03,$3e,$03,$37,$01,$3e,$01
.byt $3e,$03,$3d,$03,$3e,$03,$43,$03
.byt $42,$03,$43,$03,$45,$03,$46,$01
.byt $48,$01,$46,$03,$45,$03,$43,$03
.byt $4b,$01,$4d,$01,$4b,$03,$4a,$03
.byt $48,$ff

ptn27 =*
.byt $1f,$4a,$ff

ptn28 =*
.byt $03,$46,$01,$48,$01,$46,$03,$45
.byt $03,$4a,$0f,$43,$ff

ptn03 =*
.byt $bf,$06
.byt $48,$07,$48,$01,$4b,$01,$4a,$01
.byt $4b,$01,$4a,$03,$4b,$03,$4d,$03
.byt $4b,$03,$4a,$3f,$48,$07,$48,$01
.byt $4b,$01,$4a,$01,$4b,$01,$4a,$03
.byt $4b,$03,$4d,$03,$4b,$03,$48,$3f
.byt $4c,$07,$4c,$01,$4f,$01,$4e,$01
.byt $4f,$01,$4e,$03,$4f,$03,$51,$03
.byt $4f,$03,$4e,$3f,$4c,$07,$4c,$01
.byt $4f,$01,$4e,$01,$4f,$01,$4e,$03
.byt $4f,$03,$51,$03,$4f,$03,$4c,$ff

ptn05 =*
.byt $83,$04,$26,$03,$29,$03,$28,$03
.byt $29,$03,$26,$03,$35,$03,$34,$03
.byt $32,$03,$2d,$03,$30,$03,$2f,$03
.byt $30,$03,$2d,$03,$3c,$03,$3b,$03
.byt $39,$03,$30,$03,$33,$03,$32,$03
.byt $33,$03,$30,$03,$3f,$03,$3e,$03
.byt $3c,$03,$46,$03,$45,$03,$43,$03
.byt $3a,$03,$39,$03,$37,$03,$2e,$03
.byt $2d,$03,$26,$03,$29,$03,$28,$03
.byt $29,$03,$26,$03,$35,$03,$34,$03
.byt $32,$03,$2d,$03,$30,$03,$2f,$03
.byt $30,$03,$2d,$03,$3c,$03,$3b,$03
.byt $39,$03,$30,$03,$33,$03,$32,$03
.byt $33,$03,$30,$03,$3f,$03,$3e,$03
.byt $3c,$03,$34,$03,$37,$03,$36,$03
.byt $37,$03,$34,$03,$37,$03,$3a,$03
.byt $3d

ptn3a =*
.byt $03,$3e,$07,$3e,$07,$3f,$07
.byt $3e,$03,$3c,$07,$3e,$57,$ff

ptn07 =*
.byt $8b
.byt $00,$3a,$01,$3a,$01,$3c,$03,$3d
.byt $03,$3f,$03,$3d,$03,$3c,$0b,$3a
.byt $03,$39,$07,$3a,$81,$06,$4b,$01
.byt $4d,$01,$4e,$01,$4d,$01,$4e,$01
.byt $4d,$05,$4b,$81,$00,$3a,$01,$3c
.byt $01,$3d,$03,$3f,$03,$3d,$03,$3c
.byt $03,$3a,$03,$39,$1b,$3a,$0b,$3b
.byt $01,$3b,$01,$3d,$03,$3e,$03,$40
.byt $03,$3e,$03,$3d,$0b,$3b,$03,$3a
.byt $07,$3b,$81,$06,$4c,$01,$4e,$01
.byt $4f,$01,$4e,$01,$4f,$01,$4e,$05
.byt $4c,$81,$00,$3b,$01,$3d,$01,$3e
.byt $03,$40,$03,$3e,$03,$3d,$03,$3b
.byt $03,$3a,$1b,$3b,$8b,$05,$35,$03
.byt $33,$07,$32,$03,$30,$03,$2f,$0b
.byt $30,$03,$32,$0f,$30,$0b,$35,$03
.byt $33,$07,$32,$03,$30,$03,$2f,$1f
.byt $30,$8b,$00,$3c,$01,$3c,$01,$3e
.byt $03,$3f,$03,$41,$03,$3f,$03,$3e
.byt $0b,$3d,$01,$3d,$01,$3f,$03,$40
.byt $03,$42,$03,$40,$03,$3f,$03,$3e
.byt $01,$3e,$01,$40,$03,$41,$03,$40
.byt $03,$3e,$03,$3d,$03,$3e,$03,$3c
.byt $03,$3a,$01,$3a,$01,$3c,$03,$3d
.byt $03,$3c,$03,$3a,$03,$39,$03,$3a
.byt $03,$3c,$ff

ptn09 =*
.byt $83,$00,$32,$01,$35,$01,$34,$03
.byt $32,$03,$35,$03,$34,$03,$32,$03
.byt $35,$01,$34,$01,$32,$03,$32,$03
.byt $3a,$03,$39,$03,$3a,$03,$32,$03
.byt $3a,$03,$39,$03,$3a,$ff

ptn2a =*
.byt $03,$34,$01,$37,$01,$35,$03,$34
.byt $03,$37,$03,$35,$03,$34,$03,$37
.byt $01,$35,$01,$34,$03,$34,$03,$3a
.byt $03,$39,$03,$3a,$03,$34,$03,$3a
.byt $03,$39,$03,$3a,$ff

ptn2b =*
.byt $03,$39,$03,$38,$03,$39,$03,$3a
.byt $03,$39,$03,$37,$03,$35,$03,$34
.byt $03,$35,$03,$34,$03,$35,$03,$37
.byt $03,$35,$03,$34,$03,$32,$03,$31
.byt $ff

ptn0a =*
.byt $03
.byt $37,$01,$3a,$01,$39,$03,$37,$03
.byt $3a,$03,$39,$03,$37,$03,$3a,$01
.byt $39,$01,$37,$03,$37,$03,$3e,$03
.byt $3d,$03,$3e,$03,$37,$03,$3e,$03
.byt $3d,$03,$3e,$03,$3d,$01,$40,$01
.byt $3e,$03,$3d,$03,$40,$01,$3e,$01
.byt $3d,$03,$40,$03,$3e,$03,$40,$03
.byt $40,$01,$43,$01,$41,$03,$40,$03
.byt $43,$01,$41,$01,$40,$03,$43,$03
.byt $41,$03,$43,$03,$43,$01,$46,$01
.byt $45,$03,$43,$03,$46,$01,$45,$01
.byt $43,$03,$46,$03,$45,$03,$43,$01
.byt $48,$01,$49,$01,$48,$01,$46,$01
.byt $45,$01,$46,$01,$45,$01,$43,$01
.byt $41,$01,$43,$01,$41,$01,$40,$01
.byt $3d,$01,$39,$01,$3b,$01,$3d,$ff

ptn0d =*
.byt $01,$3e,$01,$39,$01,$35,$01,$39
.byt $01,$3e,$01,$39,$01,$35,$01,$39
.byt $03,$3e,$01,$41,$01,$40,$03,$40
.byt $01,$3d,$01,$3e,$01,$40,$01,$3d
.byt $01,$39,$01,$3d,$01,$40,$01,$3d
.byt $01,$39,$01,$3d,$03,$40,$01,$43
.byt $01,$41,$03,$41,$01,$3e,$01,$40
.byt $01,$41,$01,$3e,$01,$39,$01,$3e
.byt $01,$41,$01,$3e,$01,$39,$01,$3e
.byt $03,$41,$01,$45,$01,$43,$03,$43
.byt $01,$40,$01,$41,$01,$43,$01,$40
.byt $01,$3d,$01,$40,$01,$43,$01,$40
.byt $01,$3d,$01,$40,$01,$46,$01,$43
.byt $01,$45,$01,$46,$01,$44,$01,$43
.byt $01,$40,$01,$3d,$ff

ptn0f =*
.byt $01,$3e,$01
.byt $39,$01,$35,$01,$39,$01,$3e,$01
.byt $39,$01,$35,$01,$39,$01,$3e,$01
.byt $39,$01,$35,$01,$39,$01,$3e,$01
.byt $39,$01,$35,$01,$39,$01,$3e,$01
.byt $3a,$01,$37,$01,$3a,$01,$3e,$01
.byt $3a,$01,$37,$01,$3a,$01,$3e,$01
.byt $3a,$01,$37,$01,$3a,$01,$3e,$01
.byt $3a,$01,$37,$01,$3a,$01,$40,$01
.byt $3d,$01,$39,$01,$3d,$01,$40,$01
.byt $3d,$01,$39,$01,$3d,$01,$40,$01
.byt $3d,$01,$39,$01,$3d,$01,$40,$01
.byt $3d,$01,$39,$01,$3d,$01,$41,$01
.byt $3e,$01,$39,$01,$3e,$01,$41,$01
.byt $3e,$01,$39,$01,$3e,$01,$41,$01
.byt $3e,$01,$39,$01,$3e,$01,$41,$01
.byt $3e,$01,$39,$01,$3e,$01,$43,$01
.byt $3e,$01,$3a,$01,$3e,$01,$43,$01
.byt $3e,$01,$3a,$01,$3e,$01,$43,$01
.byt $3e,$01,$3a,$01,$3e,$01,$43,$01
.byt $3e,$01,$3a,$01,$3e,$01,$43,$01
.byt $3f,$01,$3c,$01,$3f,$01,$43,$01
.byt $3f,$01,$3c,$01,$3f,$01,$43,$01
.byt $3f,$01,$3c,$01,$3f,$01,$43,$01
.byt $3f,$01,$3c,$01,$3f,$01,$45,$01
.byt $42,$01,$3c,$01,$42,$01,$45,$01
.byt $42,$01,$3c,$01,$42,$01,$48,$01
.byt $45,$01,$42,$01,$45,$01,$4b,$01
.byt $48,$01,$45,$01,$48,$01,$4b,$01
.byt $4a,$01,$48,$01,$4a,$01,$4b,$01
.byt $4a,$01,$48,$01,$4a,$01,$4b,$01
.byt $4a,$01,$48,$01,$4a,$01,$4c,$01
.byt $4e,$03,$4f,$ff

ptn11 =*
.byt $bf,$06,$56,$1f,$57,$1f,$56,$1f
.byt $5b,$1f,$56,$1f,$57,$1f,$56,$1f
.byt $4f,$ff

ptn12 =*
.byt $bf,$0c,$68,$7f,$7f,$7f,$7f,$7f
.byt $7f,$7f,$ff

ptn13 =*
.byt $bf,$08,$13,$3f,$13,$3f,$13,$3f
.byt $13,$3f,$13,$3f,$13,$3f,$13,$1f
.byt $13,$ff

ptn14 =*
.byt $97,$09,$2e,$03,$2e,$1b,$32,$03
.byt $32,$1b,$31,$03,$31,$1f,$34,$43
.byt $17,$32,$03,$32,$1b,$35,$03,$35
.byt $1b,$34,$03,$34,$0f,$37,$8f,$0a
.byt $37,$43,$ff

ptn15 =*
.byt $97,$09,$2b,$03,$2b,$1b,$2e,$03
.byt $2e,$1b,$2d,$03,$2d,$1f,$30,$43
.byt $17,$2e,$03,$2e,$1b,$32,$03,$32
.byt $1b,$31,$03,$31,$0f,$34,$8f,$0a
.byt $34,$43,$ff

ptn16 =*
.byt $0f,$1f,$0f,$1f,$0f,$1f,$0f,$1f
.byt $0f,$1f,$0f,$1f,$0f,$1f,$0f,$1f
.byt $0f,$1f,$0f,$1f,$0f,$1f,$0f,$1f
.byt $0f,$1f,$0f,$1f,$0f,$1f,$0f,$1f
.byt $ff

ptn17 =*
.byt $97,$09,$33,$03,$33,$1b,$37,$03
.byt $37,$1b,$36,$03,$36,$1f,$39,$43
.byt $17,$37,$03,$37,$1b,$3a,$03,$3a
.byt $1b,$39,$03,$39,$2f,$3c,$21,$3c
.byt $21,$3d,$21,$3e,$21,$3f,$21,$40
.byt $21,$41,$21,$42,$21,$43,$21,$44
.byt $01,$45,$ff

ptn18 =*
.byt $97,$09,$30,$03,$30,$1b,$33,$03
.byt $33,$1b,$32,$03,$32,$1f,$36,$43
.byt $17,$33,$03,$33,$1b,$37,$03,$37
.byt $1b,$36,$03,$36,$2f,$39,$21,$39
.byt $21,$3a,$21,$3b,$21,$3c,$21,$3d
.byt $21,$3e,$21,$3f,$21,$40,$21,$41
.byt $01,$42,$ff

ptn19 =*
.byt $0f,$1a,$0f,$1a,$0f,$1a,$0f,$1a
.byt $0f,$1a,$0f,$1a,$0f,$1a,$0f,$1a
.byt $0f,$1a,$0f,$1a,$0f,$1a,$0f,$1a
.byt $0f,$1a,$0f,$1a,$0f,$1a,$0f,$1a
.byt $ff

ptn1a =*
.byt $1f,$46,$bf,$0a,$46,$7f,$7f,$ff

ptn1b =*
.byt $1f,$43,$bf,$0a,$43,$7f,$ff

ptn1c =*
.byt $83,$02,$13,$03,$13,$03,$1e,$03
.byt $1f,$03,$13,$03,$13,$03,$1e,$03
.byt $1f,$03,$13,$03,$13,$03,$1e,$03
.byt $1f,$03,$13,$03,$13,$03,$1e,$03
.byt $1f,$03,$13,$03,$13,$03,$1e,$03
.byt $1f,$03,$13,$03,$13,$03,$1e,$03
.byt $1f,$03,$13,$03,$13,$03,$1e,$03
.byt $1f,$03,$13,$03,$13,$03,$1e,$03
.byt $1f,$ff

ptn29 =*
.byt $8f,$0b,$38,$4f,$ff

ptn2c =*
.byt $83,$0e,$32,$07,$32,$07,$2f,$07
.byt $2f,$03,$2b,$87,$0b,$46,$83,$0e
.byt $2c,$03,$2c,$8f,$0b,$32,$ff

ptn2d =*
.byt $43,$83,$0e,$32,$03,$32,$03,$2f
.byt $03,$2f,$03,$2c,$87,$0b,$38,$ff

ptn39 =*
.byt $83,$01
.byt $43,$01,$4f,$01,$5b,$87,$03,$2f
.byt $83,$01,$43,$01,$4f,$01,$5b,$87
.byt $03,$2f,$83,$01,$43,$01,$4f,$01
.byt $5b,$87,$03,$2f,$83,$01,$43,$01
.byt $4f,$01,$5b,$87,$03,$2f,$83,$01
.byt $43,$01,$4f,$01,$5b,$87,$03,$2f
.byt $83,$01,$43,$01,$4f,$01,$5b,$87
.byt $03,$2f

ptn01 =*
.byt $83,$01,$43,$01,$4f,$01,$5b,$87
.byt $03,$2f,$83,$01,$43,$01,$4f,$01
.byt $5b,$87,$03,$2f,$ff

ptn02 =*
.byt $83,$02,$13,$03,$13,$03,$1f,$03
.byt $1f,$03,$13,$03,$13,$03,$1f,$03
.byt $1f,$ff

ptn1d =*
.byt $03,$15,$03,$15,$03,$1f,$03,$21
.byt $03,$15,$03,$15,$03,$1f,$03,$21
.byt $ff

ptn1e =*
.byt $03,$1a,$03,$1a,$03,$1c,$03,$1c
.byt $03,$1d,$03,$1d,$03,$1e,$03,$1e
.byt $ff

ptn1f =*
.byt $03,$1a,$03,$1a,$03,$24,$03,$26
.byt $03,$13,$03,$13,$07,$1f,$ff

ptn04 =*
.byt $03,$18,$03,$18,$03,$24,$03,$24
.byt $03,$18,$03,$18,$03,$24,$03,$24
.byt $03,$20,$03,$20,$03,$2c,$03,$2c
.byt $03,$20,$03,$20,$03,$2c,$03,$2c
.byt $ff

ptn20 =*
.byt $03,$19,$03,$19,$03
.byt $25,$03,$25,$03,$19,$03,$19,$03
.byt $25,$03,$25,$03,$21,$03,$21,$03
.byt $2d,$03,$2d,$03,$21,$03,$21,$03
.byt $2d,$03,$2d,$ff

ptn06 =*
.byt $03,$1a,$03,$1a
.byt $03,$26,$03,$26,$03,$1a,$03,$1a
.byt $03,$26,$03,$26,$03,$15,$03,$15
.byt $03,$21,$03,$21,$03,$15,$03,$15
.byt $03,$21,$03,$21,$03,$18,$03,$18
.byt $03,$24,$03,$24,$03,$18,$03,$18
.byt $03,$24,$03,$24,$03,$1f,$03,$1f
.byt $03,$2b,$03,$2b,$03,$1f,$03,$1f
.byt $03,$2b,$03,$2b,$03,$1a,$03,$1a
.byt $03,$26,$03,$26,$03,$1a,$03,$1a
.byt $03,$26,$03,$26,$03,$15,$03,$15
.byt $03,$21,$03,$21,$03,$15,$03,$15
.byt $03,$21,$03,$21,$03,$18,$03,$18
.byt $03,$24,$03,$24,$03,$18,$03,$18
.byt $03,$24,$03,$24,$03,$1c,$03,$1c
.byt $03,$28,$03,$28,$03,$1c,$03,$1c
.byt $03,$28,$03,$28

ptn3b =*
.byt $83,$04,$36,$07
.byt $36,$07,$37,$07,$36,$03,$33,$07
.byt $32,$57,$ff

ptn08 =*
.byt $83,$02,$1b,$03,$1b,$03,$27,$03
.byt $27,$03,$1b,$03,$1b,$03,$27,$03
.byt $27,$ff

ptn21 =*
.byt $03,$1c,$03,$1c,$03,$28,$03,$28
.byt $03,$1c,$03,$1c,$03,$28,$03,$28
.byt $ff

ptn22 =*
.byt $03,$1d,$03,$1d,$03,$29,$03,$29
.byt $03,$1d,$03,$1d,$03,$29,$03,$29
.byt $ff

ptn23 =*
.byt $03,$18,$03,$18,$03,$24,$03,$24
.byt $03,$18,$03,$18,$03,$24,$03,$24
.byt $ff

ptn24 =*
.byt $03,$1e,$03,$1e,$03,$2a,$03,$2a
.byt $03,$1e,$03,$1e,$03,$2a,$03,$2a
.byt $ff

ptn25 =*
.byt $83,$05,$26,$01,$4a,$01,$34,$03
.byt $29,$03,$4c,$03,$4a,$03,$31,$03
.byt $4a,$03,$24,$03,$22,$01,$46,$01
.byt $30,$03,$25,$03,$48,$03,$46,$03
.byt $2d,$03,$46,$03,$24,$ff

ptn0b =*
.byt $83,$02,$1a,$03,$1a,$03,$26,$03
.byt $26,$03,$1a,$03,$1a,$03,$26,$03
.byt $26,$ff

ptn0c =*
.byt $03,$13,$03,$13,$03,$1d,$03,$1f
.byt $03,$13,$03,$13,$03,$1d,$03,$1f
.byt $ff

ptn26 =*
.byt $87,$02,$1a,$87,$03,$2f,$83,$02
.byt $26,$03,$26,$87,$03,$2f,$ff

ptn10 =*
.byt $07,$1a,$4f,$47,$ff

ptn0e =*
.byt $03,$1f,$03,$1f,$03,$24,$03,$26
.byt $07,$13,$47,$ff

ptn30 =*
.byt $bf,$0f,$32,$0f,$32,$8f,$90,$30
.byt $3f,$32,$13,$32,$03,$32,$03,$35
.byt $03,$37,$3f,$37,$0f,$37,$8f,$90
.byt $30,$3f,$32,$13,$32,$03,$2d,$03
.byt $30,$03,$32,$ff

ptn31 =*
.byt $0f,$32
.byt $af,$90,$35,$0f,$37,$a7,$99,$37
.byt $07,$35,$3f,$32,$13,$32,$03,$32
.byt $a3,$e8,$35,$03,$37,$0f,$35,$af
.byt $90,$37,$0f,$37,$a7,$99,$37,$07
.byt $35,$3f,$32,$13,$32,$03,$2d,$a3
.byt $e8,$30,$03,$32,$ff

ptn32 =*
.byt $07,$32,$03
.byt $39,$13,$3c,$a7,$9a,$37,$a7,$9b
.byt $38,$07,$37,$03,$35,$03,$32,$03
.byt $39,$1b,$3c,$a7,$9a,$37,$a7,$9b
.byt $38,$07,$37,$03,$35,$03,$32,$03
.byt $39,$03,$3c,$03,$3e,$03,$3c,$07
.byt $3e,$03,$3c,$03,$39,$a7,$9a,$37
.byt $a7,$9b,$38,$07,$37,$03,$35,$03
.byt $32,$af,$90,$3c,$1f,$3e,$43,$03
.byt $3e,$03,$3c,$03,$3e,$ff

ptn33 =*
.byt $03,$3e
.byt $03,$3e,$a3,$e8,$3c,$03,$3e,$03
.byt $3e,$03,$3e,$a3,$e8,$3c,$03,$3e
.byt $03,$3e,$03,$3e,$a3,$e8,$3c,$03
.byt $3e,$03,$3e,$03,$3e,$a3,$e8,$3c
.byt $03,$3e,$af,$91,$43,$1f,$41,$43
.byt $03,$3e,$03,$41,$03,$43,$03,$43
.byt $03,$43,$a3,$e8,$41,$03,$43,$03
.byt $43,$03,$43,$a3,$e8,$41,$03,$43
.byt $03,$45,$03,$48,$a3,$fd,$45,$03
.byt $44,$01,$43,$01,$41,$03,$3e,$03
.byt $3c,$03,$3e,$2f,$3e,$bf,$98,$3e
.byt $43,$03,$3e,$03,$3c,$03,$3e,$ff

ptn34 =*
.byt $03,$4a,$03,$4a,$a3,$f8,$48,$03
.byt $4a,$03,$4a,$03,$4a,$a3,$f8,$48
.byt $03,$4a,$ff

ptn35 =*
.byt $01,$51,$01,$54,$01
.byt $51,$01,$54,$01,$51,$01,$54,$01
.byt $51,$01,$54,$01,$51,$01,$54,$01
.byt $51,$01,$54,$01,$51,$01,$54,$01
.byt $51,$01,$54,$ff

ptn36 =*
.byt $01,$50,$01,$4f
.byt $01,$4d,$01,$4a,$01,$4f,$01,$4d
.byt $01,$4a,$01,$48,$01,$4a,$01,$48
.byt $01,$45,$01,$43,$01,$44,$01,$43
.byt $01,$41,$01,$3e,$01,$43,$01,$41
.byt $01,$3e,$01,$3c,$01,$3e,$01,$3c
.byt $01,$39,$01,$37,$01,$38,$01,$37
.byt $01,$35,$01,$32,$01,$37,$01,$35
.byt $01,$32,$01,$30,$ff

ptn37 =*
.byt $5f,$5f,$5f
.byt $47,$83,$0e,$32,$07,$32,$07,$2f
.byt $03,$2f,$07,$2f,$97,$0b,$3a,$5f
.byt $5f,$47,$8b,$0e,$32,$03,$32,$03
.byt $2f,$03,$2f,$47,$97,$0b,$3a,$5f
.byt $5f,$47,$83,$0e,$2f,$0b,$2f,$03
.byt $2f,$03,$2f,$87,$0b,$30,$17,$3a
.byt $5f,$8b,$0e,$32,$0b,$32,$0b,$2f
.byt $0b,$2f,$07,$2c,$07,$2c,$ff

ptn38 =*
.byt $87
.byt $0b,$34,$17,$3a,$5f,$5f,$84,$0e
.byt $32,$04,$32,$05,$32,$04,$2f,$04
.byt $2f,$05,$2f,$47,$97,$0b,$3a,$5f
.byt $5f,$84,$0e,$32,$04,$32,$05,$32
.byt $04,$2f,$04,$2f,$05,$2f,$ff

ptn2f =*
.byt $03,$1a,$03,$1a,$03
.byt $24,$03,$26,$03,$1a,$03,$1a,$03
.byt $18,$03,$19,$03,$1a,$03,$1a,$03
.byt $24,$03,$26,$03,$1a,$03,$1a,$03
.byt $18,$03,$19,$03,$18,$03,$18,$03
.byt $22,$03,$24,$03,$18,$03,$18,$03
.byt $16,$03,$17,$03,$18,$03,$18,$03
.byt $22,$03,$24,$03,$18,$03,$18,$03
.byt $16,$03,$17,$03,$13,$03,$13,$03
.byt $1d,$03,$1f,$03,$13,$03,$13,$03
.byt $1d,$03,$1e,$03,$13,$03,$13,$03
.byt $1d,$03,$1f,$03,$13,$03,$13,$03
.byt $1d,$03,$1e,$03,$1a,$03,$1a,$03
.byt $24,$03,$26,$03,$1a,$03,$1a,$03
.byt $18,$03,$19,$03,$1a,$03,$1a,$03
.byt $24,$03,$26,$03,$1a,$03,$1a,$03
.byt $18,$03,$19,$ff


;====================================
;instruments
;====================================

instr =*
.byt $80,$09,$41,$48,$60,$03,$81,$00
.byt $00,$08,$81,$02,$08,$00,$00,$01
.byt $a0,$02,$41,$09,$80,$00,$00,$00
.byt $00,$02,$81,$09,$09,$00,$00,$05
.byt $00,$08,$41,$08,$50,$02,$00,$04
.byt $00,$01,$41,$3f,$c0,$02,$00,$00
.byt $00,$08,$41,$04,$40,$02,$00,$00
.byt $00,$08,$41,$09,$00,$02,$00,$00
.byt $00,$09,$41,$09,$70,$02,$5f,$04
.byt $00,$09,$41,$4a,$69,$02,$81,$00
.byt $00,$09,$41,$40,$6f,$00,$81,$02
.byt $80,$07,$81,$0a,$0a,$00,$00,$01
.byt $00,$09,$41,$3f,$ff,$01,$e7,$02
.byt $00,$08,$41,$90,$f0,$01,$e8,$02
.byt $00,$08,$41,$06,$0a,$00,$00,$01
.byt $00,$09,$41,$19,$70,$02,$a8,$00
.byt $00,$02,$41,$09,$90,$02,$00,$00
.byt $00,$00,$11,$0a,$fa,$00,$00,$05
.byt $00,$08,$41,$37,$40,$02,$00,$00
.byt $00,$08,$11,$07,$70,$02,$00,$00

.end


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