an
production
M64 features:
The following is recommended:
To get most out of this program:
Midiloader usage:
Type in the midiloader from the listings below. You have to choose the correct
one for your MIDI interface. Save the program (so you won't have to retype
everything if something goes wrong). Run it. The program will tell if it was
typed in correctly.
If everything is all right the program will wait for you to press return on a
SYS49152 line. Do so.
The midiloader is now waiting for you to transfer any file from the M64
package with an .MSX extension. Start sending M64.MSX from
your remote computer or synthesizer. The border flashes during transfer.
If the file was correctly transferred just save it as you would do with any
other BASIC program.
Below are three listings of the midiloader program. Choose the correct one.
If you have absolutely no idea what type of interface you have you can type
in the following program that will identify your MIDI interface.
Sound programs are written, compiled and run in M64. Another
program, The Performance Editor (under construction) will read
precompiled sounds and store them in banks.
Banks contain several sounds and the user can change sound via MIDI from a
sequencer or synthesizer.
First of all when you press keys you insert letters into the
text instead of overwriting like CBM BASIC. Some keys have different meanings
in the editor. Those are:
Pull down the File menu and you will see what it contains.
The letters to the right tells you that holding the Commodore key and
pressing that letter is equivalent to accessing the menu bar.
M64 will autodetect which interface you have but
in case it fails (for some strange reason) you can change it manually here.
Note that this information is just stored in memory and will be forgotten
each time you restart the editor. If you have problems with the autodetect,
contact the author.
The status line also shows the current row and column of the cursor.
To edit filetype press 'P' for PRG, 'S' for SEQ and 'U' for USR file.
To edit device, drive and filename just move cursor with cursor left/right
and edit as usual.
Pressing return while editing device or drive will reread the directory.
Press return while editing filename or filetype when finished.
Pressing STOP cancels the requester.
To load a file from Commodore device select File/Open from the menu
or press <commodore-o>. A file requester will appear. Refer to
the File Requester section for instructions how to use it.
To load a file from MIDI, select File/Open as MIDI from the menu or
press <commodore-d>. A window will appear, telling you to start
sending the file. Note that the sender's MIDI OUT must be connected to
C64 MIDI IN in order to make this work. Send the file from the sequencer,
synthesizer or whatever you are using. If all is well the border will
flash and the file will be loaded.
Press <commodore-m> or select "Edit/MIDI channel" from the menu
and make sure that M64 is configured to receive on the correct MIDI channel.
Press <commodore-i> or select "Edit/Interface" from the menu and
make sure that your interface has been selected.
When the ASL code is running M64 is ready to receive MIDI messages.
Pressing keys on your master keyboard should produce sound. The Midi led
indicator will be lit if M64 receives MIDI messages on any channel.
M64 will ignore all messages except those sent on the previously selected
MIDI channel.
The time usage indicator shows the CPU-usage. If time usage exceeds 100%
the sound will slow down (that is, always-routines will not run
at the correct frequency) and the word "OVERFLOW" will appear.
Pressing space will toggle screen blanking on/off. Screen blanking reduces
noise. When the screen is blanked, a red screen color will indicate overflow.
A C128 running in C64 mode will operate at 2MHz when the screen is blanked!
An ASL program consists of 6 main sections. These are called:
M64 runs ASL code as follows.
First, the globalInit routine is executed followed by one call to
localInit for each channel of the SID.
Now globalAlways and localAlways (for each channel) are
executed frequently (50Hz if not specified).
If a keydown message is sent from the master via MIDI then localKeyDown
for the unused channel is executed. If a keyup message is sent then
localKeyUp for the allocated channel is executed.
As we will see later, it is possible to specify exactly which code that
should be executed for each channel.
To sum up, the init-routines are ideal for setting up. Always-routines
should be used for handling effects like vibrato, slides and other things
that need to update frequently. Keydown-routines should contain code needed
to start the sound. Keyup-routines should contain code that stops the sound
or fades it. Local-routines affect the channel specific things while
global-routines affect everything that is not (the filter for example
affects the whole SID chip, not just a channel and is therefore something
that should be handled by globalInit and globalAlways).
A constant declaration looks like this:
This will assign the value 50 to the identifier "time". It is possible to
declare several constants on one line like this:
After a constant declaration it is possible to use that identifier in
expressions. An example:
Here are some examples of a valid expressions (if TIME previously has
been declared as a constant):
In this example "foo" is a label. Here is another example of valid labels:
Here "foo", "q" and "yeah" are valid labels.
The ASL compiler needs to know where certain routines are located
and therefore there are some labels that just has to exist in every
ASL program. We get back to those labels later.
There are two types of registers, local and global.
In order to use registers they must be declared. Some registers are
predeclared.
These are the predeclared global registers:
Registers starting with 'SIDG' are registers that will affect the SID chip.
Registers starting with 'MIDG' contain values of the controllers that has been
sent via MIDI from the master synthesizer or computer.
These are the predeclared local registers:
The registers starting with 'SID' are registers that will affect the SID chip.
Note that all SID registers are 16 bit, even the "boolean" ones! This means
that all registers are treated equally and you don't need to
know how many bits each register oThe registers starting with 'SID' are registers that will affect the SID chip.
Note that all SID registers are 16 bit, even the "boolean" ones! This means
that all registers are treated equally and you don't need to
know how many bits each register occupy. 65535 is always maximum and 0 is
always minimum.
Registers starting with 'MID' contain values that has been sent via MIDI
from the master synthesizer or computer.
Let's say that the routine localAlways2 displays the PulseCounter, then "$07D1"
will be shown in the run window (2001 hexadecimal, that is).
Take a look at the following code:
The movei instruction moves a constant to a register. Since it is
executed in the localInit routine the second argument is assumed to be a
local register.
If we replace PulseCounter with a global register, then the program will not
work as expected. NOTE: The current version of the ASL compiler will not
report this type of error. To read and write to global registers from
local routines you should use the glob2reg and reg2glob
instructions.
Another example:
Here, the move instruction requires two global registers as arguments
since this is a global routine. Any local registers as arguments would yield
unpredictable results.
There are three types of arguments: registers (reg), expressions (expr) and
labels (lbl).
Below is a list of all instructions and their arguments.
Example:
This program is the default ASL program that will show up in the editor when you
start M64. It will produce a simple sawtooth sound that will sound like the
bass in Spelunker or the melody in Burnin' Rubber. The pitch wheel can be
used to change the pitch of the sound two semitones up or down.
The program runs like this: First of all it will initialize. The globalInit
routine will set volume to maximum and localInit will set attack, decay and
release time. It will also set sustain level and enable the sawtooth waveform.
The values for attack, decay, sustain and release are deliberately written in
hexadecimal form since only the first nibble really matters (if you don't know
what this means, just forget it, it's not important).
When keys are pressed the localKeyDown routine will copy the correct frequency
to the SID chip. The SID gate will also be set to start the sound.
When keys are released the localKeyUp routine will clear the SID gate so that
the release of the sound starts.
As the sound plays, the globalAlways routine will do nothing but the localAlways
routine will make the pitchbend. This is done by first copying the global
register MIDGpitch to a local one (pitch is declared just above the routine).
Then the special instruction 'pitchbendi' does all the magic and updates local
register MIDfreq with the correct frequency value. The last thing to do is to
copy the frequency value to the SID chip.
To change the character of the sound we change the waveform to pulse instead
of sawtooth.
To make the sound constantly change we let the pulse width wary over time.
To do so we place a counter in a register that will constantly count up and
then use the 'triangle' or 'sinus' instruction to get the actual values to
put into the SIDpulseWidth register. The program now look like this (all
changes in italics).
Note that there are one 'pulseCount' register for each channel. All three
are syncronized so if you press three keys at the same time you can hear
that the pulse width is the same for all three channels. We will now make
them different from each other. We do so by making three different
localInit routines, one for each channel! Since just the pulseCount will
be different we will reuse our code. The localInit routine now looks like
this:
Note that the original localInit label has been removed. That is because
otherwise it would override the other localInit labels.
Ok, let's look at another example. This time it's a monophonic sound that
uses all three channels for one sound. This sound uses the syncronize feature
of the SID chip to make an odd sound. We will enable sync on channel 1 which
will syncronize the fundamental frequency of channel 1 with the fundamental
frequency of channel 3, producing "hard sync" effects. We modulate the
frequency of channel 1 with the pitch wheel (the resolution of the pitch wheel
is much higher that the modulation wheel). Channel 3's frequency will
be the frequency of the key we press. Here is the program:
To make monophonic sounds we simply added a line in the globalInit that says
'set MIDGmonophonic'.
We can try the ring modulation by changing the waveform to triangle and setting
SIDmodulate instead of SIDsync. localInit1 will look like this:
You might just feel like Jeff Minter while playing around with this sound.
is MUCH better than:
This can be done in a more efficient way:
The following code will demonstrate the typical use.
M64 stops completely when I run my script!
Probably because you forgot to end some routine with the 'end' instruction.
It can also be an 'execute' instruction that expects some files to be loaded
before starting M64.
I try to modulate pulse width with the modulation wheel but I can't get
it to work!
The SIDGmodWheel is a global register. Use glob2reg in local routines to
copy it to a local register (like SIDpulseWidth).
Nothing happens when I tap on the MIDI keyboard!
Make sure that MIDI OUT on the keyboard or sequencer is connected to
MIDI IN on the c64 MIDI interface.
Check that the keyboard is sending on the correct channel. The receive channel
can be changed by pressing <commodore-m> or selecting "Edit/MIDI channel"
from the menu (the default is channel 1).
Also, check that the correct MIDI interface is selected. Press
<commodore-i> in the editor or select Edit/Interface in the menu.
When running, I get OVERFLOW whenever I press a key!
Your sound is too complex to be updated at the current frequency. Use
the 'settimeri' command to increase the update interval time.
Registers suddenly get strange values!
Make sure that there are no references to global registers in local routines
(except in 'glob2reg' and 'reg2glob' instructions). Also make sure that there
are no local registers at all in global routines.
Now, at the BASIC prompt, type SYS2061 and press return.
You will hopefully be back in M64 with your previous ASL program.
If M64 didn't start then repeat the Run/Stop-Restore procedure and instead of
starting it with SYS2061, you reload M64 from your storage device and run it.
If your ASL program has not been destroyed M64 will let you continue editing it.
Send bug reports directly to me, the author, at the following address:
bjonte@hem2.passagen.se.
Thanks to
M64 was developed using the following equipment.
Hardware:
Software:
All contents copyright © 1997 AnyWare Designs. All rights reserved.
URL: http://www.algonet.se/~bjonte/AnyWare/M64/M64.html
1. Introduction
If you think that your c64 sounds fantastic and you make music with
sequencers and synthesizers you will probably want to use your c64 as
a synth module. M64 will transform your c64 into a synth module.
2. Requirements
The following is required to use M64:
3. Installation
3.1 M64 files
The M64 package contains the following files:
3.2 MIDI transfer
To install M64 you need to transfer all executable files to a storage device
on your c64. This manual contains a midiloader that will use your
MIDI interface to receive executable files.
3.3 Interface identifier
5 AD=56832
10 IFPEEK(AD+2)<>255THEN50
20 IFPEEK(AD+6)<>255THEN60
30 IFPEEK(AD+8)<>255THEN70
40 PRINT"NO INTERFACE CONNECTED":END
50 PRINT"SEQUENTIAL INTERFACE":END
60 PRINT"DATEL/SEIL/JMS INTERFACE":END
70 PRINT"PASSPORT INTERFACE"
3.4 Midiloader for PASSPORT-compatible interface (Sentech)
1 AD=49150:J=0:T=0:L=30
5 RT=0:READA$:IFA$=""THEN100
10 FORI=1TOLEN(A$)/2
15 GOSUB200:B=A:GOSUB200:A=B*16+A
25 POKEAD+J,A:J=J+1:RT=RT+A:NEXT:T=T+RT
27 READA:IFRT<>ATHENPRINT"DATA ERROR IN LINE "L:END
29 L=L+1:GOTO5
30 DATA "AAMAHIKJADCAKGMA",874
31 DATA "KJBFCAKGMAKJABKC",912
32 DATA "AIIFCNIGCOKNCANA",779
33 DATA "EIKJAAINCANAKCAI",792
34 DATA "CAEOMANNKKMANAPG",1339
35 DATA "MKBAPFKAAAOOCANA",1101
36 DATA "CAEOMADAEDAKAKAK",447
37 DATA "AKINECMACAEOMADA",759
38 DATA "CPCJAPAJAAJBCNOG",532
39 DATA "CNNAACOGCOEMCLMA",842
40 DATA "KJHPINAANMKNABNM",1051
41 DATA "BABEKNAINOINGDMA",871
42 DATA "CJHANAAKKJAACJAB",582
43 DATA "PAOLKNAJNOGAGIGI",1183
44 DATA "KCAACAJKMAEMHPMA",935
45 DATA "MJPHNAPEKCAICAJK",1256
46 DATA "MAKFCNKGCOIFKOIG",1055
47 DATA "KPGIINCANAFIGAEF",913
48 DATA "FCFCEPFCCBANAAEP",450
49 DATA "ELCBANAALNINMAPA",883
50 DATA "AGCANCPPOINAPFGA",1284
51 DATA "INAINOGAAIAAABAA",476
52 DATA "FAAAEAHPPA",511
53 DATA ""
100 IFT<>19827THENPRINT"DATA ERROR, CHECK PROGRAM":END
110 PRINTCHR$(147)"DATA OK, PRESS RETURN!":PRINT:PRINT:PRINT"SYS49152"CHR$(19)
120 END
200 A=ASC(LEFT$(A$,1))-65:A$=RIGHT$(A$,LEN(A$)-1):RETURN
3.5 Midiloader for DATEL-compatible interface (Seil/JMS)
1 AD=49150:J=0:T=0:L=30
5 RT=0:READA$:IFA$=""THEN100
10 FORI=1TOLEN(A$)/2
15 GOSUB200:B=A:GOSUB200:A=B*16+A
25 POKEAD+J,A:J=J+1:RT=RT+A:NEXT:T=T+RT
27 READA:IFRT<>ATHENPRINT"DATA ERROR IN LINE "L:END
29 L=L+1:GOTO5
30 DATA "AAMAHIKJADCAKGMA",874
31 DATA "KJBGCAKGMAKJABKC",913
32 DATA "AIIFCNIGCOKNCANA",779
33 DATA "EIKJAAINCANAKCAI",792
34 DATA "CAEOMANNKKMANAPG",1339
35 DATA "MKBAPFKAAAOOCANA",1101
36 DATA "CAEOMADAEDAKAKAK",447
37 DATA "AKINECMACAEOMADA",759
38 DATA "CPCJAPAJAAJBCNOG",532
39 DATA "CNNAACOGCOEMCLMA",842
40 DATA "KJHPINAANMKNABNM",1051
41 DATA "BABEKNAGNOINGDMA",869
42 DATA "CJHANAAKKJAACJAB",582
43 DATA "PAOLKNAHNOGAGIGI",1181
44 DATA "KCAACAJKMAEMHPMA",935
45 DATA "MJPHNAPEKCAICAJK",1256
46 DATA "MAKFCNKGCOIFKOIG",1055
47 DATA "KPGIINCANAFIGAEF",913
48 DATA "FCFCEPFCCBANAAEP",450
49 DATA "ELCBANAALNINMAPA",883
50 DATA "AGCANCPPOINAPFGA",1284
51 DATA "INAENOGAAIAAABAA",472
52 DATA "FAAAEAHPPA",511
53 DATA ""
100 IFT<>19820THENPRINT"DATA ERROR, CHECK PROGRAM":END
110 PRINTCHR$(147)"DATA OK, PRESS RETURN!":PRINT:PRINT:PRINT"SYS49152"CHR$(19)
120 END
200 A=ASC(LEFT$(A$,1))-65:A$=RIGHT$(A$,LEN(A$)-1):RETURN
3.6 Midiloader for SEQUENTIAL-compatible interface
1 AD=49150:J=0:T=0:L=30
5 RT=0:READA$:IFA$=""THEN100
10 FORI=1TOLEN(A$)/2
15 GOSUB200:B=A:GOSUB200:A=B*16+A
25 POKEAD+J,A:J=J+1:RT=RT+A:NEXT:T=T+RT
27 READA:IFRT<>ATHENPRINT"DATA ERROR IN LINE "L:END
29 L=L+1:GOTO5
30 DATA "AAMAHIKJADCAKGMA",874
31 DATA "KJBFCAKGMAKJABKC",912
32 DATA "AIIFCNIGCOKNCANA",779
33 DATA "EIKJAAINCANAKCAI",792
34 DATA "CAEOMANNKKMANAPG",1339
35 DATA "MKBAPFKAAAOOCANA",1101
36 DATA "CAEOMADAEDAKAKAK",447
37 DATA "AKINECMACAEOMADA",759
38 DATA "CPCJAPAJAAJBCNOG",532
39 DATA "CNNAACOGCOEMCLMA",842
40 DATA "KJHPINAANMKNABNM",1051
41 DATA "BABEKNACNOINGDMA",865
42 DATA "CJHANAAKKJAACJAB",582
43 DATA "PAOLKNADNOGAGIGI",1177
44 DATA "KCAACAJKMAEMHPMA",935
45 DATA "MJPHNAPEKCAICAJK",1256
46 DATA "MAKFCNKGCOIFKOIG",1055
47 DATA "KPGIINCANAFIGAEF",913
48 DATA "FCFCEPFCCBANAAEP",450
49 DATA "ELCBANAALNINMAPA",883
50 DATA "AGCANCPPOINAPFGA",1284
51 DATA "INAANOGAAIAAABAA",468
52 DATA "FAAAEAHPPA",511
53 DATA ""
100 IFT<>19807THENPRINT"DATA ERROR, CHECK PROGRAM":END
110 PRINTCHR$(147)"DATA OK, PRESS RETURN!":PRINT:PRINT:PRINT"SYS49152"CHR$(19)
120 END
200 A=ASC(LEFT$(A$,1))-65:A$=RIGHT$(A$,LEN(A$)-1):RETURN
4. Concepts
Sounds are created by writing programs that can read midi controllers,
act on keypresses and control the sound-chip. Programs has to be compiled
before they can be "run" for speed reasons. When a sound program is running
the C64 will act like a synth module to the outside world.
5. The Editor
When you start M64 you will see the edit screen. This is where you write,
compile, run, load and save ASL programs.
The display looks like this:
5.1 Editing
The editing is somewhat different from what you are used to if you use
CBM BASIC.
5.2 The Menubar
The top row on the display is the menu bar. Use your mouse or joystick
to access it (just like GEOS). Don't worry, everything can be controlled
with the keyboard (you just have to learn all the keycodes).
5.3 The File menu
New
The "New" command can also be invoked by pressing CLR on the keyboard.
The current ASL program will be erased and leave an empty one.
Open
The "Open" command will request for a file to open.
The current ASL program will be erased and the selected one will be read.
Open as MIDI
The "Open as MIDI" command will wait for a MIDI SYSEX file to be sent.
This way you can read programs from other devices outside the c64 world.
The current ASL program will be erased and a new one will be read from MIDI.
Save
The "Save" command will rewrite the current ASL program to the current device
without asking for a filename.
If the file exists you will NOT be asked if you wish to remove that file.
Save as
The "Save as" command will request for a file to store.
The current ASL program will be stored as the selected file.
If the file exists you will be asked if you wish to remove that file.
You will NOT have to add "@:" in the filename.
Save as MIDI
The "Save as MIDI" command will immediately send the current ASL program
as MIDI SYSEX. Use "Open as MIDI" to read it back.
This way you can save programs to other devices outside the c64 world.
About
The "About" command will display version and registration information.
Quit
The "Quit" command will get you back to BASIC. As long as the ASL
program hasn't been corrupted you can rerun M64 without erasing
your work. This is pretty handy if you want to make some calculations or
scratch some files without losing your work.
5.4 The Edit menu
Mark
The "Mark" command will toggle marking mode. You have to mark text in order
to use "Cut" and "Copy".
Cut
The "Cut" command will move the marked text into the copy buffer. You might
get confused because the display will be scrolled in order to place the cursor
on the top line (for technical reasons). This little bug will hopefully be
removed in future versions.
Copy
The "Copy" command will copy the marked text into the copy buffer.
Paste
The "Paste" command will paste the copy buffer into the current ASL program
before the current line.
Delete line
The "Delete line" command will delete the current line.
Interface
The "Interface" command will let you manually select which type of MIDI
interface you use.
A dialog will open with three buttons marked "Sequential", "Datel", and
"Passport". Use mouse or joystick to select or press "S", "D" or "P".
MIDI channel
The "MIDI channel" command will let you select which MIDI channel M64 will
receive messages on.
A dialog will open with four buttons: use, cancel, up and down.
Use mouse or joystick to select or press <cursor-up>,
<cursor-down> to change channel, return to use the setting or stop
to revert to the old setting.
5.5 The ASL menu
Compile
The "Compile" command will parse the ASL program and generate ASL code
that can be executed with the "Run" command.
Run
The "Run" command will run the last successfully compiled ASL code.
5.6 The Local menu
The "Local" menu contains all default local register names. Selecting a name
will paste it into the ASL program at the current cursor position like
if you wrote it.
5.7 The Global menu
The "Global" menu contains all default global register names. Selecting a
name will paste it into the ASL program at the current cursor position like
if you wrote it.
5.8 The A-L menu
The "A-L" menu contains instruction names starting with letters from A to L.
Selecting a name will paste it into the ASL program at the current cursor
position like if you wrote it.
5.9 The L-Z menu
The "L-Z" menu contains instruction names starting with letters from L to Z.
Selecting a name will paste it into the ASL program at the current cursor
position like if you wrote it.
5.10 The status line
The status line at the bottom of the display shows the device and filename
of the current ASL program. A '*' before the filename shows that the ASL
program has been changed since it was last saved.
5.11 The error line
The error line is located just below the status line. It shows the last
error from the compiler.
6. The File Requester
When opening or writing files from devices other than MIDI, M64
provides a file requester.
6.1 Editing
The tabulator key (arrow left, remember?) cycles through editing filename,
filetype, device and drive.
6.2 Select using keyboard
Use cursor keys to move up and down in the directory. Press return
to select the highlighted file. Press STOP to cancel. Pressing 'F1'
and 'F7' will scroll up and down respectively one page. 'F2' and 'F8' can
be pressed to jump to first/last filename.
6.3 Select using mouse or joystick
Click on a filename to select it. Click on the arrow icons (at top and bottom
of file list) to scroll one page up/down. Click on the OPEN/SAVE button when
you are satisfied or CANCEL to cancel the requester.
7. Getting started
7.1 Opening a file
ASL programs can be loaded either from a standard Commodore device or
from MIDI.
7.2 Compiling
Select ASL/Compile from the menu or press F3 to compile the current ASL
program. A window will appear that will inform you about any errors
in the ASL program. When the program has been compiled press any key
(except Restore) to return to the editor. If there was an error in the
compile the cursor will be placed near the place where the error was
detected.
7.3 Configuring
Make sure that C64 MIDI IN is connected to your master synthesizer's or
computer's MIDI OUT.
7.4 Running
Select ASL/Run from the menu or press F5 to run the last compiled program.
The picture below shows the play window that M64 will open.

8. Programming Abstract SID Language
When programming ASL some understanding of how the SID chip works is
recommended. Consult your c64 user manual if necessary.

8.1 Numeric values
Numeric values can be either decimal, hexadecimal or binary.
If you have programmed 6502 assembler you will be happy because it
is the same syntax in ASL.
8.2 Constants
A constant declaration has the form:
const <identifier>=<expression>[,<identifier>=<expression>,[...]]
const TIME=50
const TIME=50, DELAY=14
const LENGTH=50
const POSTLUDE=LENGTH-5
8.3 Expressions
Expressions may contain constants, numeric values.
Possible operations are plus, minus and unary minus.
-TIME+100
TIME--$ff
%100-$100
-$1+-%0
8.4 Labels
Labels are names on lines in the ASL program. Labels are declared by
writing letters at the beginning of a line (optionally followed by a
colon). An example:
set SIDgate
foo addi 1,a
cmp a,b
bne foo
end
set SIDgate
foo addi 1,a
q: cmp a,b
bne foo
yeah
end
8.5 Registers
Registers are used to hold values. Registers are 16 bit, which means that
each register can hold values from 0 to 65535. Registers wrap around if you
try to exceed the limits (if you add 1 to a register containing 65535 the
result will be 0).
8.6 Global registers
Global registers can be declared with the global directive as follows.
global [<registername>[,<registername>[,...]]]
8.7 Local registers
Local registers can be declared with the local directive as follows.
local [<registername>[,<registername>[,...]]]
8.8 Register handling
Assume that we have written an ASL program that declares one local register,
PulseCounter, and a global register, FilterFreq. As you can see from the
diagram below, there are actually three versions of the local register, one
for each channel. Each version can hold a unique value. The diagram also shows
that there is just one version of the global register.

localInit:
movei 666, PulseCounter
end
globalAlways:
move FilterFreq, SIDGfilterFreq
end
8.9 Instructions
Instructions have the form:
<instruction> [<argument>[,<argument>[...]]]
Debug instructions:
Control instructions:
SPEED_VALUE=TIME/CLOCK_SPEED
where CLOCK_SPEED is 1022730 for American (NTSC) monitors and 985250 for
European (PAL) monitors. TIME is the interval between always-updates in seconds.
If your ASL-programs always get OVERFLOW, then increase this value.
Compare and branch instructions:
Register manipulation:
Arithmetic instructions:
Other instructions:
reg2=32767+32767*sin(reg2/65535*2*pi)
8.10 Comments
Comments are everything to the right of a semicolon just like 6502
assembler.
;This is a comment
local hello
clr hello ;This is also a comment
; end This line is a comment (no end here)
end ;but here!
8.11 Examples
Let's look at a simple ASL program example:
;
;Name: Dummy
;
;Author: Jonas Hulten
;
;Modulations:
; pitch wheel: pitch
;
const BENDERVALUE=2
globalInit:
set SIDGvolume ;full volume
end
globalAlways:
end
localInit:
movei $4000, SIDattack
movei $8000, SIDdecay
movei $D000, SIDsustain
movei $9000, SIDrelease
set SIDsaw
end
localKeyDown:
move MIDfreq,SIDfreq ;play correct frequency
set SIDgate ;start attack
end
localKeyUp:
clr SIDgate ;start release
end
local pitch
localAlways:
;pitchbend
glob2reg MIDGpitch, pitch
pitchbendi BENDERVALUE, pitch
move MIDfreq, SIDfreq
end
;
;Name: Not so Dummy
;
;Author: Jonas Hulten
;
;Modulations:
; pitch wheel: pitch
;
const BENDERVALUE=2
const PULSESPEED=200
globalInit:
set SIDGvolume ;full volume
end
globalAlways:
end
local pulseCount
localInit:
movei $4000, SIDattack
movei $8000, SIDdecay
movei $D000, SIDsustain
movei $9000, SIDrelease
set SIDpulse
clr pulseCount
end
localKeyDown:
move MIDfreq,SIDfreq ;play correct frequency
set SIDgate ;start attack
end
localKeyUp:
clr SIDgate ;start release
end
local pitch
localAlways:
;pitchbend
glob2reg MIDGpitch, pitch
pitchbendi BENDERVALUE, pitch
move MIDfreq, SIDfreq
addi PULSESPEED, pulseCount
triangle pulseCount, SIDpulseWidth
end
localInit1:
clr pulseCount
bra init
localInit2:
movei 20000, pulseCount
bra init
localInit3:
movei 40000, pulseCount
init:
movei $4000, SIDattack
movei $8000, SIDdecay
movei $D000, SIDsustain
movei $9000, SIDrelease
set SIDpulse
end
;
;Name: Monophonic sync
;
;Author: Jonas Hulten
;
;Modulations:
; modulation wheel: channel 1 frequency
;
globalInit:
set SIDGvolume ;full volume
set MIDGmonophonic
end
globalAlways:
end
localInit1:
movei $4000, SIDattack
movei $8000, SIDdecay
movei $D000, SIDsustain
movei $9000, SIDrelease
set SIDsaw
set SIDsync
end
localInit2:
localInit3:
end
localKeyDown1:
set SIDgate ;start attack
end
localKeyDown2:
end
localKeyDown3:
move MIDfreq,SIDfreq ;play correct frequency
end
localKeyUp1:
clr SIDgate ;start release
end
localKeyUp2:
localKeyUp3:
end
local mod
localAlways1:
glob2reg MIDGpitch, mod
move mod, SIDfreq
end
localAlways2:
localAlways3:
end
localInit1:
movei $4000, SIDattack
movei $8000, SIDdecay
movei $D000, SIDsustain
movei $9000, SIDrelease
set SIDtriangle
set SIDmodulate
end
8.12 Trix and Tips
There are a couple of techniques that are very useful when programming ASL.
Constants
Use constants instead of numbers so that people can adjust the sound parameters
without reading the whole code.
const VIBRATOSPEED=50
; ...
addi VIBRATOSPEED, Counter
addi 50, Counter
Limiting
The following example shows how to use the 'cmp' instruction in combination
with branch instructions to make a counter count from 0 to 4 and then stop
counting.
cmpi 4, Counter ;compare Counter with 4.
bhs noCount ;branch to noCount if Counter was
;higher or same as 4.
addi 1, Counter ;increment Counter.
noCount:
addi 1, Counter ;increment Counter
mini 4, Counter ;let Counter be the lowest of 4 and Counter
Vibrato
The following code shows how to add vibrato to a register.
const SPEED=200, AMPLITUDE=40 ;first some declarations
local Counter, SinValue
;... some code here ...
addi SPEED,Counter ;update Counter
sinus Counter, SinValue ;get sinus value (0..65535)
scalei AMPLITUDE+AMPLITUDE, SinValue ;scale down sinus value (0..80)
subi AMPLITUDE, SinValue ;change offset (-40..40)
add SinValue, SIDfreq ;add vibrato to SID frequency!
;... and some code here too ...
Pitchbend
Making pitchbend with ASL can be done without the special 'pitchbend'
instruction but that is not recommended. This instruction does more
than it's operands tell you:
const BENDERVALUE=12 ;pitchbend a full octave (12 semitones)
local pitch ;first some declarations
;... some code here ...
localAlways:
glob2reg MIDGpitch, pitch ;copy global register to local
pitchbendi BENDERVALUE, pitch
;the result is an updated MIDfreq register
move MIDfreq, SIDfreq ;so just copy it to the SID!
;... and some code here too ...
8.13 Troubleshooting
Finding errors that are not compile errors are generally hard (especially if
you are inexperienced). The most common errors when programming ASL are:
9. Bugs
M64 should be pretty bug-free.
However, if M64 suddenly jams you should hold Run/Stop and tap the Restore key.
If that didn't got you back to a BASIC prompt you have to make a soft reset
by hand (this is not possible with a standard C64 without a reset switch).
10. Future
Future versions of M64 will (hopefully) feature:
11. Registration
This program was shareware but since I haven't updated the program for half a
year I have decided to release it as freeware! Those who have registered will
get the Performance Player for free when it is released and others will have
to pay a small sum of money for it.
12. Copyright
The program M64 and this manual is copyright © 1997 AnyWare Designs.
I, the author, or anyone else at AnyWare Designs are not responsible for any
kind of damage caused by this program directly or indirectly from the use
or misuse of M64 or M64 related programs.
13. AnyWare Designs
AnyWare Designs are
Jonas Hultén (author of this program)
and
Petrus Hyvönen.
14. Credits
M64 was written by
Jonas Hultén.
$VER: M64_manual 1.1.2 (10.1.98)
Created by Jonas Hultén.
Email: bjonte@hem2.passagen.se
May the Commodore Force be with you.