Easy integration of Arkos Tracker 2 player with CPCTelera

By Arnaud. French version of this article is available on Arkos Tracker 2’s website!

The objective of this tutorial is to use music and sounds created by Arkos Tracker 2 with the CPCTelera development environment.

Many games use this environment, for example the winner of CPCRetroDev 2020 The abduction of Oscar Z (Dreamin`Bits), Sorcerers (SalvaKantero) second place of CPCRetroDev 2020 or Space Movies (RetroBytes). Most of the CPCRetrodev participants use this Framework.

CPCTelera is a development environment under Linux or Windows with Cygwin which allows programming in C and assembler for the Amstrad CPC. It includes libraries written in assembler allowing to manage: graphics, keyboard, firmware, video, memory and audio. For more details: http://lronaldo.github.io/cpctelera/

Currently CPCTelera only manages the player of Arkos Tracker 1 and the objective of this tutorial is to be able to use the music and sounds generated from Arkos Tracker 2. The assembler code generated by Arkos Tracker 2 can be directly used, only the binding file (PlayerAkm_cbinding.s) will have to be modified in case of a change of player for example.

A functional example of the “player Minimalist”, based on the Arkos Tracker 2 music files SoundEffects.aks and Targhan – A Harmless Grenade.aks, is provided. To compile it, simply enter the make command.

The arkos2.zip archive is a classic CPCTelera:

  • songs: contains the ArkosTracker2 music files.
  • src: contains all the sources described in the tutorial.
  • main.c the main program for playing music and sounds.
  • sound.c and sound.h: an example of implementation of the Arkos Tracker 2 player.
  • arkos2/PlayerAkm_cbinding.s: assembler file that links the calls from the C functions to the Arkos Tracker 2 player functions.
  • arkos2/PlayerAkm.asm: generated assembler file (read more of the tutorial), CPCTelera/SDCC compatible, containing music/sounds and the Minimalist player.
  • arkos2/ArkosPlayer2.h: C header file containing the declaration of the Arkos Tracker 2 player functions that can be used by the C compiler.
  • optional/setInterruptHandler.s and setInterruptHandler.h: interrupt handler (optional) using alternative registers.

Generation and creation of files compatible with CPCTelera

The following steps will allow you to use your own music and sounds in CPCTelera:

  • The first thing to do is to follow the following tutorial (up to and including the paragraph “Regenerating sources”) in order to generate the assembler file in “SDCC Z80” format. At the end of this step rename the generated file to PlayerAkm.asm and copy it to the arkos2 directory.
  • Second step: make the music and sounds accessible to the C compiler.

In sound.c modify the name of the resources according to the name of your own productions (their name is in the assembler file PlayerAkm.asm).

/** Resources */ 
extern void* AHARMLESSGRENADE_START;
extern void* SOUNDEFFECTS_SOUNDEFFECTS;

At the end of this step everything is ready to be used by CPCTelera.

Remark: if you want to use another Arkos Tracker 2 player (e.g. the generic AKG player instead of AKM) you will have to modify the PlayerAkm_cbinding.s file to change the name of the functions, e.g:

_PLAYER_ARKOS_INITSOUNDEFFECTS::
        jp PLY_AKM_INITSOUNDEFFECTS

will become:

PLAYER_ARKOS_INITSOUNDEFFECTS::
        jp PLY_AKG_INITSOUNDEFFECTS

Implementation of the created elements

The first thing to do is to initialize the music and sounds before using them (example of the main.c file):

// Main loop
void main(void)
{
        InitSound();
        …
}

Next the PlaySound function will have to be called (in the example every 1/50th of a second) to hear the sound produced. In this case, the call to this function can be either in an interruption:

void sInterruptHandler(void)
{
        static u8 sInterrupt = 0;
        // Play sound at 1/50th
        if (++sInterrupt == 6)
        {
                PlaySound();
                cpct_scanKeyboard_if();
                sInterrupt = 0;
        }
}
void main(void)
{
        // Init stuff
        …
        // Play first song
        PlayMusic(0);
        // Play sound on interrupt
        cpct_setInterruptHandler(sInterruptHandler);
        // Loop forever
        while (1)
        {
                if (cpct_isKeyPressed(Key_1))
                {
                        // Play sound 1 on Channel A with sound Max (0 > 10)
                        PlaySFX(1, CHANNEL_A, MAX_VOL);                }
                ...
        }
}

or directly in the main loop using a time delay using cpct_waitVSYNC:

void main(void)
{
        // Init stuff
        …
        // Loop forever
        while (1)
        {
                if (cpct_isKeyPressed(Key_1))
                {
                        // Play sound 1 on Channel A with sound Max (0 > 10)
                        PlaySFX(1, CHANNEL_A, MAX_VOL);
                }
                ...
                PlaySound();
                cpct_waitVSYNC(); // Wait for next 1/50th second
        }
}

Warning: you must think the case where the sound is played under interruption and your code uses alternative registers (most of CPCTelera’s functions do not use them, but check in the doc). In this case you will have to use a modified version of CPCTelera’s cpct_setInterruptHandler to backup and restore these registers. The asm_setInterruptHandler function provided in the example allows to do this by backing up and restoring all registers.