Ape Escape - Swapping voice packs

Post a topic about yourself to let others know your skills, hobbies, etc.
Post Reply
Stasis
Interested PSXDEV User
Interested PSXDEV User
Posts: 5
Joined: Sep 08, 2021
PlayStation Model: SCPH-5500
Location: New Zealand

Ape Escape - Swapping voice packs

Post by Stasis » September 11th, 2021, 1:46 pm

Apologies if this is the wrong place to be posting this.

So I've been digging around lately into attempting to swap the EU/UK voice acting/packs into the NTSC version of Ape Escape as it runs noticeably better. I played Ape Escape a lot as a kid, and the value of swapping these voice-packs over is entirely based on nostalgia. This may sound ridiculous or a waste of time, but I'm self-aware and it's definitely a waste of time :lol:

This has been a learning adventure so far as to how psx games work in general, how their data is packed, and how to reverse engineer bits and pieces of the game.

I made a simple but possibly naive attempt to repack the US bin with just the STR files I located from the EU source bin using ultraiso. Booting this resulted in the forbidden boot image/logo, so I can only assume it did not repack as it should have.

From here I've moved on to use fisgon as I learned about the various issues of repacking psx bin files and Ape Escape is in mode2. Repacking the STR files using this did allow the game to boot normally again, however, the voice lines simply did not play. Onto the next thing.

I started wondering, are these really the files I need to be moving, do they play correctly through an STR player, etc. They do not, turns out they're XA files and place fine when opened with something that handles XA files (such as XA Audio Converter, wish there was source for this, wanted to port it to Rust). Great, this tool allows you to repack the XA files with WAV and be a bit more preserving, I tried doing this with a single voice line and repacking it into the bin to see if Ape Escape would pick this up. No luck.

The STR folder contents:

Code: Select all

STR $ ls

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         6/05/1999   5:36 PM         283336 END_TEST.ALL
-a----         6/05/1999   5:37 PM         482204 END_TEST.STR
-a----         7/05/1999   2:13 PM        4026668 GOV1.STR
-a----         7/05/1999   2:13 PM        4026668 GOV2.STR
-a----         7/05/1999   2:13 PM        2333228 LAB.STR
-a----         7/05/1999   2:13 PM       21600812 STEXP.STR
-a----         7/05/1999   2:13 PM        2370860 TALK.STR
-a----         7/05/1999   2:14 PM       12757292 WEPGET.STR
On to the next thing, what does the source have to say about this. I've always been interested in getting more familiar with Ghidra, and found ghidra_psx_ldr. I loaded up the source and begun digging to try and find at what point that the game actually load or read from the STR-not-STR-but-XA-files, but could not find an entry point to these files. The only reference to the local file system I could find was to KKIIDDZZ.DAT:

Code: Select all

                             LAB_80011d10                                    XREF[1]:     80011d18(j)  
        80011d10 38 98 00 0c     jal        CdSearchFile                                     undefined4 CdSearchFile(undefine
        80011d14 d0 40 05 26     _addiu     a1=>s_\KKIIDDZZ.HED;1_800a40d0,s0,0x40d0         = "\\KKIIDDZZ.HED;1"

Code: Select all

  do {
    iVar1 = CdSearchFile(aCStack56,"\\KKIIDDZZ.HED;1");
  } while (iVar1 == 0);
From here I kind of went astray a bit, and did some digging into the header/hex for the header and also the BNS file associated with it to not find any references to the STR folder or files again. I attempted to find any references to any of the STR file names, such as WEPGET, or STEXP (which contains the professor's voice lines in XA), but also came up dry.

From here I revisited the function I decompiled earlier and found that these differences occur in this data loading function between the EU and US versions of the game:
Image
Where the first mismatch is:

Code: Select all

  do {
    iVar2 = CdRead(1,&DAT_800b7e50,0x80);
  } while (iVar2 == 0);
  CdReadSync(0,auStack24);
  iVar2 = 0;
  puVar4 = &DAT_800b7e50;

Code: Select all

                             LAB_80011d4c                                    XREF[1]:     80011d58(j)  
        80011d4c 50 7e 25 26     addiu      a1=>DAT_800b7e50,s1,0x7e50                       = ??
        80011d50 bc 9f 00 0c     jal        CdRead                                           int CdRead(undefined4 param_1, u
        80011d54 80 00 06 24     _li        a2,0x80
        80011d58 fc ff 40 10     beq        v0,zero,LAB_80011d4c
        80011d5c 01 00 04 24     _li        a0,0x1
        80011d60 21 20 00 00     clear      a0
        80011d64 23 a0 00 0c     jal        CdReadSync                                       int CdReadSync(int mode, u_char 
        80011d68 30 00 a5 27     _addiu     a1,sp,0x30
        80011d6c 21 20 00 00     clear      a0
        80011d70 0f 00 06 3c     lui        a2,0xf
        80011d74 ff ff c6 34     ori        a2,a2,0xffff
        80011d78 f0 ff 07 3c     lui        a3,0xfff0
        80011d7c 0b 80 02 3c     lui        v0,0x800b
        80011d80 50 7e 45 24     addiu      a1,v0,0x7e50
I'm a bit stuck from here, have been looking for a few days but I suppose I have some questions

From what I can tell in the cue, the STR folder does exist in the file system for the disk, but are these files referenced by their addresses as opposed to using the file system to search for the files?

Have I gone completely off track and this is actually a trivial problem?

Does anyone have any advice on where I should go from here? (Aside from give up lol)

I can probably update the addresses in a hex editor once I've located them in Ghidra, from what I can tell I can edit the instruction assembly in Ghidra and then use the new hex to patch the old. But I'm concerned about how do I know what the new correct address is with repacking the BIN file? Any recommendations here on how I can solve this particular issue?

I'm trying to catch up on domain knowledge here but it's very difficult, however, the information in this community has been incredible and I'm extremely thankful for this. This has been a lot of fun, and has motivated me to look into porting some of the tools that I can to rust or similar to keep them alive. Was hoping to do that XA converter I've been using but the source isn't available and decompiling / importing delphi c++ apps has been more difficult than Ape Escape so far haha

User avatar
inc^lightforce
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 248
Joined: Mar 07, 2013
I am a: Programmer Windows+PS1, GFX Artist
PlayStation Model: Black
Location: Germany

Post by inc^lightforce » September 12th, 2021, 9:11 am

i never tried this, but have you thoughts about this:

unpack the game iso.
replace the US voice files with the EU voice files (watch out for the file names, must be the same like the one in the NTSC US version)

now i would try: PSX ISO GAME BUILDER

after the process you should have a correct bin and cue on your HDD.

not sure, just thoughts ...

Stasis
Interested PSXDEV User
Interested PSXDEV User
Posts: 5
Joined: Sep 08, 2021
PlayStation Model: SCPH-5500
Location: New Zealand

Post by Stasis » September 12th, 2021, 12:16 pm

inc^lightforce wrote: September 12th, 2021, 9:11 am i never tried this, but have you thoughts about this:

unpack the game iso.
replace the US voice files with the EU voice files (watch out for the file names, must be the same like the one in the NTSC US version)

now i would try: PSX ISO GAME BUILDER

after the process you should have a correct bin and cue on your HDD.

not sure, just thoughts ...
Yup have done the equivalent. I did retry all of this using cdmage which seemingly does a more accurate extraction than what I might have been doing otherwise.

Unpacking the files then repacking with PSX ISO builder results in a disk that hangs after the psx logo.

Also retried psx-mode2 (was meant to say I was using this to repack disks, not fisgon)
Using the reextracted files I attempted to replace the STEXP voice pack with the EU one directly again:

Code: Select all

psx-mode2 $ .\psx-mode2-en.exe '.\Ape Escape (USA).bin' /STR/STEXP.STR .\STEXP.STR
Which results in an cue/bin that boots into the game correctly, but when it comes time for the professor to speak, he leaves us with a chilling silence :lol:

I suspect the hardcoded values from before mean that it does reference the data by location as opposed to using the file system, although these addresses might also refer to data position in the DAT file itself. Hmm.

User avatar
inc^lightforce
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 248
Joined: Mar 07, 2013
I am a: Programmer Windows+PS1, GFX Artist
PlayStation Model: Black
Location: Germany

Post by inc^lightforce » September 12th, 2021, 11:31 pm

I'm in since 1998. Can you provide both bin/cue Version? Not sure if one of them or both was also copy protected with libcrypt 2. If yes, it won't work the usual way.
In this case, hard coding is the magic.
This could also explain your first try that ended up into the Black screen.

Btw. On real Hardware, a mod chip is always needed.

Let me have a look at the 1:1 non touched pal and ntsc bin/cue. I need a link pls.

Stasis
Interested PSXDEV User
Interested PSXDEV User
Posts: 5
Joined: Sep 08, 2021
PlayStation Model: SCPH-5500
Location: New Zealand

Post by Stasis » September 13th, 2021, 1:00 am

inc^lightforce wrote: September 12th, 2021, 11:31 pm I'm in since 1998. Can you provide both bin/cue Version? Not sure if one of them or both was also copy protected with libcrypt 2. If yes, it won't work the usual way.
In this case, hard coding is the magic.
This could also explain your first try that ended up into the Black screen.

Btw. On real Hardware, a mod chip is always needed.

Let me have a look at the 1:1 non touched pal and ntsc bin/cue. I need a link pls.
You're a real veteran! I'll send you a DM with some details.

I've been testing this on a ps1 I modded with xstation and a ps1digital, as well as no$psx and duckstation.

Would love to get your input :) I've been investigating that method I found a bit more with ghidra and it's interesting:

Code: Select all


int FUN_80011cf8(void)

{
  CdlFILE *cd_search_result;
  int pos_to_int_sector;
  int cd_op_status;
  int *piVar1;
  uint *puVar2;
  CdlFILE f;
  byte local_20 [8];
  u_char auStack24 [8];
  
  do {
    cd_search_result = CdSearchFile(&f,"\\KKIIDDZZ.HED;1");
  } while (cd_search_result == (CdlFILE *)0x0);
  pos_to_int_sector = CdPosToInt(&f.pos);
  do {
    cd_op_status = CdControl(CdlSetloc,(u_char *)&f,(u_char *)0x0);
  } while (cd_op_status == 0);
  do {
    cd_op_status = CdRead(1,&DAT_800b7e50,CdlModeSpeed);
  } while (cd_op_status == 0);
  CdReadSync(0,auStack24);
  cd_op_status = 0;
  puVar2 = &DAT_800b7e50;
  do {
    cd_op_status = cd_op_status + 1;
    *puVar2 = *puVar2 & 0xfff00000 | (*puVar2 & 0xfffff) + 1 + pos_to_int_sector & 0xfffff;
    puVar2 = puVar2 + 1;
  } while (cd_op_status < 0x1c0);
  FUN_80012c0c((char *)&f,0x1c5);
  pos_to_int_sector = CdPosToInt(&f.pos);
  cd_op_status = 4;
  piVar1 = &DAT_800a8560;
  do {
    *piVar1 = pos_to_int_sector;
    cd_op_status = cd_op_status + 1;
    piVar1 = piVar1 + 3;
  } while (cd_op_status < 0x10);
  FUN_80012c0c((char *)&f,0x1c4);
  pos_to_int_sector = CdPosToInt(&f.pos);
  cd_op_status = 0x10;
  piVar1 = &DAT_800a85f0;
  do {
    *piVar1 = pos_to_int_sector;
    cd_op_status = cd_op_status + 1;
    piVar1 = piVar1 + 3;
  } while (cd_op_status < 0x18);
  FUN_80012c0c((char *)&f,0x1c1);
  pos_to_int_sector = CdPosToInt(&f.pos);
  cd_op_status = 0x18;
  piVar1 = &DAT_800a8650;
  do {
    *piVar1 = pos_to_int_sector;
    cd_op_status = cd_op_status + 1;
    piVar1 = piVar1 + 3;
  } while (cd_op_status < 0x1f);
  FUN_80012c0c((char *)&f,0x1c0);
  pos_to_int_sector = CdPosToInt(&f.pos);
  cd_op_status = 0x1f;
  piVar1 = &DAT_800a86a4;
  do {
    *piVar1 = pos_to_int_sector;
    cd_op_status = cd_op_status + 1;
    piVar1 = piVar1 + 3;
  } while (cd_op_status < 0x2b);
  FUN_80012c0c((char *)&f,0x1c2);
  pos_to_int_sector = CdPosToInt(&f.pos);
  cd_op_status = 0x2b;
  piVar1 = &DAT_800a8734;
  do {
    *piVar1 = pos_to_int_sector;
    cd_op_status = cd_op_status + 1;
    piVar1 = piVar1 + 3;
  } while (cd_op_status < 0x33);
  FUN_80012c0c((char *)&f,0x1c3);
  pos_to_int_sector = CdPosToInt(&f.pos);
  cd_op_status = 0x33;
  piVar1 = &DAT_800a8794;
  do {
    *piVar1 = pos_to_int_sector;
    cd_op_status = cd_op_status + 1;
    piVar1 = piVar1 + 3;
  } while (cd_op_status < 0x3a);
  local_20[0] = 200;
  do {
    pos_to_int_sector = CdControlB(CdlSetmode,local_20,(undefined *)0x0);
  } while (pos_to_int_sector == 0);
  do {
    pos_to_int_sector = CdControlB(CdlDemute,(byte *)0x0,(undefined *)0x0);
  } while (pos_to_int_sector == 0);
  return 0;
}
Slowly making progress on at least getting this function deciphered, appears to read in data starting at the physical position of the header, various bit masking and operations would either lead me to think of some encryption or compression on the data. If that's the case, it may well be that the data I'm trying to update the references for is encrypted in the header or dat file.

Edit: Should have mentioned, libcrypt only on the pal version, so should be okay since we're trying to get to ntsc

Stasis
Interested PSXDEV User
Interested PSXDEV User
Posts: 5
Joined: Sep 08, 2021
PlayStation Model: SCPH-5500
Location: New Zealand

Post by Stasis » September 17th, 2021, 11:07 am

Haven't made much mode progress yet, ended up building a new pc and setting up my entire dev environment again is painful lol. I did wonder if this method I'm deciphering is purely to unpack the DAT file opposed to the audio though, looks likely

User avatar
inc^lightforce
Verified
Psy-Q Enthusiast
Psy-Q Enthusiast
Posts: 248
Joined: Mar 07, 2013
I am a: Programmer Windows+PS1, GFX Artist
PlayStation Model: Black
Location: Germany

Post by inc^lightforce » September 22nd, 2021, 4:53 am

I set up my original dev sdk with real Hardware to be able, sending the code instantly to the dev PlayStation to see what's going on and also have the open debug Window at the same time.
Make things way easier with real Hardware

Update soon.

Stasis
Interested PSXDEV User
Interested PSXDEV User
Posts: 5
Joined: Sep 08, 2021
PlayStation Model: SCPH-5500
Location: New Zealand

Post by Stasis » September 22nd, 2021, 9:22 am

Looking forward to hearing your findings! Thank you!

That workflow sounds a lot better than mine lol

Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests