This is the second of two features by Scott Mackie on the
MIDI interface - his introduction and guide to building your own MIDI interface
were contained in AMPLINEX 006.
MIDI Performance Code for AMPLE
Scott Mackie
Having, I hope, constructed your MIDI interface and got it
running, you can now start on the code needed to make AMPLE run as a MIDI
expander.
The 'Xpander' code comes as two parts: an assembler i/o
section and an AMPLE handling routine. This has the benefits of machine code
speed and AMPLE flexibility. I originally wrote the code entirely in AMPLE but
it was really too slow to use properly, and resulted in arpeggios on chordal
work - nice effect, but pretty unusable!
Although the assembler routine has its limitations (it slows
down a bit after more than 5 notes are pressed simultaneously) it is much more efficient
than AMPLE. Chordal work is still slightly slurred but the overall performance
is much better.
The code is positioned in memory at &900 and &D00,
with buffers at &A00 and &C00 (which unfortunately will corrupt the
Staff editor - sorry!). At &D00 is the interrupt code which loads the data
from the 6850 (the chip at the 'core' of the MIDI interface) into a circular
buffer and updates a pointer. It also 'echoes' the data to the MIDI Out to
simulate a MIDI Thru. There is a very small propagation delay, but this almost unnoticeable.
The code at &900 is the data handler. It 'chases' the
interrupt routine around the loop, reading the data back out and updating the output
pointer accordingly.
This method has the benefit of not missing any data, but the
performance can be slowed slightly under heavy data input. The buffer size is a
complete page, i.e. 256 bytes, which should be more than enough - if it isn't,
you're either Rick Wakeman or playing with the system exclusive dump on the
synthesiser!
After reading the buffer, the assembler code interprets the
data and stores it accordingly. I use the Econet workspace (&90 to &9F)
as variable space, so I'm afraid if the system is to be used on Econet some rewrites
may be needed.
The workspace is configured as:
&90: Input pointer. Where the latest input data is in
the buffer. Updated by the interrupt routine.
&91: Output pointer. Where the program has got to in the
buffer. Updated by the foreground program.
&92: ID byte for the following data 0: Noteon/off 1:
Pitchbend 2: Patch change
&93: <ID dependant data> &94: <ID dependant
data> &95: Voice to be used for current event &96: Blank &97: .
: Voice assignment data held here. . : 128 indicates unused voice &9F:
The assembler routine also provides voice allocation
routines for AMPLE, including a keysplit system. When a note is pressed, the
code goes to a lookup table at &C80, which contains the details of the
currently setup keysplit. The code finds the current zone the key pressed is in
and then allocates the voice accordingly. This system allows multi-timbral
(i.e. using more than one instrument) music to be played across the entire
range of the keyboard.
When a free voice is found for the note to be played on, the
note number is placed in the table between &97 and &9F for future
reference. A value of 128 indicates that the voice is clear. When a Noteoff is
issued, the code checks the table for the note number and places a 128 in the
voice location it finds, freeing that voice for future use.
A simple wrap-around system operates so that if the number
of notes played in any one zone exceeds the maximum allowed, the overspill
notes are played on the first voice of the split. This compromise seems to be
the best solution to a rather grey area of synthesiser programming.
Having completed all the data preparation, the assembler
routine returns to AMPLE, where the header block is checked and the relevant routines
called. The notes are played using the ACT command, and a rest is played for a
Noteoff. This allows envelopes such as Swell and Soft to complete.
If required, the code will release a channel to be used
again, without issuing a rest. This is achieved by use of the MNOTEOFF command.
OFF MNOTEOFF stops Noteoffs issuing rests and is very useful with envelopes
that actually tail away to zero, as the sound is more continuous with no rests being
issued.
Upright, in particular, is very effective like this and can
be played much like a normal piano. A foot pedal can be used to trigger this,
connected to the fire button for Joystick 1 on the Analogue port. A simple push-to-make
footswitch will do, and the code will detect its depression and act accordingly
(see the 'help!' information in the actual program about this).
Right, having waded your way through all that information,
how do you use the code?
Having loaded the file F.Xpander, try the following:
RUN
The disc drive should run and load in the file 'F.Xcode'.
Set the transmit channel on your synthesiser to channel 1 and enable its MIDI
output if required. Pressing a few keys on the synthesiser should now result in
AMPLE playing Upright at the right pitch.
If this doesn't work, check that the interface is paged into
the right position in memory. The details about this are in the assembler
listing file 'F.Xsource' which is included on this disc.
Also included in the 'Xpander' program is an AMPLE word
called 'test' that will print out all the data arriving at the MIDI port. This
should help with debugging if there's a problem. With luck, the code will work
and the fun can start!
Holding the SHIFT key down while pressing a note on the
master keyboard should take you back to the AMPLE prompt. The command 'RUN' is intelligent
and checks to see if the NMI code is still present. If not, the code will boot
in the NMI routines again from disc. If any problem should occur, just press
BREAK and type 'RUN' again. This should cure any minor problems (especially if
a disc is accessed, as this will overwrite the MIDI interrupt code).
Any sound can be used with the keyboard, just by defining
the maximum number of MIDI voices, i.e.
4 MSINGLE viola4
will provide 4-note polyphony with a 4-channel viola sound.
Changing the MIDI receive channel is easy. All that you have
to do is type, for example,
6 MCHAN
to set the interface to channel 6. The channel is defaulted
to 1 initially.
The MIDI interface also accepts velocity information so the
sounds produced will be responsive to velocity data. I haven't tried this feature
yet as I can't afford a velocity-sensitive keyboard, but I hope it will work!
Moving the pitch bend wheel on your synthesiser should
result in AMPLE changing the pitch of the sound. Incidentally, there's no
reason why the pitch bend wheel should cause the pitch to change. It could
alter the stereo position, volume, or voice parameters if required. Be experimental
with the AMPLE code!
Issuing a patch change from your synthesiser should cause
AMPLE to select a new sound for the voices. Edit the word 'Mpatchc' to suit
your own tastes and sounds. The word is set up at the moment to provide a
general selection of patches.
The last topic to be covered is key splits. All key splits
do is to allow different instruments to be used depending on where the note pressed
is on the keyboard. Up to 8 instrument zones can be defined, but within the
confines of 8 notes of polyphony. For example, you can have a split of 2+6, but
not 1+2+6 because this means having to use 9 voices, exceeding the internal
limit for AMPLE. The two commands to drive the key split definition process are
MSPLIT and KEYSPLIT.
If you type
MSPLIT
the screen will clear and you will be prompted for the
number of zones to be used across the keyboard. Having typed this in, you will
then be prompted for the number of notes to be used in zone 1 (which is the
lowest zone in the keyboard). The code will then wait for you to press the key
on the MIDI keyboard that indicates the top of the zone. This definition
process will continue until all the zones have been defined.
When MSPLIT finishes, it calls KEYSPLIT and prints out a
list of numbers. This sequence of numbers is the input to the routine KEYSPLIT.
This is the raw (very!) routine for processing splits. If that exact key split
setup is needed again then the string of numbers output can be used to call
KEYSPLIT, without having to go through the process again. The words mix1, mix2
and mix3 all illustrate this technique and should be studied in order to fully understand
this topic.
A complete listing of all the words used is included in the
AMPLE file 'F.Xpander'. Just type 'help!' to get the information.
And now for what the code doesn't do! The code will not
allow you to play along with existing music in AMPLE, although I am working on that.
I'm afraid this is due to the need for a quick response time in the input routine
(the program loops in the assembler domain to save time jumping between AMPLE
and the code). It also forbids use of Echo for, I presume, the same reason.
Maybe some AMPLINEX members can advise me on this aspect of the code.
Apart from these things, the code does run reasonably
reliably and doesn't seem to be prone to leaving 'hanging' notes.
I hope these articles have provided some AMPLINEX members
with enough material to experiment with MIDI. The basic code works well, but
changes can be made to it to allow further MIDI data to be processed, such as modulation
or aftertouch. Any comments on the code or queries could be sent to AMPLINEX
or, if preferred, to myself at the address below.
Scott Mackie 48 Milford East Kilbride GLASGOW G75 9BU
Note: An error was spotted in the previous article with
reference to the AMPLE hardware paging addresses. It does actually map into the
whole of the &FD page, between page numbers &30 and &3F and not
&FD30 and &FD3F as stated.
Related files on this disc:
Published in AMPLINEX 007, September
1988