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 M64demo.MSX (or 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.
Note that in the demo version it is not possible to edit ASL programs.
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.
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 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: md6cbm@mdstud.chalmers.se.
In the demo version you can not edit ASL programs, only load, save, compile
and run them. All MIDI controllers except the modulation wheel are ignored. That
means no sustain pedal, aftertouch, pan, expression or pitch wheel.
If you register you will receive the latest version of M64 and all related
programs written at the time (the Performance Player has not been finished yet).
You will also receive all future versions of M64 for free. Registered users also
have free e-mail support.
Register by sending 100 SEK, 10 UK pounds, US $15 or 25 DM along with the registration
form that came with this package to:
Jonas Hultén After the registration you will receive the necessary files by e-mail. Refer
to the installation section if you want to know how to transfer the M64 package
electronically to your c64.
Thanks to
M64 was developed using the following equipment.
Hardware:
Software:
All contents copyright © 1997 AnyWare Designs. All rights reserved. URL: http://www.mdstud.chalmers.se/~md6cbm/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 is shareware. That means that you will be
able to play around with the demo version of this program and if you think it's
worth it, you pay some money to get the full version of the program. It is a lot
of work behind this program even if the size of the executable is around 30kB.
Remember that this is not a Visual BASIC program, so the source code has to be
huge to produce 30kB code! Actually it's about 16000 lines right now.
Kalendervägen 121D
S-415 13 GOTHENBURG
SWEDEN
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.0.13 (8.6.97)
Created by Jonas Hultén.
Email: md6cbm@mdstud.chalmers.se
May
the Commodore Force be with you.