Using a song in production, using any assembler

BREAKING NEWS: Do NOT use Rasm 1.5 or 1.6, it is buggy! Use the 1.7 or higher, or any version below 1.5!

Sooo, you don't want to use Rasm in your production, but you're a bit embarrassed because the player and music sources are not compatible with your assembler. Fortunately, I got you covered.

Thanks to Disark, you will be able to convert the sources into ones that your assembler will like (to be more precise: it will convert a binary into a source). This command-line tool is inside the tools folder of the AT2 package (since alpha5), so you don't need to download it.

Prerequisite:

  • I assume you have read the previous parts of the tutorial, because I will not explain everything from scratch.
  • You still need to download Rasm to compile the sources. Don't worry, it is cross-platform! Do it now, thanks.
  • You have successfully exported a song (and sound effects optionally) in the AKG format (as an example), so have these files:
    • Grenade.asm (the song)
    • Grenade_playerconfig.asm (the optional config file for optimization)
    • SoundEffects.asm (the sound effects).
    • SoundEffects_playerconfig.asm (the optional config file for the optimization of the sound effects).

For this tutorial, we will emphasize on SDCC, because it is quite used on our 8-bit community, and it is also the most bothersome to care about! But if you're using Maxam, Winape, Pasmo, Vasm or anything else, it's going to be even easier!

If you want to follow this tutorial using SDCC:

  • I used the latest (3.9.0) version. If you have any problem, please update your version.
  • SDCC requires us to use hex2bin to generate the final binary. Download it here (windows exe here).

Also, we still use the AKG format. Using others (AKM, Lightweight, AKY) is possible and works exactly the same.

Converting your sources

A mandatory step is to convert the player/song/sound effects sources into another source that your assembler will understand. This must be done only once, so don't worry. Of course, if you change your songs, you will have to do this step once again!

What I advise is to compile all these into one single file. Most productions don't need more flexibility than this: you probably don't need to separate the player from the song, at first (but if you do, this can be easily done).

Let's create an asm file that will gather all these sources. We will call it CompileAT2Files.asm:

;Compiles the player, the music and sfxs, using RASM.
;No ORG needed.

    ;This is the music, and its config file.
    include "Grenade.asm" 
    include "Grenade_playerconfig.asm" ;Optional.
 
    ;This is the sfxs, and its config file.  
    include "SoundEffects.asm" 
    include "SoundEffects_playerconfig.asm"  ;Optional.

    ;What hardware? Uncomment the right one.
    ;PLY_AKG_HARDWARE_CPC = 1
    PLY_AKG_HARDWARE_MSX = 1        
    ;PLY_AKG_HARDWARE_SPECTRUM = 1
    ;PLY_AKG_HARDWARE_PENTAGON = 1

    ;Comment/delete this line if not using sound effects.
    PLY_AKG_MANAGE_SOUND_EFFECTS = 1

    ;This is the player.
    include "PlayerAkg.asm"

Note that, in this example:

  • I used the MSX hardware.
  • I enabled the sound effects.
  • I used both configuration file for song and sound effects, to have a fully optimized player.
  • The player has been added at the end, to make sure all the flags were set for the player to be well configured. You don't have to keep the same order, you can put the music/sfx after the player. BUT the flags and configuration files MUST be declared before the player, else it won't be able to use them.
  • Feel free to change all the parameters to satisfy your needs, of course.

Assembling with Rasm

We are now going to assemble this source file with Rasm.

"But hey, I thought we were converting sources, I don't want no stickin' binary!" you say in a hoarse voice. Well don't worry, we will get a source back thanks to Disark! First, let's compile this with Rasm:

rasm CompileAT2Files.asm -o UniversalAt2Files -s -sl -sq

This assembles the source above and produces two files:

  • UniversalAt2Files.bin: the binary.
  • UniversalAt2Files.sym: the symbol file.

Regenerating sources

Disark will require at least the binary, but shines when given the symbol file: it will be able to reproduce the source in a faithful way!

Disark UniversalAt2Files.bin At2Files.asm --symbolFile UniversalAt2Files.sym --sourceProfile sdcc

Here, we have chosen "sdcc" as the source profile, but you can ask for other assemblers. Check here for more info about the arguments.

What matters is that a new file, At2Files.asm, has been generated. You can open it. It contains the music, the sound effects and the player, in a syntax that can be understood by SDCC! Isn't that great? And since it is a well-generated source, you can relocate it wherever you want, and access its labels!

Building a tester

All is well, but it is now time to build a tester to check if what I'm selling you (for free) is really working. We're still using SDCC because it's soooo bothersome, but adapting to any other assembler is very easy.

We will embed Z80 code into a C program, but will not enter a single C line (ok... just one). Indeed, SDCC being a C compiler first, Z80 areas must be declared. Let's create a TesterSdcc.c file. For now, type this:

void main()
{
__asm
        .area tester (ABS)
        .org 0x4000
__endasm;
}

This simply declares an asm area (called "tester"), with an ORG at &4000. If you're using any other assembler, only the ORG instruction is useful!

I want you to first test that this compiles with SDCC:

sdcc -mz80 --no-std-crt0 --vc TesterSdcc.c

This should generate a few files we don't care about for now, but most of all, there should be no error and no warning! If there are, check you code and update SDCC.

Code initialization

Every code in every platform needs a bit of setup to satisfy the hardware/the system (stop interruption, etc.). We covered that in the previous part, but I'll make an example here anyway. We'll choose the MSX as an example because, just like SDCC, it's the most bothersome :).

void main()
{
__asm
    .area tester (ABS)
    .org 0xb000
 
    ;Header of a MSX binary file.
    .db 0xfe     ;Declares a binary header.
    .dw TesterStart    ;Start of the tester, just after this header.
    .dw TesterEnd      ;End of the tester.
    .dw TesterStart    ;Execution address.

TesterStart:           ;Starts our real code here. 
    ;... We will have to put our code here. 
TesterEnd:

__endasm;
} 

Ok, we can still compile this without error. This code makes it possible, on MSX, to load and execute this file using the BLOAD Basic instruction.

Add music

Just like we did in the previous part of the tutorial, we'll play music first and see if it works. Reminder:

  1. The player is initialized by giving the address of the music, and the index of the subsong to play (0 most of time).
  2. We wait for the frame flyback (hardware dependent!) to sync our music on.
  3. We play one frame of the song.
  4. We loop to the frame flyback label to play our song indefinitely.
...
TesterStart:
    ;1 - Initializes the music.
    ld hl,#AHARMLESSGRENADE_START    ;The music.
    xor a     ;The Subsong to play (>=0).
    call PLY_AKG_INIT

    ;2 - Wait for the frame flyback (MSX/Spectrum/Pentagon specific).
Sync:
    ei
    nop
    halt
    di

    ;3 - Play one frame of the song.
    call PLY_AKG_PLAY

    ;4 - Loop!
    jr Sync

    ;Of course we have to include the music/sfx/player!
    .include "At2Files.asm"
TesterEnd: 
...

Note: you may want to know how I found the AHARMLESSGRENADE_START label. You might have a different result, because it depends on how you generated your song. The first part is the "source prefix" asked by AT2 in the Export panel. But why the upper case? Because Rasm always treats its labels as upper case, and as Disark used the symbols exported by Rasm, logically, all the labels of our "At2Files.asm" are upper case.

This looks like a working tester! But let's compile it. This is done in two passes with SDCC. If you're using any other assembler, this is probably done in one:

sdcc -mz80 --no-std-crt0 --vc TesterSdcc.c
hex2bin TesterSdcc.ihx

The first line generates a few files, including an IHX file which contain more or less the binary, in a special format. The second line converts it to raw binary. At the end, and if no error occurred, you should have a TesterSdcc.bin!

First test on hardw... emulator

Testing it once again heavily depends on your hardware. You can include the binary in a virtual disk and run it on hardware or emulator. For the sake of completeness, I'll test this on a MSX emulator.

I am no MSX expert, but a simple way of doing it is as follows:

  • Use MSX Disk Manager (Windows) to create a DSK (default parameters are fine), drag'n'drop TesterSdcc.bin in it. Rename it to Tester.bin inside the software, else the long name will be bothersome. Save the DSK.
  • Use BlueMsx (Windows). Drag'n'drop the DSK, the MSX will boot. Once the prompt is shown, type:
bload"tester.bin",R

The file will load and the music will be heard! Isn't it great?

Add sound effects

One last step is to add the sound effects. We have already included the sound effects themselves, the player is configured to play them (via the PLY_AKG_MANAGE_SOUND_EFFECTS flag), so there isn't a lot left to do!

First thing, initialize the sound effects. This is exactly the same as for the music:

...
TesterStart:
    ;1 - Initializes the music.
    ld hl,#AHARMLESSGRENADE_START    ;The music.
    xor a     ;The Subsong to play (>=0).
    call PLY_AKG_INIT

<strong>    ;1b - Initializes the sound effects.
    ld hl,SOUNDEFFECTS    ;Address of the sound effects.
    call PLY_AKG_INITSOUNDEFFECTS
</strong>
    ...

The sound effect initialization must be done only once. It can be done at any time, but it must be performed before playing the sfxs. The SOUNDEFFECTS label is found in the"At2Files.asm", and its label comes from the "label prefix" that you entered when exporting the sound effects.

Now, you can play the sound effect. In order to have a fully working example, I set up a little timer to play the first sound effect every 100 frames on channel 3:

...
    ;3 - Play one frame of the song. 
    call PLY_AKG_PLAY

<strong>    ;3b - Plays a sound effect.</strong>
<strong>    ;Waits a bit before triggering a sound effect.
Counter: ld a,#0
    inc a
    cp #100     ;Waits for the 100th frame.
    jr nz,CounterEnd
    ;Plays a sound effect
    ld a,#1  ;Sound effect number (&gt;=1)
    ld c,#2  ;channel (0-2)
    ld b,#0  ;Inverted volume (0-16)
    call PLY_AKG_PLAYSOUNDEFFECT</strong>
<strong>
    xor a   ;Resets the counter.
CounterEnd:
    ld (Counter + 1),a</strong>

    ;4 - Loop! 
    jr Sync
...

Remember that calling the PLY_AKG_PLAYSOUNDEFFECT method will only program the sound effect: it will only be heard when the PLY_AKG_PLAY is called, frame by frame.

Compile and test this code... This will work of course! For more info about how the sound effects work, check this page.

This is now the end of this tutorial. I hope it was useful to you, and that you will flawlessly integrate AT2 in your new productions!