AYmake V0.0 by James McKay (14/08/1998)
=======================================

Purpose
-------
The purpose of AYmake is to allow the creation of new AY files.
When I say "AY" files I mean the "ZXAMEMUL" format originally used by DeliAY
(add-on part of the DeliTracker) on the Amiga.  Here they were usually called
"EMUL.*" but, for the sake of DOS 8.3 filenames, I decided to call them
"*.AY".

On the Amiga you had to use an assembler to make AY files, the result being
big endian words and ghastly 16-bit relative pointers.  Fine for space saving
but annoying (and limiting) otherwise.

AY files are specifically for the playing of "128K music" using the AY-3-8912
soundchip at I/O addresses 49149 and 65533.  According to standards it
*CANNOT* be used for playing 128K samples or any 48K (internal speaker)
sound.  This is to maintain compatibility with the original player on the
Amiga, however AYmake will allow you to make songs which have these in them
since AYplay V0.2 can handle them.

In addition, AY files can also play Amstrad CPC tunes (using the CPC ports),
but AYplay is not very good at playing these!

AYmake resembles "make" in concept but it looks like an INI file (as I used
the x128 INI file code to save time).


Usage
-----
C:\> AYMAKE GAME

This will take GAME.INI and create GAME.AY providing that the INI file
has no mistakes in it.

C:\> AYMAKE /debug GAME

Will do the same as above, but also output debug information to stdout.


About AY Files
--------------
AY files basically contain some blocks of Z80 code, some register/memory
information and some text for the player to display.


The Memory Model That An AY File Lives In
-----------------------------------------
AYplay emulates a Spectrum 128K (in 48K mode) with the following exceptions:

* Only the soundchip ports are emulated (49149 and 65533).
* Additionally, the Amstrad CPC ports are emulated.
* There is no ROM software.
* Interrupts do not work normally, they are completely controlled by AYplay.
* All 64K memory is RAM.
* No screen or contended memory.
* Memory is preset with certain values (see below).
* AYplay V0.2 also supports port 254 (internal speaker).


Memory Model
------------
    0 :         : call INIT             : 205,0,0
    3 :         : ld hl,INTERRUPT       : 33,0,0
    6 :         : ld a,h                : 124
    7 :         : or l                  : 181
    8 :         : jr nz,OK              : 32,8
    10:         : ld a,i                : 237,87
    12:         : ld h,a                : 103
    13:         : dec l                 : 45
    14:         : ld e,(hl)             : 94
    15:         : inc hl                : 35
    16:         : ld d,(hl)             : 86
    17:         : ex de,hl              : 235
    18: OK      : ld (HERE+1),hl        : 34,23,0
    21: LOOP    : halt                  : 118
    22: HERE    : call ????             : 205,0,0
    25:         : jr LOOP               : 24,250
    27:         : ret                   : 201

   28-   55 : 255
   56       : 201
   57-16383 : 255
16384-65535 : 000

Exception : If a word read is done at 65535 then it will always "see" 243 at
address 0 (65536), so that JR 65524 can be done (for "I=255" situations).

Address 27 may be used as a dummy INIT routine.

When you play a song the PC is set to 0 and this code is executed.
So, INIT and INTERRUPT are supplied by you.  If INIT is 0 then the start
address of the code block is called instead.  If INTERRUPT is 0 then the Z80
code works out where the interrupt should be, based on the value of the I
register after the INIT routine has been called.  The "halt" causes an
immediate interrupt, due to it's different implementation.  The end result
is that a song is played!

This is a very strange system.

You don't need to understand any of this, which is just as well...


What You Have To Do
-------------------
Firstly you must have hacked out a song player into a raw file and know
exactly where it should reside in memory, what the registers should be and
the INIT and INTERRUPT addresses.

You have to make an INI file, this is a (sort of) script file.

Firstly the Main Header:

	Creator         ="Song Author" ; The guy who wrote the tune(s).
	Misc            ="Game Name (C) 1988" ; For example...
	StartSong       =0 ; Number from 0-255

Fortunately you don't need StartSong since AYmake allows an automatic way of
deciding this.

To signify a new song do:

	NewSong=This

And to show that this is the startsong have this on the next line:

	StartSong=This

Much easier!


Song Fields:

	SongName="Level 3"
	AReg=0
	Stack=49151
	JpAddr=49152
	IntAddr=49155
	CodeStartAddr=49152
	CodeLength=AUTO
	CodeName=GAME.BIN
	CodeStartAddr2=32768
	CodeName2=25HZ.BIN

"Areg" (8-bits) is the value of every high byte of every register, before
	the INIT routine is called.  (eg.  A, B, D, H, A', B', D', H',
	IXH, IYH).  The low bytes are set to 0.
"Stack" is the stack pointer.
"JpAddr" is the INIT routine, if you set this to 0 then the
	"CodeStartAddress". is called instead.
"IntAddr" is the INTERRUPT routine, if you set this to 0 then it is
	calculated from the value of the I register after the INIT routine.
"CodeStartAddrX" is the start address of the code, in AYmake you can have 4
	different code blocks (and therefore 4 different start addresses)
	per song.  The "X" number may hold the values 1-4.
"CodeLength" is the length of the code block, can be a number, but is better
	to set to AUTO.  (This is actually ignored completely).
"CodeNameX" is the filename of the raw data block.  Like "CodeStartAddrX" you
	can also set "X" to the values 1-4.

Note about "CodeStartAddrX" and "CodeNameX" : The "X" signifies a number
(currently AYmake will allow the values 1-4) so that you can have more than
one code block per song.  The start address now has an additional meaning,
if it is zero then the file associated with it will not be loaded, nor will
any file after it (within that particular song).  You can omit the "X" number
and it will just assume that you are referring to code block 1.

You can also do this:

	JpAddr=DUMMY
	IntAddr=DUMMY

In order to prevent one of them from taking place (don't do both!).


Timesavers:

All of the Song Fields can have "All" preceeding them to make them effective
starting from the next "NewSong=This" and all the songs after that.

eg:

	AllSongName="I am too lazy to name the songs."
	AllCodeStartAddr=32768
	AllCodeLength=AUTO
	AllCodeName=GAMECODE.BIN
	AllCodeStartAddr2=949
	AllCodeName2=BEEPER.BIN

Note : When a "NewSong=This" is read, the parser latches all "All" values
       onto the new song, but you can still change individual fields by
       using the non "All" fields to change them.  For example, if you had
       one block of code which played multiple songs:

	AllStack=32767
	AllJpAddr=32768
	AllIntAddr=32771
	AllCodeStartAddr=32768
	AllCodeLength=AUTO
	AllCodeName=MULTI.BIN

	NewSong=This

	SongName="Song 1."
	Areg=0

	NewSong=This

	SongName="Song 2."
	Areg=1


You can also use hex numbers (for all numeric fields) in the following ways:

	JpAddr=#8000
	AllStack=$C000
	Areg=0x7F

You can even do:

	CodeStartAddr0x4=40000

You can also add comments with ";"

	; This script file written on 19/11/2090.

The easiest course of action is to just modify the example INI file
supplied.


Hacking Tunes
-------------
I can only say a little on this subject since I am not an expert on it.
To try this you must understand the Z80, know the I/O ports involved and
have a suitable setup for extracting the code into raw files, possibly an
emulator with a built in disassembler and raw code saving options.

In all cases you must be able to read the code of the routines that you find,
in order to know the location and size of the audio data.


48K Tunes (the kind that stop the on-screen action):
----------------------------------------------------
While the tune is playing enter your disassembler and go back along the
stack pointer.  You should find a single CALL which starts and plays the
tune to completion.

When making an AY file of it, set the "JpAddr" to the CALL value and set the
"IntAddr" to DUMMY (27).  Unfortunately, the tune may use the BEEPER routine
from the Spectrum ROM, which isn't in AYplay, so you would have to include
it yourself by loading it as another code block within that song.
The BEEPER routine is 949,67 (0x3B5,0x43) in the 48K ROM.


128K Tunes:
-----------
This is more difficult, you are looking for two CALLs - the INIT and the
INTERRUPT.  The INTERRUPT routine will probably live in the IM2 handler.
(First byte of IM2 is stored at wordpeek(wordpeek((Ireg<<8)|255)) ).

While in IM2 look for a routine which OUTs to 49149 and 65533.  Trace back
(without leaving IM2) and try to find one single CALL - this will be your
INTERRUPT value.  To test it, you could try CALLing it in a loop to see
if it makes a wibbly noise (because it's being CALLed too frequently, but it
is advancing the tune to the next note).

The INIT will probably access common memory locations with the INTERRUPT and
may be close to the INTERRUPT routine, but it's a bit of a hit and miss
affair.  The INIT routine may also be called with the A reg (or other
registers) set to certain values, possibly indicating multiple tunes played
from the one routine...

Remember that there is only a flat 64K in AYplay, no page flipping can
occur.


Amstrad CPC Tunes:
------------------
Similar to 128K tunes, but you may have to do substantial modifications to
the song player.  For example, it may use IM1 (CALL 56) to play the songs,
it may also use some I/O ports that aren't emulated by AYplay.

In general, a lot of work will be required.


Other Tunes:
------------
The original DeliAY allowed you to write custom playing routines in 68000
code, nothing like that is available here.


Maintaining Compatibility With The Amiga DeliAY
-----------------------------------------------
* Only make tunes that use the AY-3-8912 and only simple tunes, not samples.
* Do not make 48K tunes.
* Avoid using address 56 for dummy routines, use "DUMMY" (27) instead.


Limitations
-----------
* Due to the 16-bit relative pointers used in the file format, you cannot
  make an AY file which is very big (the biggest jump you can have is 32767).
* Only 256 tunes per file (maximum), which is unlikely to be a problem
  considering the other limitations mentioned.
* AYmake may display a "Very Serious Error" if you try to put too much in one
  file, experimentation is recommended.
* AYmake is limited to 128 filenames per INI file - unlikely to be a problem.

If you were making the AY file manually then you could probably squeeze more
in, but this is tricky!

There are other fields in the AY file format, but I've chosen not to include
them in AYmake, as they are non-essential.

The generated AY file is of version 0 and req_version 0.

Bye!

