★ CODING ★ SOURCES ★ Récupérer une musique dans un jeu CPC par Tom et Jerry GPA 1993,2001 ! ★ |
Récupérer une musique dans un jeu CPC (Tom et Jerry GPA 1993,2001) | Coding Sources |
A la demande de Trebor 45, je vais vous faire un petit topo sur l'art et la maniere de récupérer une musique dans un jeu commercial ou une démo. Ayant pas mal pratiqué cet exercice (via les compilations Music Pack !), je peux vous faire part de mon expérience dans le domaine (cela fait un peu ancien combattant !). Avant de parler de la marche à suivre, il faut préciser deux choses :
1) Un peu de théorie...
Les musiques dans les jeux sont en général jouées sous interruption. Cela signifie que le player est appelé à intervalle régulier par l'intermédiaire d'une fonctionnalité spéciale du microprocesseur Z80, le cœur de nos CPC. Deux cas de figure peuvent se présenter :
Parfois, les musiques ne sont pas jouées par l'intermédiaire d'une interruption (beaucoup de démos dont les Music Pack sont concernées). L'interruption système RST &38 est alors "bloquée" et ne sert qu'à faire de la synchronisation vidéo pour utiliser des techniques nécessitant un timing précis, comme de la rupture ou des rasters. Le code d'une musique peut se trouver n'importe où en mémoire. C'est là un des avantages de l'assembleur, mais dans ce cas précis, cela nous complique la vie. Les données peuvent aussi bien se loger dans la RAM Basic que dans la RAM video, les zones réservées au système ou dans les bank mémoire supplémentaires pour les CPC ayant plus de 64ko. Cela peut donc poser problème pour les trouver. Heureusement que le CPC n'a pas 4mo de mémoire en standard ! En général, le player et les datas d'une musique sont rangés dans la mémoire de façon contigue, mais certains programmeurs sadiques trouvent une délectation suprême à disperser le tout. D'autres poussent même le vice jusqu'a morceler les données un peu partout ! Ne les maudissons pas et supposons qu'ils sont contraints d'agir ainsi pour économiser de la place mémoire. M'enfin, cela n'arrange pas nos petites affaires !!! Vous l'avez compris, récupérer une musique suppose donc de rechercher son player et ses données ! 2) La quête du player C'est la partie la plus délicate de notre périple. Il nous faut localiser la routine jouant la musique. Les différentes techniques présentées permettent dans la majorité des cas de la trouver. 2.1) Rechercher les opérations effectuées sur le RST &38. Pour pouvoir utiliser à ses fins ce vecteur d'interruption, le programmeur doit modifier son adresse de saut (JP &B941 sur un CPC 6128). Il doit donc changer le contenu des cases mémoire &39 et &3A par une ou des affectations mémoire. En recherchant les chaînes hexadecimales &39,&00 ou &38,&00, nous avons donc une chance de trouver des bouts de code dans ce style :
Evidemment, il y a toujours des originaux pour faire autrement, en utilisant par exemple la commande LDIR ou les registres d'index. Si vous trouvez quelque chose ressemblant à ce que nous venons de voir, notez l'adresse pokée en &39 et allez voir ce qu'il y a. La plupart du temps, vous allez trouver une routine qui sauvegarde tous les registres du Z80 avec des commandes PUSH, puis lance quelques CALL après de petits tests (JR Z, etc..). Exécutez en mode direct ces CALL après les avoir éventuellement étudiés. Si un bruit continu sort des entrailles de votre CPC, c'est presque gagné ! Notez l'adresse du CALL et testez cette hypothétique musique en tapant une de ces routines : a) La musique est jouable directement
b) La musique n'est pas jouable avec les interruptions ou est logée à un endroit réservé au système :
Si vous entendez une musique, le player est trouvé ! 2.2) Rechercher des bouts de routine sauvegardant les registres du Z80 Si la méthode RST &38 s'est révèlée vaine, tout n'est pas perdu. Je ne vais pas expliquer dans les détails la notion d'interruption, mais une contrainte qu'elle pose au programmeur va nous intéresser. Ce dernier est obligé de sauvegarder certains registres du Z80 avant de faire quoi que ce soit. PUSH AF &F5 On recherche les valeurs correspondant à ces mnémoniques et le tour est joué ! Puis l'on recommence ce que nous avons vu précedemment (analyse et tests des CALL). Attention, une sauvegarde des registres ne correspond pas forcément a une routine jouant ensuite une musique... 2.3) Le Hacker à la rescousse ! Vous avez lamentablement échoué dans vos précédentes recherches. Il existe une solution pour vérifier définitivement que la musique n'utilise pas l'interruption RST &38, le mode ALTERNATE du Hacker. Cette commande permet de faire tourner dans les bank supplémentaires du CPC (version 128ko obligatoire donc !) un programme. Contrairement à ce que prétend la documentation de cette interface, cette commande tourne aussi sur CPC 6128 , mais en mode "aveugle" (on ne voit pas ce que l'on tape au clavier). Enorme avantage, une fois le programme stoppe par le bouton magique, les banks ne sont pas initialisées. Il suffit de connecter ensuite la bank &C4 (bank 1) et de désassembler en &4038 pour trouver l'adresse de saut de l'interruption &38 du programme arrêté, sympathique non ? A partir de la, si cette adresse semble intéressante, on recommence la procédure décrite en 2.1). Si vous êtes l'heureux utilisateur d'une Multiface II, vous n'avez pas besoin de cette astuce, un arrêt du programme et l'édition de la RAM en &38 suffit. Pour faire ce genre de tests, vous pouvez aussi vous servir d'un émulateur comme Caprice, qui permet de geler un programme et voir le contenu de sa mémoire... 2.4) Rechercher la routine envoyant des données au PSG Dans toute musique, le programmeur est obligé d'utiliser une routine qui envoie des données au processeur sonore du CPC. Il existe bien dans le firmware du CPC un vecteur système servant à cela (&BD34), mais il n'est jamais utilisé. Les programmeurs de musiques préfèrent utiliser leur propre routine. Cette dernière est grosso modo toujours la même et se déroule comme suit (exemple : routine d'une musique Soundtrakker). LD B,&F4 |
boucle | CALL &BD19 |
- | CALL &8000 |
- | JP boucle |
> Normalement, vous devriez entendre la musique d'Outrun ! Le plus dur est fait.
b) Recherche de la sub-routine d'initialisation
On revient à l'endroit ou nous avions trouvé une instruction travaillant sur le RST &38 (en &107).
* Désassembler de nouveau à partir de &100 et chercher un CALL effectué pas trop loin de la case mémoire &8000 (adresse d'exécution précedemment trouvée).
> On trouve le code suivant :
LD A,&1
CALL &80B9
Cet appel se fait à priori dans la zone mémoire où se trouve la musique... Testons cette routine à l'aide d'un CALL (ne pas oublier de mettre le registre A a la valeur 1). Evidemment, rien ne se passe. Il faut exécuter la routine jouant la musique pour en vérifier le résultat.
Décidement, nous avons beaucoup de chance, nous avons trouvé du premier coup la bonne adresse, la musique est jouée à partir de son début.
Comme nous savons qu'il y a deux thèmes sur Outrun, cherchons un éventuel autre appel à la routine d'initialisation (CALL &80B9 pour ceux qui ne suivent pas !).
Aie, c'est le désert total, on n'a rien trouvé de plus...
A priori, vu ce que nous avons trouvé précedemment, il semblerait que c'est le registre A qui détermine la musique à initialiser. Il ne nous reste qu'à faire des essais avec différentes valeurs pour ce registre, en partant de 0. La chance (ou le talent ?) nous sourie encore, car un CALL &80B9 avec A=0 initialise l'autre thème du jeu.
Les plus curieux pourront lancer la routine avec A=3 ou A=4, par exemple, vous entendrez alors des bruitages !
c) Le nettoyage
* L'exécution de la musique étant en &8000, nous allons éditer la mémoire a partir de cette adresse et "remonter" (commande 'e' puis flèche vers le haut).
> Nous voyons une petite zone de &00 avant l'adresse d'exécution. Cela permet de supposer que l'adresse d'exécution correspond au debut de la musique.
* Cherchons maintenant la "fin" du morceau, en descendant dans la mémoire (flèche vers le bas). En &8F80, nous retrouvons une autre zone de &00.
> Nous allons travailler à partir de ces deux bornes.
* Sauvegarder la zone dans un fichier (OUTRUN.MUS, par exemple).
* Retourner sous Basic pour effacer la mémoire
* Revenir sous le prompt du Hacker, puis charger en mémoire le fichier OUTRUN.MUS.
* Tester la musique en l'écoutant jusqu'à la fin.
Dans notre cas, tout se passe bien.
* Nous pouvons donc recommencer l'opération en effacant une petite portion de la zone RAM occupée par le fichier (par exemple, de &8E00 à &8F80).
> Dans cet exemple précis, tout rognage du fichier OUTRUN.MUS se traduit par des pertes de données (sons bizarres, voix ne jouant plus, ou avec des rythmes décales, etc...). La longueur définitive de notre fichier est donc :
&8F7F - &8000 = &F80
Victoire, la musique d'Outrun est mise en fichier et utilisable dans vos créations les plus folles ! Il faut quand même noter que cette extraction est facile. Pour quelqu'un de bien entrainé, la chose est règlée en moins d'un quart d'heure. Cela constitue neanmoins un excellent exercice pour les profanes...
5) Ripper la musique de "Dizzy down the rapids" avec le Hacker
Et hop, une commande spéciale d'Iron. Nous allons voir maintenant un deuxième exemple. La victime est cette fois-ci un jeu de Codemasters dans le style de Toobin, avec l'incontournable Dizzy ! La description sera un peu plus lapidaire que pour Outrun, mais devrait suffire pour y arriver.
a) La recherche du player
* Arrêter le jeu sur la page du menu avec le Hacker puis rechercher la chaîne hexadécimale 38 00 en mémoire :
> On trouve 3 adresses : &6833, &7297, &AA76
* Désassembler un peu avant ces adresses (&6820, &7290, &AA70)
> Rien ne semble correspondre à du code.
* Rechercher la chaîne hexadecimale 39 00 en mémoire :
> On trouve une seule adresse : &2F43
* On désassemble en &2F30.
> On trouve du code intéressant :
&2F3F LD HL,&2F0E
&2F42 LD (&39),HL
* Désassembler en &2F0E.
> Il y a une routine sauvegardant des registres, puis lançant avec des tests trois CALL : &2C31, &23E6 et &6F17.
* On exécute les trois adresses :
> Rien ne se passe pour les deux premières. Avec &6F17, un souffle se fait entendre...
* Tester l'adresse avec la routine suivante en &BE80 :
boucle | CALL &BD19 |
- | CALL &6F17 |
- | JP boucle |
Oh, une belle musique retentit !
b) Recherche de la sub-routine d'initialisation
* On reprend le desassemblage en &2F30 en cherchant un CALL dans la zone des &6F17.
> Rien.
* On étudie les CALL situes après &24F2 (la commande pokant le RST &38) en desassamblant à chaque adresse, toujours pour rechercher un éventuel appel dans la zone pres de &6F17.
En &2F6B, on trouve un CALL &3363, qui exécute le code suivant :
CALL &6E3D
RET
* On essaie cette adresse. Il ne se passe rien. Par précaution, on désassemble en &6E3D. La routine ressemble pourtant à une routine d'initialisation. Elle est cependent un peu courte, et est suivie d'une autre routine, en &6E44.
* On recherche des appels à cette routine (&6E44)
> deux adresses sont trouvées : &335C et &3361. Tiens, c'est très proche de ce que nous avions trouvé plus haut...
* En désassemblant (on n'arrête pas ici !) un peu avant &335C, on trouve ceci :
&335A | XOR A |
&335B | JP &6E44 |
&335E | LD A,&1 |
&3360 | JP &6E44 |
> Hum, ca ressemble à une routine d'initialisation, ca... On teste !
Trouvé ! En prime, on a aussi la routine d'arrêt, qui est &6E3D ! En général, on trouve plutôt d'abord la routine d'initialisation.
c) Le nettoyage de printemps.
* On étudie le code un peu avant &6E30. A priori, le début de la musique est bien en &6E3C, car le "visuel" de la mémoire avec Edit (permet de voir une plage de la RAM sous forme de valeurs hexadecimale) ressemble à un sprite (valeurs se reproduisant à des intervalles constants).
* On se déplace maintenant vers le haut de la mémoire. A partir de &7C3E, il y a des zeros partout !
> On suppose alors que la musique est située entre &6E3D et &7C3D.
Il n'est en fait même pas nécessaire de faire des tests, car nos précedents désassemblages nous ont appris que la routine d'arrêt de la musique allait en &7C14. Si on désassemble à partir de là, on trouve une routine qui se termine en... &7C3D !
Voila, la musique est prête à etre sauvegardée. Cet exemple est, vous l'avez constaté, un peu plus complexe que pour Outrun. Il constitue un bon exemple de ce à quoi l'on est en général confronté.
Récupérer une musique dans un jeu CPC par Tom et Jerry GPA 1993,2001 !
|
|