| ★ 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 |
|
| LD HL,&xxxx | LD HL,&39 | LD A,&C3 | etc... |
| LD (&39),HL | LD (HL),&xx | LD (&38),A | - |
| - | INC HL | LD HL,&xxxx | - |
| - | LD (HL),&xx | LD (&39),HL | - |
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
| boucle | CALL &BD19 |
| - | CALL music ' (l'adresse que vous avez notée, on suit ?) |
| - | JP boucle |
b) La musique n'est pas jouable avec les interruptions ou est logée à un endroit réservé au système :
| - | DI |
| - | LD HL,&38 |
| - | LD (HL),&C9 |
| boucle | LD B,&F5 |
| boucle2 | IN A,(C) |
| - | RRA |
| - | JR NZ,boucle2 |
| - | CALL music |
| - | JP boucle |
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.
Comme en prime, le codeur est un animal bête et discipliné qui reproduit ce qu'il a appris, il va sauvegarder ces registres dans un ordre donné :
PUSH AF &F5
PUSH BC &C5
PUSH HL &E5
PUSH DE &D5
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.
Cette méthode n'est évidemment utile que si le jeu contenant la musique convoitée n'occupe pas les bank supplémentaires...
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).
2.5) Le désassemblage pur et dur !
Le programmeur de jeu dont vous convoitez la musique est un être raffiné ; dernière solution, la plus laborieuse, il vous faut étudier le programme depuis son adresse d'exécution. Pas de recette miracle, seules de la perséverance et un peu de chance vous permettront d'arriver à vos fins...
Bien, à partir de maintenant, je considère vous vous avez trouvé le player (pas de panique si ce n'est pas encore bien clair, nous verrons deux exemples par la suite). Avant de passer au nettoyage de la musique (c'est à dire ne garder que les données utiles), il nous faut trouver les adresses d'init du ou des thèmes qui la composent, et pour les perfectionnistes, celle qui l'arrête. En pratique, on peut se passer fort bien de cette derniere sous Basic, un CALL &BCA7 faisant l'affaire (pitié, pas de PRINT CHR$(7), ce que l'on voit souvent dans des vieilles mauvaises démos allemandes).
Là, pas de recette miracle, il faut noter que souvent, cette adresse n'est pas bien loin de la routine jouant la musique. On retrouve alors un appel à cette routine "près" de la portion de code détournant le RST &38.
A vos désassembleurs !
Pour les musiques ayant plusieurs thèmes, en général, les programmeurs utilisent un registre (souvent A) pour définir quel air doit être joué. Parfois, il faut poker des valeurs en mémoire (les musiques de Tiny Williams, par exemple). Bref, il faut avoir du flair !
3) Le grand ménage
Il faut maintenant récupérer les données associées au player que vous avez débusque ! Là encore, pas de méthode miracle, mais quelques recommandations à suivre donnant souvent de bons résultats.
La première chose consiste à parcourir la mémoire à partir du player pour trouver une zone de 00 conséquentes ou une routine n'ayant rien à voir avec la musique. Cette technique primaire est assez efficace car souvent, le player et les données sont situées l'un après l'autre, particulièrement si votre musique se trouve dans une bank de mémoire supplémentaire, ou dans la zone réservée au système (&A67B à &BFFF pour le 6128).
Sinon, il faut procéder par tâtonnement, en sauvegardant tout d'abord une large zone mémoire, puis en la "dégraissant" (remplir des bouts avec des 00) au fur et à mesure. Je vous le concède, ce n'est pas bien passionnant ni tres épanouissant techniquement. En plus, c'est souvent long !
La longueur usuelle pour une musique simple varie entre &A00 et &1000, mais peut être plus grande chez certains éditeurs (Krisalis, par exemple !).
Petite anecdote, la musique la plus lassante (pour être poli) que j'ai nettoyée est celle de Turbo out run. Elle ne comporte pas moins de 8 blocs de données différents, situés un peu partout dans la mémoire. De quoi devenir dingue !
Voilà, après ces explications, "ripper" une musique de jeu devrait vous sembler facile. Euh.. non ? Bon, deux exemples vous montreront que c'est plus simple que cela en à l'air.
4) Ripper la musique de 'Outrun'avec le Hacker
Nous allons récupérer ensemble la musique d'un jeu très célèbre, Outrun. C'est vrai, la conversion sur nos micros de cette borne d'arcade est vraiment mauvaise. La musique est néanmoins assez mignonne sur CPC, en plus, elle est facile à récupérer !
a) La recherche du player
après avoir chargé le jeu, on l'arrête avec le hacker au niveau de la page de présentation. On commence la recherche avec la première méthode (cf 2.1)).
* Taper 'S' puis la chaîne hexadécimale 38 00
> Le Hacker trouve trois fois cette chaîne aux adresses &107, &4CA4, &83BE.
* Désassembler un peu avant ces adresses (&100, &4CA0,&83B0 par exemple) grâce à la commande 'D' et étudier ces zones de code.
Oh miracle, la première adresse (&107) a bien une action sur le RST &38 en pokant l'adresse &17C en &39.
* Désassembler en &17C.
> Nous trouvons d'abord deux instructions qui sauvegardent des registres (ca ne vous rappelle rien ?), puis deux appels à deux routines :
CALL C,&8000
CALL &99B
* On exécute le premier CALL en mode direct.
> Le CALL &8000 se traduit par un son strident et continu. Le player est trouve ? Vérifions...
* Taper la routine suivante en &BE80 puis faire un CALL &BE80
| 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 !
| ![]() |
|