Using CPCtelera with AT2

This is the french version of this great article written by Arnaud, the author of many excellent games published mostly on the RetroDev competition. The english version is hosted on our good friends' website 64 Nops! Thanks again to Arnaud for his contribution.

L'objectif de ce tutoriel est d'utiliser des musiques et sons créés par Arkos Tracker 2 avec l'environnement de développement CPCTelera.

Beaucoup de jeux utilisent cet environnement, par exemple le gagnant du CPCRetroDev 2020 "The abduction of Oscar Z" (Dreamin`Bits), "Sorcerers" seconde place du CPCRetroDev 2020 (SalvaKantero) ou encore Space Moves (RetroBytes).
L'essentiel des participants au CPCRetrodev utilisent d'ailleurs ce Framework.

CPCTelera est un environnement de développement sous Linux ou Windows avec Cygwin et qui permet de programmer en C et en assembleur pour l'Amstrad CPC.
Il inclut des librairies écrites en assembleur permettant de gérer : les graphismes, le clavier, le firmware, la vidéo, la mémoire et l'audio. Pour plus de détails : http://lronaldo.github.io/cpctelera/

Actuellement CPCTelera ne gère que le player d'Arkos Tracker 1 et l'objectif de ce tutoriel est de pouvoir exploiter les musiques et sons générés à partir d'Arkos Tracker 2.
Le code assembleur généré par Arkos Tracker 2 peut être directement utilisé, seul le fichier de liaison (PlayerAkm_cbinding.s) devra être modifié en cas de changement de player par exemple.

Un exemple fonctionnel du "player Minimalist", basé sur les fichiers musicaux d'Arkos Tracker 2 "SoundEffects.aks" et "Targhan - A Harmless Grenade.aks", est fourni.
Pour le compiler il faut simplement entrer la commande make.

L'archive arkos2.zip est un projet CPCTelera classique :

  • songs : contient les fichiers musicaux ArkosTracker2
  • src : contient toutes les sources décrites dans ce tutoriel
  • main.c : le programme principal permettant de jouer la musique et les sons
  • sound.c et sound.h : un exemple d'implémentation du player d'Arkos Tracker 2
  • arkos2/PlayerAkm_cbinding.s : fichier assembleur qui permet de faire le lien entre les appels des fonctions du C vers les fonctions du player d'Arkos Tracker 2
  • arkos2/PlayerAkm.asm : fichier assembleur généré (cf. suite du tutoriel), compatible CPCTelera/SDCC, contenant musique/sons ainsi que le player Minimalist
  • arkos2/ArkosPlayer2.h : fichier d'en-tête C contenant la déclaration des fonctions du player d'Arkos Tracker 2 pouvant être utilisées par le compilateur C
  • optional/setInterruptHandler.s et setInterruptHandler.h : gestionnaire d'interruption (facultatif) utilisant les registres alternatifs

Génération et création des fichiers compatibles avec CPCTelera

Les étapes suivantes vous permettront d'utiliser vos propres musiques et sons dans CPCTelera.

  • La première chose à faire est de suivre ce tutoriel (jusqu'au paragraphe "Regenerating sources" inclus) afin de générer le fichier assembleur au format "SDCC Z80".
    A l'issue de cette étape renommer le fichier généré en PlayerAkm.asm et le copier dans le répertoire arkos2.
  • Deuxième étape : rendre accessibles les musiques et sons au compilateur C

Dans sound.c modifier le nom des ressources en fonction du nom de vos propres productions (leur nom est dans le fichier assembleur PlayerAkm.asm)

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

A la fin de cette étape tout est prêt pour être utilisé par CPCTelera.

Remarque :
Si vous voulez utiliser un autre player d'Arkos Tracker 2 (ex : le player générique AKG au lieu de AKM) il faudra modifier le fichier PlayerAkm_cbinding.s pour changer le nom des fonctions.

ex:

 _PLAYER_ARKOS_INITSOUNDEFFECTS::
     jp PLY_AKM_INITSOUNDEFFECTS

deviendra

_PLAYER_ARKOS_INITSOUNDEFFECTS::
    jp PLY_AKG_INITSOUNDEFFECTS

Mise en oeuvre des éléments créés

La première chose à faire est d'initialiser la musique et les sons avant de les utiliser (exemple du fichier main.c) :

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

Ensuite il faudra appeler la fonction PlaySound (dans l'exemple tous les 1/50ème de seconde) pour entendre le son produit.
Dans ce cas, l'appel à cette fonction peut être, soit dans une 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 stuffs
    ...
    
    // 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
            PlaySFX(1, CHANNEL_A, MAX_VOL); 
        }   
        ...
    }
}

ou directement dans la boucle principale en utilisant une temporisation à l'aide de cpct_waitVSYNC :

void main(void)
{
    // Init stuffs
    ...

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

Attention : il faut prévoir le cas où le son est joué sous interruption et que votre code utilise les registres alternatifs (la plupart des fonctions de CPCTelera ne les utilisent pas, mais vérifiez dans la doc).
Dans ce cas il faudra utiliser une version modifiée de cpct_setInterruptHandler de CPCTelera afin de sauvegarder et restaurer ces registres.
La fonction asm_setInterruptHandler fournie dans l'exemple permet de le faire en sauvegardant et restaurant tous les registres.