Various Music-related Files
---------------------------

Note: Any file which is a program will be stored in xzx tape
format, which is as follows:

  bytes 0- 3: the string "XZF1".
  bytes 4-20: a spectrum tape header, including:
              byte   4:    zero
              bytes  5-14: a name
              bytes 15-16: the file length
              bytes 17-18: the LINE number, if any
              bytes 19-20: the length of the program, excluding variables.
  bytes 21- : the program itself.

This format can be changed into a +3 disk image using "xzx2plus3" by Thomas
Kjaer (available from ftp.nvg.unit.no).

Any file which is CODE will be stored as raw data.  The start address
and length will be given with the file's description below.  If the
start address is given as "start", then the code is relocatable and
any start address may be chosen.

Each of these files except "FL" and part of 2TUNE2C is written by Ian
Collier.  Permission to use and distribute as-is for non-commercial
purposes is granted provided due acknowledgement is given.

  ADVERTISEMENT

  Many of these programs work best on the +3 in "48K Disk BASIC", which is
  available for v4.0 +3 machines from ftp.nvg.unit.no.

FL (CODE 49152,1152) - the tune from FAIRLIGHT.

This piece of code was hacked (without permission, sorry) out of the
said game.  Call 49152 and listen.  Note: the program exits when a key is
pressed.  After the tune has finished the program will still continue to
pause waiting for a keystroke.

FL2 (CODE 60000,1350) / 2TUNEC (CODE 62200,145)
                             - a copy of the tune from FAIRLIGHT.

Before I examined the game to find the tune, I attempted to reproduce the
effect myself.  The result wasn't perfect, but see how well I did...  Load
both pieces of code and then call 62200.  This program always runs until the
tune has finished.

2TUNE2 (program) / 2TUNE2C (CODE 60000,155) - a 2-channel tune generator

If I remember correctly, the code uses a slightly modified version of the
algorithm used in FAIRLIGHT to generate 2-channel music (as opposed to
2TUNEC, which was written independently).  The program is a simple-minded
entry system for the music.  When you run the program, it will ask for a
unit note length.  Type in a number between, say, 0.05 and 0.5, which is a
time value measured in seconds.  Each note will have a duration which is a
multiple of this number.  After answering this question, type in for each
note two note values and a duration.  Note: the maximum note length is
just below 1.8 seconds.  If you ask for more than this then the program
will fail horribly.  The two note values can be either zero (for a rest)
or a semitone number which is much like the spectrum's BEEP instruction
except that middle C is about 24 instead of zero.

Typing a space instead of the first note value will play the music so far.
Entering nothing (the null string) instead of the first note value will stop
the program.  To save the music, save from 60000 to X inclusive.  that is,
type

   SAVE "somename" CODE 60000, x-59999 .

To play the music, call 60000.

JJ2 (CODE 60000,1419) - a 2-channel tune

This is a tune entered using the system described above.  Call 60000 and
see whether you recognise this well-known piece by J. S. Bach...

MINUETZ (program) / MIN (CODE 59000,5903) - a Mozartian music generator

The idea for this program was based on program by Hopkins/Laverty which
was supplied with their Protek sound board for the Spectrum (and also
published in Your Computer), which was in turn based upon an idea by
Mozart.  This is a 128K spectrum version which has been written from
scratch, except that the same bars and table have been kept.

Mozart wrote about 160 bars of 3-part music and a table showing which
bar of music was to be used for each throw of two dice, depending upon
the position of the bar within a 16-bar minuet.  Each set of 16 throws
of a pair of dice therefore generates a different minuet.  This process is
clearly very suited to implementation on a computer, and that is where this
program comes in.  The computer will throw the dice (or, for the impatient,
just draw up a table of 16 numbers), and will then play the minuet which
has been generated.  The music will sound through the 128K spectrum's sound
chip, and will also appear on MIDI channels 1, 2 and 3 via the MIDI port.

Unfortunately, this program suffers from a misinterpretation which was made
by the original authors.  If the dice throw for the last bar in the first
half of the minuet is an odd number, then the notes which are generated
will apparently clash.  After this program was written I saw an article
which included a facsimile of this bar written by Mozart, and it turns
out that the discordant notes are not to be played together.  Instead,
the lower sequence of four notes in the bass clef should be played on
the first time and the upper four notes should be played on the repeat.

TUNE (program) / TUNE.BIN (CODE 64000,1216) / FILL.BIN (CODE start,3294)
                             - a tune player

This is an interrupt-driven tune program which was designed for the 48K
Spectrum with Protek sound generator board or for 48K {Disk} BASIC on
128K machines, but it works in 128K mode as long as the program isn't
unexpectedly paged out.  The tune is played in 3 channels on the sound
chip, and also (on a 128K Spectrum) output on MIDI channels 1, 2 and 3.

All the tunes I have typed in are by the band SKY - hence the large SKY
banner which is displayed by the program...

CANNON.TUN (CODE 29994,2080) / DANZA.TUN (CODE 29994,1440) /
GRACE.TUN (CODE 29994,171)   - tunes to play with the program TUNE

(The tunes are "Cannonball" and "Danza" from SKY and "Grace" from SKY3).

MAKETUNE (program) - a 3-channel tune generator

This program outputs tunes in the format which is used by TUNE above.

A tune file contains three "programs" (one for each channel of music)
which are interpreted simultaneously by the TUNE program, and three
start addresses.  In order to play a tune, you should load TUNE.BIN,
poke in the three start addresses into the variables st1, st2 and st3
(which are, in this version, at 65166, 65168 and 65170, respectively),
and then call 64000.  The tune will play in the background until it has
finished, or until a STOP error occurs (which is detected by testing the
contents of 23610).  The program then puts the interrupt mode back to
normal.

Each program may contain the following commands:

   (zero): this is a rest, and takes a one-byte parameter which is the
           length of the rest in 1/50 second units.
   (any non-zero number): this is a note, and takes a one-byte parameter
           which is the length of the note in 1/50 second units.  The note
           value is a semitone number, with middle C being note 48.
   end:    this must be placed at the end of each program.
   vol:    this sets the volume of the current channel to the one-byte
           parameter.  In addition, if bit 7 of the parameter is set then
           the channel becomes a white-noise channel instead of a tone
           channel.
   wave:   this tells the channel to use the AY-3-8910 envelope waveform
           given by the one-byte parameter until the next "wave" or "vol"
           instruction.
   x:      this sets the waveform period to a value given by the one-byte
           parameter.
   call:   this calls a program at the address given by a two-byte
           parameter.  Calls can be nested to a level of 10.
   ret:    this returns from a called program.  It must be placed at the
           end of any program which is called, but must not be placed in
           any program which is not called.
   djnz:   this takes two one-byte parameters: a repetition count and a
           relative jump (the program inputs an address and then calculates
           the relative jump).  Repeated sections may be nested to an
           arbitrary level.  Note: the "number of repetitions so far"
           is stored in memory, so may be corrupted if a tune is stopped
           before it has finished.  The program has a command "reset" which
           puts all the "djnz" instructions back to normal.  Running a tune
           to completion will reset all the "djnz" instructions back to
           normal.

The MAKETUNE program inputs any of the above commands and pokes them in
at the address shown in the prompt.  It also accepts any of the following
commands:

   m<x>:   moves the current address pointer to x.
   st:     prints the current values of st1, st2, st3 (initially these all
           point to a program containing the single instruction "end").
   st<n>:  sets the value of stn (where n is 1, 2 or 3) to the current
           address.
   play:   plays the current tune (starting from the most recent values
           assigned to st1, st2 and st3).
   play c: plays only the channel numbers listed in the string c.
   stop:   stops the tune if it is in progress (this command resets any
           "djnz" instructions back to normal).
   reset:  resets any "djnz" instructions in the most recently played
           tune.
   do<x>:  plays a "call x" instruction.  The program starting at x must end
           with either "ret" or "end".
   do:     plays a "call" at the current address.
   v<x>:   views one screen's worth of memory starting at location x.
   v:      views one screen's worth of memory continuing from the point
           where the last "v" command left off, or from the current address
           (if there was no previous "v" command or the "m" command has been
           executed since the last "v" command).
   save:   saves the tune in a format suitable for use by the TUNE program.
           The code which is saved starts at 29994 with the values of st1,
           st2 and st3, and then includes any programs which have been typed
           in between 30000 and the current address.  The current address
           must be at the end of the tune in order for this to work.
   load:   loads a tune which has been saved with the "save" instruction.

PLAY (program) / PLAY.BIN (CODE 62500,2520) - a "piano" program

This program turns the spectrum keyboard into a piano keyboard with
3-note polyphony.  The program stores the tune as three sequences of
note and rest commands as described above, so a tune can be saved and
used with the TUNE.BIN program.  The PLAY program does not contain an
option to save the tune, but the pointers are always displayed so that
sections of the tune can be saved.

SOUND2 (CODE 63000,2120) - BBC Micro sounds emulator

This program was also originally designed for the 48K spectrum with a Protek
sound board, and works on that or in 48K modes of 128K machines.

Call 63000 to initialise (this has to be done after each RUN or CLEAR, so
put it at the start of any program which uses SOUND2).  The new commands
"=s" and "=e" will be available.  These emulate the BBC Micro's SOUND and
ENVELOPE commands, respectively, with a couple of minor differences.
Descriptions of the commands follow.

=s &HSFN, vol|env, pitch, duration

&HSFN is a collection of flags written as hex digits.  Unfortunately,
the spectrum does not have hex conversion (except with my modified
Interface 1 ROM or some other utility) so the number should be expressed as
N+16*F+256*S+4096*H (which, of course, simplifies when one or more of H, S
and F is zero).  N is a channel number.  Unlike the BBC Micro's sound chip,
the AY-3-891x does not have a channel 0. Instead, white noise is produced by
adding 4 to the channel number, which should be between 1 and 3 (inclusive).
F is a flush flag.  If F=1 then all pending notes on channel N are flushed
and the note takes place immediately.  If F is zero then notes will queue
up.  S is a synchronisation flag.  In a chord of two notes or more, each
note should have S set to the number of other notes in the chord (that is, 1
or 2).  Notes with a non-zero S flag will wait until the correct number of
other notes, each with a non-zero S flag, are ready to be played.  H is a
delay flag.  If it is set to 1 then the note will wait until the previous
note has finished its "release" cycle (that is, it has reached zero volume)
before playing.  In the usual case where H is zero, the note will be played
as soon as the previous note has reached the end of its duration.

The vol|env parameter is either a number between -15 and 0 whose absolute
value indicates the volume at which the note should be played, or the
number of a defined envelope.  The pitch parameter is a number between 0
and 255, which indicates pitch in steps of a quarter-semitone.  A value of
80 indicates middle C (thus a value of 0 indicates a bass E and a value of
255 indicates a slightly flat very high G#).  The duration parameter gives
the length of the note in tenths of a second.

The =s command queues notes for each channel in a separate queue.  Each
queue can hold four notes.  If the queue is full then the =s command will
pause until there is enough space in the queue.

=e N, T, PS1, PS2, PS3, NS1, NS2, NS3, AR, DR, SR, RR, AT, DT

   where each parameter is an integer and

      1 <= N <= 10
      1 <= T <= 255
   -255 <= PS1, PS2, PS3 <= 255
      0 <= NS1, NS2, NS3 <= 255
      0 <= AR, AT, DT <= 126
   -126 <= DR, SR <= 126
   -126 <= RR <= 0

N is an envelope number.  T is a time value in 1/50-second units (not
1/100 as on the BBC Micro) between 1 and 127, plus a repeat flag.  Usually
the pitch part of the envelope is repeated forever, but if bit 7 (the high
bit) of T is set then the pitch part of the envelope is only executed once,
after which the pitch remains constant.  The pitch part of the envelope is
defined by the three pairs of values PS1/NS1, PS2/NS2 and PS3/NS3.  Each
pair gives a pitch step (PS) and a number of steps (NS).  At every time
interval of length T, the current pitch of any note played using this
envelope is altered by adding the PS value, modulo 256 (for example, 255+1
is zero and 0-1 is 255).  This is carried out NS times, and then the next
pair of values is considered in sequence.  The volume part of the envelope
consists of an attack cycle, a decay cycle, a sustain cycle and a release
cycle.  Each cycle increases or decreases the volume by a certain amount at
every time interval of length T. The volume at any time is a 7-bit number in
the range 0-126 (which is, of course, divided by 8 before passing it to the
sound chip).  The attack rate is given by AR, and the attack cycle continues
until the volume reaches or passes the attack target given by AT.  The decay
cycle then takes place, at a rate given by DR (note that although this is
called the "decay" cycle, the volume of the note can increase during
this cycle).  This cycle continues until the volume reaches or passes
the decay target given by DT.  The sustain cycle then takes place at a
rate given by SR, and continues until the duration of the note (given on
the =s instruction) has ended.  At this point, if there is a note queuing
(which does not have the H flag set) then the current note finishes.
Otherwise, the release cycle takes place, at a rate given by RR, and
finishes whenever the volume reaches zero.  Note that since RR may be
zero, the note may continue forever.

PLAYCOM (CODE 60000,3205) - a PLAY command giving 5 channels in 48K BASIC

This program was also originally designed for the 48K spectrum with a
Protek sound board, and works on that or in 48K modes of 128K machines.
Its advantage over the 128K mode PLAY command is that it gives up to five
channels on audio by using the "beeper" as well as the sound chip, but the
disadvantage is that it does not do MIDI.

A short information file that I typed years ago is contained in PLAYCOM.FSE
(this is a Unix ASCII text file).

In case you do not have access to a 128K Spectrum manual, here is a brief
summary of commands:

  a..g A..G   notes (capitals are an octave higher)
          &   rest
          #   sharpen following note
          $   flatten following note
      1..12   note lengths
          _   add note lengths together (as in "5_3")
     !text!   comment
      (...)   repeat the enclosed text
          H   halt
       M<n>   set mask to n (complement of sound chip register 7)
          N   null
       O<n>   change octaves ("O5c" is middle C)
       T<n>   tempo n crotchets per minute
          U   use a sound-chip envelope
       V<n>   change volume
       W<n>   change waveform number

and note lengths:

          1   semiquaver
          2   dotted semiquaver
          3   quaver
          4   dotted quaver
          5   crotchet
          6   dotted crotchet
          7   minim
          8   dotted minim
          9   semibreve
         10   triplet semiquavers
         11   triplet quavers
         12   triplet crotchets.

CHRISTUS / GABRIELI / HOSANNA / MICHAEL / PURCELL / SATWS / SUSSEX 
(all programs)   - music written in PLAY statements

Each of these except SATWS ("See amid the winter snow") and SUSSEX (the
Sussex carol) are described in REM statements at the start of the program.
The latter two are carols from "100 Carols for Choirs".

HOSANNA and PURCELL will work as-is using either 128K PLAY or PLAYCOM
(above).  SATWS and SUSSEX will only work on PLAYCOM.  GABRIELI will
only work on 128K PLAY because it is in 8 parts.  The other two files
are designed for 128K PLAY but can easily be converted to PLAYCOM.

Converting from 128K PLAY to PLAYCOM involves the following.

 * Select the 4 or 5 most important channels from tunes that have more
   than 4 or 5 channels (4 is better because with 5 channels PLAYCOM can
   get a bit out of tune.  However, the above programs are OK to play
   with 5 channels) (in MICHAEL, f$ is clearly the least important).
 * If 5 channels remain, then select the two channels which are least
   important and/or contain the lowest notes to be played on the beeper.
   Lower notes have a higher probability of being played in tune (in
   MICHAEL, choose d$ and e$ as the two lowest; in CHRISTUS choose c$
   and e$ since c$ has only a few notes and e$ is the lowest).
 * If 4 channels remain, consider putting the bass or the melody channel on
   the beeper, because it is likely to be louder than the other channels.
 * When selecting the beeper channels also note that notes played on the
   beeper will be (temporarily) stopped whenever another note ends or
   starts.
 * Remove all Y instructions from all strings and remove V instructions from
   the string(s) which will be played on the beeper.
 * Write the PLAY instructions with the beeper channel(s) last.

