-
Posts
425 -
Joined
-
Last visited
-
Days Won
1
Content Type
Profiles
Pokédex
Portal
Technical Documentation
Pages
Tutorials
Forums
Events
Downloads
Gallery
Blogs
Everything posted by psy_commando
-
Did you get cubic ninja to do that ? 0_o Well that's a departure from how the NDS works.. I didn't really mean to imply it could be used to exploit the system itself. But still that was kinda awkward on my part ^^; I just can't think today.. I've spent 4 hours going step-by-step through the sound driver's code trying to figure out how to get an amplitude value out of the values in the SWD file, and my brain is like jello now.. But now that I think of it, do you think you could try to decompile one of the lua script file, for say, the top menu, and replace the compiled script with it ? And then repack the rom, and run it ? I'd like to know if the lua interpreter in the game is fully capable of loading lua scripts that aren't compiled, or if it has been crippled or something. Because I doubt we'd be able to recompile the scripts properly. And if you have time, if you go into "script\menu", there is a file named "menu_dungeon_debug.lua" with a function named "OpenDungeonDebugMenu()". I was wondering if you could try to put a call to that function somewhere during the gameplay ? And try to mess around with that ? There are lua functions for literally everything in the game, and a lot of debug scripts are still lying around ! Nearly the whole game runs in the lua engine!
-
PMD:GTI has been out for a long while. And well the title is basically : I guess my intro text kinda overlooked that part though But PSMD will most likely have the exact same engine with a few differences. Etrian Mystery Dungeon was largely the same as PMD:GTI, and its a completely different franchise that works differently than pokemon. Chunsoft is still using the SIR0 format which they've been using since Red Rescue Team on the GBA. So something tells me they're not about to change everything Besides, if the engine is actually all different, whatever we find can still be used for PMD:GTI. I thought gateway only worked on a few firmwares ? Isn't the ARM9 only for running NDS games, and doesn't it runs into its own little sandbox? Just wondering, because up to date 3ds info is hard to come by I know that ironhax is limited to usermode, but its really better than nothing. Especially if people manage to find a kernel mode exploit, having at least access to user mode homebrew would probably be a plus. And well, you can still access the SD card and etc. Maybe there's a chance we can find an exploit in PSMD or GTI to inject stuff in memory or run a basic debugger or something ? Honestly, SIR0 files seem like something easily exploitable, because with the pointer translation table, you can literally manipulate pointers in the game's memory! That actually caused a huge bug in one of my utilities for a while, and it caused all kinds of really messed up effects in the game. In the past, overflow errors with c strings for example have been used as exploit vectors to write in memory in spots where they wanted to. Like that missingno glitch in red/blue with the trainer name and inventory and the old tutorial guy.
-
Portraits are stored uncompressed in face_graphic.bin. Here are my notes on the file : EDIT: The notes below are wrong/outdated! The FARC header mainly.. [font=Fixedsys] face_graphic.bin The file contains all the character portraits used in the game. It contains several sub-files stored within a FARC container. ============================================================ Overview ============================================================ FARC chunks appear to be archive of some sort. They're fairly straightforward apparently. Offset Name Size Type Description ---------- ---- ---- ---- ----------- FARCHeader vary - Header for the FARC archive format. [ 0x00 magicn 4 - The 4 ASCII letters "FARC" { 0x46, 0x41, 0x52, 0x43 } 0x04 unktbl 28 - Unknown content. [] 0x20 nbentries 4 int32 The nb of entries in the subfiletbl ???? 0x24 subfiletbl (nbentries * 4) uint32[] A table with offsets between all sub files. To get the actual offset to a subfile you need to add all the previous offset! They're relative to the beining of the file! [ foffset 4 uint32 Offset from last sub-file of a sub-file! ... ] padbytes vary - A certain amount of padding bytes. Must be a multiple of 4. ] subfiledata vary - Contains the data for all sub-files mentioned in the subfiletbl. [] ============================================================ Portrait Pointers Table ============================================================ This SIR0 chunk contains a list of 16bits character null terminated strings, along with a table associating those strings to the offsets of each portraits. Offset + Name Size Type Description ----------- ---- ---- ---- ----------- SIR0Header 16 - The standard SIR0 header. [ 0x00 magicn 4 - "SIR0" 0x04 subhdrptr 4 uint32 Pointer to the sub-header. 0x08 ptroffsettblptr 4 uint32 Points to the SIR0 encoded pointer offset table. 0x0C null 4 - Terminating zeroes. ] strtable vary - A table containing 16 bits character strings. Each strings is the filename of a pokemon portrait. [ Entry [ portraitstr vary wchar[] A null terminated wchar string. padchar 0-2 wchar If the string ends on an offset not 4 bytes aligned, a single wchar is added to align the next string on 4 bytes! ] ... ] portraittbl (nbportraits * 16) - A table containing details on all the portraits in the game. [ pentry [ stroffset 4 uint32 An offset to the name string for this portrait. portraitoffset 4 uint32 An offset to the potrait's image data from the portrait data chunk's beginning. portraitsz 4 uint32 The size of the portrait image in bytes. null 4 - 4 bytes of zeroes. ] ... ] subhdr 16 - The sub-header. [ 0x00 portraittblptr 4 uint32 A pointer to the beginning of the portrait data table. 0x04 nbportraits 4 uint32 The nb of portrait entries in the portraittbl! 0x08 null 8 - 8 bytes of zeros. ] ptroffsettbl vary - The standard SIR0 pointer offset table. [] ============================================================ Portrait Image Data ============================================================ Stored in the sub-file after the SIR0 portrait table. Images are 24bits, rgb, tiled. They're flipped vertically upside down. I suspect they're 64x64 pixels. I can't figure the exact tile size right now. 8x8 does not works. [/font] I can't figure the correct image format for some reasons.. I've had similar results when trying to figure out PXD's portraits formats. But for some reasons I can't get those to work.. Examples (Archen is the first portrait in the list for some reasons..): As you can see, there is something odd going on here.. In that image the portrait was interpreted as a 64x64, rgb24, tiled 8x8, vertically flipped image. But the rows are all weird... Any suggestions ?
-
Its all good. And no problems And I see now what you're talking about ! That's a part of the DSE sound driver memory. All the addresses in the R2 registers you listed are within the "mseq" chunk at 0x2291C70. And all the addresses in the R3 registers are within the "mdev" chunk at 0x22921E0. Those structures are right after the main bank's sample list in memory. If you look at offset 0x228C6C0 there's the wavi chunk for all the samples used by music in the game!(It would probably move in memory if the system sound effects and bank would change size though. ) And the reason I was mentioning the volume envelopes, is because the volume for notes is calculated along with the volume envelope, so you'll probably end up stumbling on the part where they're combined together into a single volume value. Also I finally finished the list of all the events and the code for their event handler I had been working on. It also made me realize that events 0x80 to 0x8F are actually delay events, and not really delta-time prefixes. I can say that because their value is put into the "last pause" variable in memory. So event 0x90 can repeat the last 0x80-0x8F event, for example. There's still more work to do to detail it, but if we can figure what all of those do, we'll get 100% DSE events support! : [font=Fixedsys]//==================================================== // Event-Specific Handling Functions //==================================================== // ---- Event 0x90 (Address 02071928) ---- 02071928 E5921010 ldr r1,[r2,10h] //Load last delay 0207192C E582100C str r1,[r2,0Ch] //Set as current delay 02071930 E12FFF1E bx r14 // ---- Event 0x91 (Address 02071934) ---- 02071934 E0D010D1 ldrsb r1,[r0],1h //Increment read pos, and read next track byte into R1 02071938 E5923010 ldr r3,[r2,10h] //Load last delay 0207193C E0831001 add r1,r3,r1 //Add last delay to the delay byte we read 02071940 E5821010 str r1,[r2,10h] //Write last delay 02071944 E582100C str r1,[r2,0Ch] //Set as current delay 02071948 E12FFF1E bx r14 // ---- Event 0x92 (Address 0207194C) ---- 0207194C E4D01001 ldrb r1,[r0],1h //Increment read pos, and read next track byte into R1 02071950 E5821010 str r1,[r2,10h] //Write last delay 02071954 E582100C str r1,[r2,0Ch] //Set as current delay 02071958 E12FFF1E bx r14 // ---- Event 0x93 (Address 0207195C) ---- 0207195C E5D03000 ldrb r3,[r0] //Read the next byte 02071960 E5D01001 ldrb r1,[r0,1h] //Read the next byte 02071964 E2800002 add r0,r0,2h //Increment read pos 02071968 E0831401 add r1,r3,r1,lsl 8h //Assemble a int16 with the 2 bytes 0207196C E5821010 str r1,[r2,10h] //Write last delay 02071970 E582100C str r1,[r2,0Ch] //Set as current delay 02071974 E12FFF1E bx r14 // ---- Event 0x94 (Address 02071978) ---- 02071978 E5D03000 ldrb r3,[r0] //Read the next byte 0207197C E5D01001 ldrb r1,[r0,1h] //Read the next byte 02071980 E5D0C002 ldrb r12,[r0,2h] //Read the next byte 02071984 E2800003 add r0,r0,3h //Increment read pos 02071988 E0831401 add r1,r3,r1,lsl 8h //Assemble a int16 with the 2 bytes 0207198C E081180C add r1,r1,r12,lsl 10h //Assemble a int32 with the 2 bytes 02071990 E5821010 str r1,[r2,10h] //Write last delay 02071994 E582100C str r1,[r2,0Ch] //Set as current delay 02071998 E12FFF1E bx r14 // ---- Event 0x95 (Address 0207199C) ---- 0207199C E92D4038 push r3-r5,r14 020719A0 E1A05000 mov r5,r0 020719A4 E1A00003 mov r0,r3 020719A8 E1A04002 mov r4,r2 020719AC EB000C1E bl 2074A2Ch 020719B0 E3500000 cmp r0,0h if( R0 > 0 ) 020719B4 C4550001 ldrgtb r0,[r5],-1h if( R0 <= 0 ) 020719B8 D2855001 addle r5,r5,1h if( R0 > 0 ) 020719BC C584000C strgt r0,[r4,0Ch] 020719C0 E1A00005 mov r0,r5 020719C4 E8BD8038 pop r3-r5,r15 // ---- Event 0x96 (Address 0207191C) ---- 0207191C E3A01000 mov r1,0h 02071920 E5C21002 strb r1,[r2,2h] 02071924 E12FFF1E bx r14 // ---- Event 0x97 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0x98 (Address 020719C8) ---- 020719C8 E92D4010 push r4,r14 020719CC E592C020 ldr r12,[r2,20h] 020719D0 E1A04000 mov r4,r0 020719D4 E35C0000 cmp r12,0h if( R12 != 0 ) 020719D8 1A000005 bne 20719F4h 020719DC E3A01000 mov r1,0h 020719E0 E1A00003 mov r0,r3 020719E4 E5C21002 strb r1,[r2,2h] 020719E8 E2444001 sub r4,r4,1h 020719EC EB000827 bl 2073A90h 020719F0 EA000005 b 2071A0Ch 020719F4 E1D230BA ldrh r3,[r2,0Ah] 020719F8 E3A00001 mov r0,1h 020719FC E2833001 add r3,r3,1h 02071A00 E1C230BA strh r3,[r2,0Ah] 02071A04 E5C10003 strb r0,[r1,3h] 02071A08 E5924020 ldr r4,[r2,20h] 02071A0C E1A00004 mov r0,r4 02071A10 E8BD8010 pop r4,r15 // ---- Event 0x99 SetLoopPoint (Address 02071A14) ---- 02071A14 E5820020 str r0,[r2,20h] //Set current track pointer as loop pos 02071A18 E12FFF1E bx r14 // ---- Event 0x9A (Address 0207191C) ---- //Same as 0x96 // ---- Event 0x9B (Address 0207191C) ---- //Same as 0x96 // ---- Event 0x9C (Address 02071A1C) ---- 02071A1C E92D4010 push r4,r14 02071A20 E5D24006 ldrb r4,[r2,6h] 02071A24 E3A0100C mov r1,0Ch 02071A28 E4D0E001 ldrb r14,[r0],1h //Read next byte and increment read ptr 02071A2C E1610184 smulbb r1,r4,r1 02071A30 E2823024 add r3,r2,24h 02071A34 E7830001 str r0,[r3,r1] 02071A38 E083C001 add r12,r3,r1 02071A3C E3A01000 mov r1,0h 02071A40 E58C1004 str r1,[r12,4h] 02071A44 E5CCE008 strb r14,[r12,8h] 02071A48 E5D23004 ldrb r3,[r2,4h] 02071A4C E2841001 add r1,r4,1h 02071A50 E5CC3009 strb r3,[r12,9h] 02071A54 E5C21006 strb r1,[r2,6h] 02071A58 E8BD8010 pop r4,r15 // ---- Event 0x9D (Address 02071A5C) ---- 02071A5C E5D2C006 ldrb r12,[r2,6h] 02071A60 E2823024 add r3,r2,24h 02071A64 E3A0100C mov r1,0Ch 02071A68 E24CC001 sub r12,r12,1h 02071A6C E023319C mla r3,r12,r1,r3 02071A70 E5D31008 ldrb r1,[r3,8h] 02071A74 E2511001 subs r1,r1,1h if( R1 == 0 ) { 02071A78 05C2C006 streqb r12,[r2,6h] 02071A7C 012FFF1E bxeq r14 } 02071A80 E5830004 str r0,[r3,4h] 02071A84 E5C31008 strb r1,[r3,8h] 02071A88 E5D30009 ldrb r0,[r3,9h] 02071A8C E5C20004 strb r0,[r2,4h] 02071A90 E5930000 ldr r0,[r3] 02071A94 E12FFF1E bx r14 // ---- Event 0x9E (Address 02071A98) ---- 02071A98 E5D2C006 ldrb r12,[r2,6h] 02071A9C E2823024 add r3,r2,24h 02071AA0 E3A0100C mov r1,0Ch 02071AA4 E24CC001 sub r12,r12,1h 02071AA8 E023319C mla r3,r12,r1,r3 02071AAC E5D31008 ldrb r1,[r3,8h] 02071AB0 E2511001 subs r1,r1,1h if( R1 == 0 ) { 02071AB4 05930004 ldreq r0,[r3,4h] 02071AB8 05C2C006 streqb r12,[r2,6h] } 02071ABC E12FFF1E bx r14 // ---- Event 0x9F (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xA0 (Address 2071AC0) ---- 02071AC0 E4D01001 ldrb r1,[r0],1h //Reads the parameter byte. And increment read position. 02071AC4 E5C21004 strb r1,[r2,4h] //Store TrackOctave at 0x2291D88 [2291D88]!? 02071AC8 E12FFF1E bx r14 //Return to main event handling function // ---- Event 0xA1 (Address 02071ACC) ---- 02071ACC E5D23004 ldrb r3,[r2,4h] 02071AD0 E0D010D1 ldrsb r1,[r0],1h 02071AD4 E0831001 add r1,r3,r1 02071AD8 E5C21004 strb r1,[r2,4h] 02071ADC E12FFF1E bx r14 // ---- Event 0xA2 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xA3 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xA4 (Address 02071AE0) ---- 02071AE0 E92D4070 push r4-r6,r14 02071AE4 E1A06000 mov r6,r0 02071AE8 E1A05001 mov r5,r1 02071AEC E5950048 ldr r0,[r5,48h] 02071AF0 E5D64000 ldrb r4,[r6] 02071AF4 E1A00840 mov r0,r0,asr 10h 02071AF8 E0010490 mul r1,r0,r4 02071AFC E1B01421 movs r1,r1,lsr 8h 02071B00 E59F0014 ldr r0,=3938700h if( R1 == 0 ) 02071B04 03A01001 moveq r1,1h 02071B08 EB007968 bl 20900B0h 02071B0C E5850044 str r0,[r5,44h] 02071B10 E5C54017 strb r4,[r5,17h] 02071B14 E2860001 add r0,r6,1h 02071B18 E8BD8070 pop r4-r6,r15 // ---- Event 0xA5 (Address 02071B20) ---- 02071B20 E92D4070 push r4-r6,r14 02071B24 E1A06000 mov r6,r0 02071B28 E1A05001 mov r5,r1 02071B2C E5950048 ldr r0,[r5,48h] 02071B30 E5D64000 ldrb r4,[r6] 02071B34 E1A00840 mov r0,r0,asr 10h 02071B38 E0010490 mul r1,r0,r4 02071B3C E1B01421 movs r1,r1,lsr 8h 02071B40 E59F0014 ldr r0,=3938700h if( R1 == 0 ) 02071B44 03A01001 moveq r1,1h 02071B48 EB007958 bl 20900B0h 02071B4C E5850044 str r0,[r5,44h] 02071B50 E5C54017 strb r4,[r5,17h] 02071B54 E2860001 add r0,r6,1h 02071B58 E8BD8070 pop r4-r6,r15 // ---- Event 0xA6 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xA7 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xA8 (Address 02071B60) ---- 02071B60 E92D4010 push r4,r14 02071B64 E1A04000 mov r4,r0 02071B68 E5D42000 ldrb r2,[r4] 02071B6C E5D41001 ldrb r1,[r4,1h] 02071B70 E1A00003 mov r0,r3 02071B74 E0811402 add r1,r1,r2,lsl 8h 02071B78 E1A01801 mov r1,r1,lsl 10h 02071B7C E1A01821 mov r1,r1,lsr 10h 02071B80 EB000802 bl 2073B90h 02071B84 E2840002 add r0,r4,2h 02071B88 E8BD8010 pop r4,r15 // ---- Event 0xA9 (Address 02071B8C) ---- 02071B8C E92D4010 push r4,r14 02071B90 E1A04000 mov r4,r0 02071B94 E1D310BE ldrh r1,[r3,0Eh] 02071B98 E5D42000 ldrb r2,[r4] 02071B9C E1A00003 mov r0,r3 02071BA0 E20110FF and r1,r1,0FFh 02071BA4 E0811402 add r1,r1,r2,lsl 8h 02071BA8 E1A01801 mov r1,r1,lsl 10h 02071BAC E1A01821 mov r1,r1,lsr 10h 02071BB0 EB0007F6 bl 2073B90h 02071BB4 E2840001 add r0,r4,1h 02071BB8 E8BD8010 pop r4,r15 // ---- Event 0xAA (Address 02071BBC) ---- 02071BBC E92D4010 push r4,r14 02071BC0 E1A04000 mov r4,r0 02071BC4 E1D320BE ldrh r2,[r3,0Eh] 02071BC8 E5D41000 ldrb r1,[r4] 02071BCC E1A00003 mov r0,r3 02071BD0 E3C220FF bic r2,r2,0FFh 02071BD4 E0821001 add r1,r2,r1 02071BD8 E1A01801 mov r1,r1,lsl 10h 02071BDC E1A01821 mov r1,r1,lsr 10h 02071BE0 EB0007EA bl 2073B90h 02071BE4 E2840001 add r0,r4,1h 02071BE8 E8BD8010 pop r4,r15 // ---- Event 0xAB (Address 02071BEC) ---- 02071BEC E2800001 add r0,r0,1h 02071BF0 E12FFF1E bx r14 // ---- Event 0xAC (Address 02071BF4) ---- 02071BF4 E92D4070 push r4-r6,r14 02071BF8 E1A06000 mov r6,r0 02071BFC E1A05001 mov r5,r1 02071C00 E1A04003 mov r4,r3 02071C04 E5D61000 ldrb r1,[r6] 02071C08 E1A00004 mov r0,r4 02071C0C EB0007ED bl 2073BC8h 02071C10 E1B02000 movs r2,r0 02071C14 5A000006 bpl 2071C34h 02071C18 E1D410BE ldrh r1,[r4,0Eh] 02071C1C E5950028 ldr r0,[r5,28h] 02071C20 E59530A0 ldr r3,[r5,0A0h] 02071C24 E595C09C ldr r12,[r5,9Ch] 02071C28 E0622801 rsb r2,r2,r1,lsl 10h 02071C2C E3E010CB mvn r1,0CBh 02071C30 E12FFF3C blx r12 // ---- Event 0xAD (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xAE (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xAF (Address 02071C3C) ---- 02071C3C E92D4070 push r4-r6,r14 02071C40 E1A05000 mov r5,r0 02071C44 E5D52000 ldrb r2,[r5] 02071C48 E5D50001 ldrb r0,[r5,1h] 02071C4C E1A04001 mov r4,r1 02071C50 E0820400 add r0,r2,r0,lsl 8h 02071C54 E1A00800 mov r0,r0,lsl 10h 02071C58 E1B01820 movs r1,r0,lsr 10h if( R1 == 0 ) { 02071C5C 03A06000 moveq r6,0h 02071C60 0A000007 beq 2071C84h } 02071C64 E3A00FFA mov r0,3E8h 02071C68 E0000091 mul r0,r1,r0 02071C6C E59F1050 ldr r1,=22B7330h 02071C70 E1D112F8 ldrsh r1,[r1,28h] 02071C74 EB00790D bl 20900B0h 02071C78 E1A00800 mov r0,r0,lsl 10h 02071C7C E1B06820 movs r6,r0,lsr 10h if( R6 == 0 ) 02071C80 03A06001 moveq r6,1h 02071C84 E5D50002 ldrb r0,[r5,2h] 02071C88 E3560000 cmp r6,0h 02071C8C E1A01800 mov r1,r0,lsl 10h 02071C90 E5841070 str r1,[r4,70h] if( R6 == 0 ) { 02071C94 05841068 streq r1,[r4,68h] 02071C98 0A000006 beq 2071CB8h } 02071C9C E5940068 ldr r0,[r4,68h] 02071CA0 E0510000 subs r0,r1,r0 if( R0 == 0 ) { 02071CA4 03A06000 moveq r6,0h 02071CA8 0A000002 beq 2071CB8h } 02071CAC E1A01006 mov r1,r6 02071CB0 EB00787B bl 208FEA4h 02071CB4 E584006C str r0,[r4,6Ch] 02071CB8 E1C467B4 strh r6,[r4,74h] 02071CBC E2850003 add r0,r5,3h 02071CC0 E8BD8070 pop r4-r6,r15 // ---- Event 0xB0 (Address 02071CC8) ---- 02071CC8 E92D4010 push r4,r14 02071CCC E1A04000 mov r4,r0 02071CD0 E2830064 add r0,r3,64h 02071CD4 EB000BEA bl 2074C84h 02071CD8 E1A00004 mov r0,r4 02071CDC E8BD8010 pop r4,r15 // ---- Event 0xB1 (Address 02071CE0) ---- 02071CE0 E92D4010 push r4,r14 02071CE4 E1A04000 mov r4,r0 02071CE8 E5D41000 ldrb r1,[r4] 02071CEC E2830064 add r0,r3,64h 02071CF0 E5C3106C strb r1,[r3,6Ch] 02071CF4 EB000BE9 bl 2074CA0h 02071CF8 E2840001 add r0,r4,1h 02071CFC E8BD8010 pop r4,r15 // ---- Event 0xB2 (Address 02071D00) ---- 02071D00 E92D4010 push r4,r14 02071D04 E1A04000 mov r4,r0 02071D08 E5D41000 ldrb r1,[r4] 02071D0C E2830064 add r0,r3,64h 02071D10 E5C3106D strb r1,[r3,6Dh] 02071D14 EB000BE1 bl 2074CA0h 02071D18 E2840001 add r0,r4,1h 02071D1C E8BD8010 pop r4,r15 // ---- Event 0xB3 (Address 02071D20) ---- 02071D20 E92D4010 push r4,r14 02071D24 E1A04000 mov r4,r0 02071D28 E5D41000 ldrb r1,[r4] 02071D2C E2830064 add r0,r3,64h 02071D30 E5C31070 strb r1,[r3,70h] 02071D34 EB000BD9 bl 2074CA0h 02071D38 E2840001 add r0,r4,1h 02071D3C E8BD8010 pop r4,r15 // ---- Event 0xB4 (Address 02071D40) ---- 02071D40 E92D4010 push r4,r14 02071D44 E1A04000 mov r4,r0 02071D48 E5D40000 ldrb r0,[r4] 02071D4C E35000FF cmp r0,0FFh if( (R0 & 0xFF) != 0 ) 02071D50 15C3006E strneb r0,[r3,6Eh] 02071D54 E5D40001 ldrb r0,[r4,1h] 02071D58 E35000FF cmp r0,0FFh if( (R0 & 0xFF) != 0 ) 02071D5C 15C3006F strneb r0,[r3,6Fh] 02071D60 E2830064 add r0,r3,64h 02071D64 EB000BCD bl 2074CA0h 02071D68 E2840002 add r0,r4,2h 02071D6C E8BD8010 pop r4,r15 // ---- Event 0xB5 (Address 02071D70) ---- 02071D70 E92D4010 push r4,r14 02071D74 E1A04000 mov r4,r0 02071D78 E5D41000 ldrb r1,[r4] 02071D7C E2830064 add r0,r3,64h 02071D80 E5C31071 strb r1,[r3,71h] 02071D84 EB000BC5 bl 2074CA0h 02071D88 E2840001 add r0,r4,1h 02071D8C E8BD8010 pop r4,r15 // ---- Event 0xB6 (Address 02071D90) ---- 02071D90 E92D4010 push r4,r14 02071D94 E1A04000 mov r4,r0 02071D98 E5D41000 ldrb r1,[r4] 02071D9C E2830064 add r0,r3,64h 02071DA0 E5C31072 strb r1,[r3,72h] 02071DA4 EB000BBD bl 2074CA0h 02071DA8 E2840001 add r0,r4,1h 02071DAC E8BD8010 pop r4,r15 // ---- Event 0xB7 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xB8 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xB9 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xBA (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xBB (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xBC (Address 02071DB0) ---- 02071DB0 E4D01001 ldrb r1,[r0],1h 02071DB4 E5C21005 strb r1,[r2,5h] 02071DB8 E12FFF1E bx r14 // ---- Event 0xBD (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xBE (Address 02071DBC) ---- 02071DBC E92D4010 push r4,r14 02071DC0 E1A04000 mov r4,r0 02071DC4 E1D410D0 ldrsb r1,[r4] 02071DC8 E1A00003 mov r0,r3 02071DCC EB0007A2 bl 2073C5Ch 02071DD0 E2840001 add r0,r4,1h 02071DD4 E8BD8010 pop r4,r15 // ---- Event 0xBF (Address 02071DD8) ---- 02071DD8 E92D4010 push r4,r14 02071DDC E1A04000 mov r4,r0 02071DE0 E5D41000 ldrb r1,[r4] 02071DE4 E5920054 ldr r0,[r2,54h] 02071DE8 E3510040 cmp r1,40h 02071DEC E5D01004 ldrb r1,[r0,4h] if( R1 >= 0x40 )//unsigned { 02071DF0 23811001 orrcs r1,r1,1h 02071DF4 25C01004 strcsb r1,[r0,4h] 02071DF8 2A000002 bcs 2071E08h } 02071DFC E3C11001 bic r1,r1,1h 02071E00 E5C01004 strb r1,[r0,4h] 02071E04 EB000A74 bl 20747DCh 02071E08 E2840001 add r0,r4,1h 02071E0C E8BD8010 pop r4,r15 // ---- Event 0xC0 (Address 02071E10) ---- 02071E10 E5D31004 ldrb r1,[r3,4h] 02071E14 E3811002 orr r1,r1,2h 02071E18 E5C31004 strb r1,[r3,4h] 02071E1C E12FFF1E bx r14 // ---- Event 0xC1 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xC2 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xC3 (Address 02071E20) ---- 02071E20 E4D01001 ldrb r1,[r0],1h 02071E24 E5C31058 strb r1,[r3,58h] 02071E28 E12FFF1E bx r14 // ---- Event 0xC4 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xC5 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xC6 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xC7 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xC8 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xC9 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xCA (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xCB (Address 02071E20) ---- 02071E2C E2800002 add r0,r0,2h 02071E30 E12FFF1E bx r14 // ---- Event 0xCC (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xCD (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xCE (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xCF (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xD0 (Address 02071E34) ---- 02071E34 E92D4010 push r4,r14 02071E38 E1D010D0 ldrsb r1,[r0] 02071E3C E59FC06C ldr r12,=4000208h 02071E40 E3A02000 mov r2,0h 02071E44 E1A01C01 mov r1,r1,lsl 18h 02071E48 E1A04841 mov r4,r1,asr 10h 02071E4C E1C345B4 strh r4,[r3,54h] 02071E50 E593E0C4 ldr r14,[r3,0C4h] 02071E54 E593101C ldr r1,[r3,1Ch] 02071E58 E1DEE0F4 ldrsh r14,[r14,4h] 02071E5C E1A01841 mov r1,r1,asr 10h 02071E60 E1A01801 mov r1,r1,lsl 10h 02071E64 E0841841 add r1,r4,r1,asr 10h 02071E68 E08E1001 add r1,r14,r1 02071E6C E1C311B6 strh r1,[r3,16h] 02071E70 E1DC40B0 ldrh r4,[r12] 02071E74 E1CC20B0 strh r2,[r12] 02071E78 E59320B4 ldr r2,[r3,0B4h] 02071E7C E3520000 cmp r2,0h if( R2 == 0 ) 02071E80 0A000005 beq 2071E9Ch 02071E84 E1D210B6 ldrh r1,[r2,6h] 02071E88 E3811010 orr r1,r1,10h 02071E8C E1C210B6 strh r1,[r2,6h] 02071E90 E5922154 ldr r2,[r2,154h] 02071E94 E3520000 cmp r2,0h if( R2 != 0 ) 02071E98 1AFFFFF9 bne 2071E84h 02071E9C E59F200C ldr r2,=4000208h 02071EA0 E2800001 add r0,r0,1h 02071EA4 E1D210B0 ldrh r1,[r2] 02071EA8 E1C240B0 strh r4,[r2] 02071EAC E8BD8010 pop r4,r15 // ---- Event 0xD1 (Address 02071EB4) ---- 02071EB4 E92D4010 push r4,r14 02071EB8 E1D040D0 ldrsb r4,[r0] 02071EBC E1D315F4 ldrsh r1,[r3,54h] 02071EC0 E59FC070 ldr r12,=4000208h 02071EC4 E3A02000 mov r2,0h 02071EC8 E0811404 add r1,r1,r4,lsl 8h 02071ECC E1A01801 mov r1,r1,lsl 10h 02071ED0 E1A04841 mov r4,r1,asr 10h 02071ED4 E1C345B4 strh r4,[r3,54h] 02071ED8 E593E0C4 ldr r14,[r3,0C4h] 02071EDC E593101C ldr r1,[r3,1Ch] 02071EE0 E1DEE0F4 ldrsh r14,[r14,4h] 02071EE4 E1A01841 mov r1,r1,asr 10h 02071EE8 E1A01801 mov r1,r1,lsl 10h 02071EEC E0841841 add r1,r4,r1,asr 10h 02071EF0 E08E1001 add r1,r14,r1 02071EF4 E1C311B6 strh r1,[r3,16h] 02071EF8 E1DC40B0 ldrh r4,[r12] 02071EFC E1CC20B0 strh r2,[r12] 02071F00 E59320B4 ldr r2,[r3,0B4h] 02071F04 E3520000 cmp r2,0h if( R2 == 0 ) 02071F08 0A000005 beq 2071F24h 02071F0C E1D210B6 ldrh r1,[r2,6h] 02071F10 E3811010 orr r1,r1,10h 02071F14 E1C210B6 strh r1,[r2,6h] 02071F18 E5922154 ldr r2,[r2,154h] 02071F1C E3520000 cmp r2,0h if( R2 != 0 ) 02071F20 1AFFFFF9 bne 2071F0Ch 02071F24 E59F200C ldr r2,=4000208h 02071F28 E2800001 add r0,r0,1h 02071F2C E1D210B0 ldrh r1,[r2] 02071F30 E1C240B0 strh r4,[r2] 02071F34 E8BD8010 pop r4,r15 // ---- Event 0xD2 (Address 02071F3C) ---- 02071F3C E92D4010 push r4,r14 02071F40 E1D040D0 ldrsb r4,[r0] 02071F44 E1D315F4 ldrsh r1,[r3,54h] 02071F48 E59FC070 ldr r12,=4000208h 02071F4C E3A02000 mov r2,0h 02071F50 E0811104 add r1,r1,r4,lsl 2h 02071F54 E1A01801 mov r1,r1,lsl 10h 02071F58 E1A04841 mov r4,r1,asr 10h 02071F5C E1C345B4 strh r4,[r3,54h] 02071F60 E593E0C4 ldr r14,[r3,0C4h] 02071F64 E593101C ldr r1,[r3,1Ch] 02071F68 E1DEE0F4 ldrsh r14,[r14,4h] 02071F6C E1A01841 mov r1,r1,asr 10h 02071F70 E1A01801 mov r1,r1,lsl 10h 02071F74 E0841841 add r1,r4,r1,asr 10h 02071F78 E08E1001 add r1,r14,r1 02071F7C E1C311B6 strh r1,[r3,16h] 02071F80 E1DC40B0 ldrh r4,[r12] 02071F84 E1CC20B0 strh r2,[r12] 02071F88 E59320B4 ldr r2,[r3,0B4h] 02071F8C E3520000 cmp r2,0h if( R2 == 0 ) 02071F90 0A000005 beq 2071FACh 02071F94 E1D210B6 ldrh r1,[r2,6h] 02071F98 E3811010 orr r1,r1,10h 02071F9C E1C210B6 strh r1,[r2,6h] 02071FA0 E5922154 ldr r2,[r2,154h] 02071FA4 E3520000 cmp r2,0h if( R2 != 0 ) 02071FA8 1AFFFFF9 bne 2071F94h 02071FAC E59F200C ldr r2,=4000208h 02071FB0 E2800001 add r0,r0,1h 02071FB4 E1D210B0 ldrh r1,[r2] 02071FB8 E1C240B0 strh r4,[r2] 02071FBC E8BD8010 pop r4,r15 // ---- Event 0xD3 (Address 02071FC4) ---- 02071FC4 E92D4008 push r3,r14 02071FC8 E5D0C000 ldrb r12,[r0] 02071FCC E5D01001 ldrb r1,[r0,1h] 02071FD0 E1D3E5F4 ldrsh r14,[r3,54h] 02071FD4 E59F2074 ldr r2,=4000208h 02071FD8 E08C1401 add r1,r12,r1,lsl 8h 02071FDC E08E1001 add r1,r14,r1 02071FE0 E1A01801 mov r1,r1,lsl 10h 02071FE4 E1A0E841 mov r14,r1,asr 10h 02071FE8 E1C3E5B4 strh r14,[r3,54h] 02071FEC E593C0C4 ldr r12,[r3,0C4h] 02071FF0 E593101C ldr r1,[r3,1Ch] 02071FF4 E1DCC0F4 ldrsh r12,[r12,4h] 02071FF8 E1A01841 mov r1,r1,asr 10h 02071FFC E1A01801 mov r1,r1,lsl 10h 02072000 E08E1841 add r1,r14,r1,asr 10h 02072004 E08C1001 add r1,r12,r1 02072008 E1C311B6 strh r1,[r3,16h] 0207200C E1D2C0B0 ldrh r12,[r2] 02072010 E3A01000 mov r1,0h 02072014 E1C210B0 strh r1,[r2] 02072018 E59320B4 ldr r2,[r3,0B4h] 0207201C E3520000 cmp r2,0h if( R2 == 0 ) 02072020 0A000005 beq 207203Ch 02072024 E1D210B6 ldrh r1,[r2,6h] 02072028 E3811010 orr r1,r1,10h 0207202C E1C210B6 strh r1,[r2,6h] 02072030 E5922154 ldr r2,[r2,154h] 02072034 E3520000 cmp r2,0h if( R2 != 0 ) 02072038 1AFFFFF9 bne 2072024h 0207203C E59F200C ldr r2,=4000208h 02072040 E2800002 add r0,r0,2h 02072044 E1D210B0 ldrh r1,[r2] 02072048 E1C2C0B0 strh r12,[r2] 0207204C E8BD8008 pop r3,r15 // ---- Event 0xD4 (Address 02072054) ---- 02072054 E92D40F8 push r3-r7,r14 02072058 E1A07000 mov r7,r0 0207205C E1A06003 mov r6,r3 02072060 E5D61004 ldrb r1,[r6,4h] 02072064 E5D74000 ldrb r4,[r7] 02072068 E5D70001 ldrb r0,[r7,1h] 0207206C E3110002 tst r1,2h 02072070 E5D72002 ldrb r2,[r7,2h] 02072074 E0840400 add r0,r4,r0,lsl 8h 02072078 E1A00800 mov r0,r0,lsl 10h 0207207C E1A05820 mov r5,r0,lsr 10h 02072080 E59640C4 ldr r4,[r6,0C4h] if( (R1 & 2) == 0 ) { 02072084 03A01000 moveq r1,0h 02072088 0586101C streq r1,[r6,1Ch] } 0207208C E596101C ldr r1,[r6,1Ch] 02072090 E1A00C02 mov r0,r2,lsl 18h 02072094 E1A01841 mov r1,r1,asr 10h 02072098 E0810820 add r0,r1,r0,lsr 10h 0207209C E1A00800 mov r0,r0,lsl 10h 020720A0 E1A00820 mov r0,r0,lsr 10h 020720A4 E1A01800 mov r1,r0,lsl 10h 020720A8 E5861024 str r1,[r6,24h] 020720AC E3550000 cmp r5,0h if( R5 == 0 ) { 020720B0 0586101C streq r1,[r6,1Ch] 020720B4 0A000006 beq 20720D4h } 020720B8 E596001C ldr r0,[r6,1Ch] 020720BC E0510000 subs r0,r1,r0 if( R0 == 0 ) { 020720C0 03A05000 moveq r5,0h 020720C4 0A000002 beq 20720D4h } 020720C8 E1A01005 mov r1,r5 020720CC EB007774 bl 208FEA4h 020720D0 E5860020 str r0,[r6,20h] 020720D4 E1C652B8 strh r5,[r6,28h] 020720D8 E596001C ldr r0,[r6,1Ch] 020720DC E1D615F4 ldrsh r1,[r6,54h] 020720E0 E1A00840 mov r0,r0,asr 10h 020720E4 E1A00800 mov r0,r0,lsl 10h 020720E8 E1D420F4 ldrsh r2,[r4,4h] 020720EC E0810820 add r0,r1,r0,lsr 10h 020720F0 E59F1048 ldr r1,=4000208h 020720F4 E0820000 add r0,r2,r0 020720F8 E1C601B6 strh r0,[r6,16h] 020720FC E1D130B0 ldrh r3,[r1] 02072100 E3A00000 mov r0,0h 02072104 E1C100B0 strh r0,[r1] 02072108 E59610B4 ldr r1,[r6,0B4h] 0207210C E3510000 cmp r1,0h if( R1 == 0 ) 02072110 0A000005 beq 207212Ch 02072114 E1D100B6 ldrh r0,[r1,6h] 02072118 E3800010 orr r0,r0,10h 0207211C E1C100B6 strh r0,[r1,6h] 02072120 E5911154 ldr r1,[r1,154h] 02072124 E3510000 cmp r1,0h if( R1 == 0 ) 02072128 1AFFFFF9 bne 2072114h 0207212C E59F200C ldr r2,=4000208h 02072130 E2870003 add r0,r7,3h 02072134 E1D210B0 ldrh r1,[r2] 02072138 E1C230B0 strh r3,[r2] 0207213C E8BD80F8 pop r3-r7,r15 // ---- Event 0xD5 (Address 02072144) ---- 02072144 E5D01000 ldrb r1,[r0] 02072148 E5D0C001 ldrb r12,[r0,1h] 0207214C E2800002 add r0,r0,2h 02072150 E1A02001 mov r2,r1 02072154 E151000C cmp r1,r12 if( R1 <= R12 ) //unsigned { 02072158 81A0200C movhi r2,r12 0207215C 81A0C001 movhi r12,r1 } 02072160 E5C3200C strb r2,[r3,0Ch] 02072164 E5C3C00D strb r12,[r3,0Dh] 02072168 E12FFF1E bx r14 // ---- Event 0xD6 (Address 0207216C) ---- 0207216C E5D02000 ldrb r2,[r0] 02072170 E5D01001 ldrb r1,[r0,1h] 02072174 E2800002 add r0,r0,2h 02072178 E0821401 add r1,r2,r1,lsl 8h 0207217C E1C310BA strh r1,[r3,0Ah] 02072180 E12FFF1E bx r14 // ---- Event 0xD7 (Address 02072184) ---- 02072184 E92D4010 push r4,r14 02072188 E1A04000 mov r4,r0 0207218C E5D42000 ldrb r2,[r4] 02072190 E5D41001 ldrb r1,[r4,1h] 02072194 E1A00003 mov r0,r3 02072198 E0811402 add r1,r1,r2,lsl 8h 0207219C E1A01801 mov r1,r1,lsl 10h 020721A0 E1A01841 mov r1,r1,asr 10h 020721A4 EB0006B9 bl 2073C90h 020721A8 E2840002 add r0,r4,2h 020721AC E8BD8010 pop r4,r15 // ---- Event 0xD8 (Address 020721B0) ---- 020721B0 E5D02000 ldrb r2,[r0] 020721B4 E5D01001 ldrb r1,[r0,1h] 020721B8 E2800002 add r0,r0,2h 020721BC E0811402 add r1,r1,r2,lsl 8h 020721C0 E1C315B6 strh r1,[r3,56h] 020721C4 E12FFF1E bx r14 // ---- Event 0xD9 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xDA (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xDB (Address 020721C8) ---- 020721C8 E4D01001 ldrb r1,[r0],1h 020721CC E5C31059 strb r1,[r3,59h] 020721D0 E12FFF1E bx r14 // ---- Event 0xDC (Address 020721D4) ---- 020721D4 E92D4038 push r3-r5,r14 020721D8 E5D05000 ldrb r5,[r0] 020721DC E5D04001 ldrb r4,[r0,1h] 020721E0 E5D0E002 ldrb r14,[r0,2h] 020721E4 E5D0C003 ldrb r12,[r0,3h] 020721E8 E5D02004 ldrb r2,[r0,4h] 020721EC E3A01001 mov r1,1h 020721F0 E0854404 add r4,r5,r4,lsl 8h 020721F4 E5C31075 strb r1,[r3,75h] 020721F8 E5C31076 strb r1,[r3,76h] 020721FC E1A01804 mov r1,r4,lsl 10h 02072200 E5C32077 strb r2,[r3,77h] 02072204 E1A01841 mov r1,r1,asr 10h 02072208 E5831078 str r1,[r3,78h] 0207220C E08E140C add r1,r14,r12,lsl 8h 02072210 E1C317BC strh r1,[r3,7Ch] 02072214 E3A01000 mov r1,0h 02072218 E1C317BE strh r1,[r3,7Eh] 0207221C E1C318B0 strh r1,[r3,80h] 02072220 E5C31082 strb r1,[r3,82h] 02072224 E2800005 add r0,r0,5h 02072228 E8BD8038 pop r3-r5,r15 // ---- Event 0xDD (Address 0207222C) ---- 0207222C E5D02000 ldrb r2,[r0] 02072230 E5D01001 ldrb r1,[r0,1h] 02072234 E0821401 add r1,r2,r1,lsl 8h 02072238 E1C317BE strh r1,[r3,7Eh] 0207223C E5D02002 ldrb r2,[r0,2h] 02072240 E5D01003 ldrb r1,[r0,3h] 02072244 E2800004 add r0,r0,4h 02072248 E0821401 add r1,r2,r1,lsl 8h 0207224C E1C318B0 strh r1,[r3,80h] 02072250 E12FFF1E bx r14 // ---- Event 0xDE (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xDF (Address 02072254) ---- 02072254 E5D01000 ldrb r1,[r0] 02072258 E2800001 add r0,r0,1h 0207225C E3510002 cmp r1,2h if( R1 == 2 ) 02072260 03A01001 moveq r1,1h 02072264 E5C31075 strb r1,[r3,75h] 02072268 E3510000 cmp r1,0h if( R1 == 0 ) 0207226C 03A01000 moveq r1,0h else 02072270 13A01001 movne r1,1h 02072274 E5C31076 strb r1,[r3,76h] 02072278 E12FFF1E bx r14 // ---- Event 0xE0 (Address 0207227C) ---- 0207227C E92D4038 push r3-r5,r14 02072280 E1D040D0 ldrsb r4,[r0] 02072284 E3A05000 mov r5,0h 02072288 E59F2078 ldr r2,=82061029h 0207228C E1A01804 mov r1,r4,lsl 10h 02072290 E5831034 str r1,[r3,34h] 02072294 E583102C str r1,[r3,2Ch] 02072298 E1C353B8 strh r5,[r3,38h] 0207229C E593C0C4 ldr r12,[r3,0C4h] 020722A0 E5D31050 ldrb r1,[r3,50h] 020722A4 E1DCE0D8 ldrsb r14,[r12,8h] 020722A8 E59FC05C ldr r12,=4000208h 020722AC E1610184 smulbb r1,r4,r1 020722B0 E004019E mul r4,r14,r1 020722B4 E0CE1492 smull r1,r14,r2,r4 020722B8 E084E00E add r14,r4,r14 020722BC E1A01FA4 mov r1,r4,lsr 1Fh 020722C0 E081E6CE add r14,r1,r14,asr 0Dh 020722C4 E1C3E1B8 strh r14,[r3,18h] 020722C8 E1DC40B0 ldrh r4,[r12] 020722CC E1CC50B0 strh r5,[r12] 020722D0 E59320B4 ldr r2,[r3,0B4h] 020722D4 E3520000 cmp r2,0h if( R2 == 0 ) 020722D8 0A000005 beq 20722F4h 020722DC E1D210B6 ldrh r1,[r2,6h] 020722E0 E3811020 orr r1,r1,20h 020722E4 E1C210B6 strh r1,[r2,6h] 020722E8 E5922154 ldr r2,[r2,154h] 020722EC E3520000 cmp r2,0h if( R2 != 0 ) 020722F0 1AFFFFF9 bne 20722DCh 020722F4 E59F2010 ldr r2,=4000208h 020722F8 E2800001 add r0,r0,1h 020722FC E1D210B0 ldrh r1,[r2] 02072300 E1C240B0 strh r4,[r2] 02072304 E8BD8038 pop r3-r5,r15 // ---- Event 0xE1 (Address 02072310) ---- 02072310 E92D4038 push r3-r5,r14 02072314 E1D020D0 ldrsb r2,[r0] 02072318 E593102C ldr r1,[r3,2Ch] 0207231C E0824841 add r4,r2,r1,asr 10h 02072320 E354007F cmp r4,7Fh if( R4 > 0x7F ) //signed { 02072324 C3A0407F movgt r4,7Fh 02072328 CA000001 bgt 2072334h } 0207232C E3540000 cmp r4,0h if( R4 < 0 ) //signed 02072330 B3A04000 movlt r4,0h 02072334 E1A01804 mov r1,r4,lsl 10h 02072338 E5831034 str r1,[r3,34h] 0207233C E583102C str r1,[r3,2Ch] 02072340 E3A05000 mov r5,0h 02072344 E1C353B8 strh r5,[r3,38h] 02072348 E5D31050 ldrb r1,[r3,50h] 0207234C E593C0C4 ldr r12,[r3,0C4h] 02072350 E59F2060 ldr r2,=82061029h 02072354 E0010194 mul r1,r4,r1 02072358 E1DCE0D8 ldrsb r14,[r12,8h] 0207235C E59FC058 ldr r12,=4000208h 02072360 E004019E mul r4,r14,r1 02072364 E0CE1492 smull r1,r14,r2,r4 02072368 E084E00E add r14,r4,r14 0207236C E1A01FA4 mov r1,r4,lsr 1Fh 02072370 E081E6CE add r14,r1,r14,asr 0Dh 02072374 E1C3E1B8 strh r14,[r3,18h] 02072378 E1DC40B0 ldrh r4,[r12] 0207237C E1CC50B0 strh r5,[r12] 02072380 E59320B4 ldr r2,[r3,0B4h] 02072384 E3520000 cmp r2,0h if( R2 == 0 ) 02072388 0A000005 beq 20723A4h 0207238C E1D210B6 ldrh r1,[r2,6h] 02072390 E3811020 orr r1,r1,20h 02072394 E1C210B6 strh r1,[r2,6h] 02072398 E5922154 ldr r2,[r2,154h] 0207239C E3520000 cmp r2,0h if( R2 != 0 ) 020723A0 1AFFFFF9 bne 207238Ch 020723A4 E59F2010 ldr r2,=4000208h 020723A8 E2800001 add r0,r0,1h 020723AC E1D210B0 ldrh r1,[r2] 020723B0 E1C240B0 strh r4,[r2] 020723B4 E8BD8038 pop r3-r5,r15 // ---- Event 0xE2 (Address 020723C0) ---- 020723C0 E92D4070 push r4-r6,r14 020723C4 E1A05000 mov r5,r0 020723C8 E1D510D2 ldrsb r1,[r5,2h] 020723CC E5D52000 ldrb r2,[r5] 020723D0 E5D50001 ldrb r0,[r5,1h] 020723D4 E1A04003 mov r4,r3 020723D8 E1A01801 mov r1,r1,lsl 10h 020723DC E0820400 add r0,r2,r0,lsl 8h 020723E0 E1A00800 mov r0,r0,lsl 10h 020723E4 E5841034 str r1,[r4,34h] 020723E8 E1B06820 movs r6,r0,lsr 10h if( R6 == 0 ) { 020723EC 0584102C streq r1,[r4,2Ch] 020723F0 0A000006 beq 2072410h } 020723F4 E594002C ldr r0,[r4,2Ch] 020723F8 E0510000 subs r0,r1,r0 if( R0 == 0 ) { 020723FC 03A06000 moveq r6,0h 02072400 0A000002 beq 2072410h } 02072404 E1A01006 mov r1,r6 02072408 EB0076A5 bl 208FEA4h 0207240C E5840030 str r0,[r4,30h] 02072410 E1C463B8 strh r6,[r4,38h] 02072414 E2850003 add r0,r5,3h 02072418 E8BD8070 pop r4-r6,r15 // ---- Event 0xE3 SetExpression (Address 0207241C) ---- 0207241C E92D4038 push r3-r5,r14 02072420 E5D04000 ldrb r4,[r0] //Read parameter 02072424 E59F2074 ldr r2,=82061029h 02072428 E59FE074 ldr r14,=4000208h //Master interupt control 0207242C E5C34050 strb r4,[r3,50h] //Puts parameter there. Its most likely the current track's expression 02072430 E593102C ldr r1,[r3,2Ch] //loaded 0x640000 02072434 E593C0C4 ldr r12,[r3,0C4h] //read 0x2292360 02072438 E1A01841 mov r1,r1,asr 10h //R1 = 0x64 0207243C E0040491 mul r4,r1,r4 //R4 = 0x64 * Expression (R4 = 0x64 * 0x73 = 0x2CEC) 02072440 E1DC10D8 ldrsb r1,[r12,8h] //R1 = 0x7F 02072444 E3A0C000 mov r12,0h //R12 = 0 02072448 E0040491 mul r4,r1,r4 //R4 = 0x7F * 0x2CEC = 0x164914 0207244C E0C51492 smull r1,r5,r2,r4 //R1 = 0xFFFFFFFF & (R2 * R4), R5 = (R2 * R4) >> 32.(signed) (R1= 0x469AF434, R5= 0xFFF5088F) 02072450 E0845005 add r5,r4,r5 //R5 = 0x164914(1,460,500) + 0xFFF5088F(-718,705) = 0xB51A3(741,795) 02072454 E1A01FA4 mov r1,r4,lsr 1Fh //R1 = 0x164914 >> 31 = 0 02072458 E08156C5 add r5,r1,r5,asr 0Dh //R5 = 0 + 0xB51A3 >> 13 = 0x5A(90) 0207245C E1C351B8 strh r5,[r3,18h] //0x2292370 + 0x18 2292388 02072460 E1DE40B0 ldrh r4,[r14] //Get previous Master interrupt state 02072464 E1CEC0B0 strh r12,[r14] //Turn interrupts off (Probably a critical section) 02072468 E59320B4 ldr r2,[r3,0B4h] // This is a pointer 0207246C E3520000 cmp r2,0h //Check if pointer is null if( R2 == 0 ) 02072470 0A000005 beq 207248Ch ///GOTO LBL1 ///LBL2 02072474 E1D210B6 ldrh r1,[r2,6h] 02072478 E3811020 orr r1,r1,20h 0207247C E1C210B6 strh r1,[r2,6h] 02072480 E5922154 ldr r2,[r2,154h] 02072484 E3520000 cmp r2,0h if( R2 != 0 ) 02072488 1AFFFFF9 bne 2072474h ///GOTO LBL2 ///LBL1 0207248C E59F2010 ldr r2,=4000208h //Master interrupt control 02072490 E2800001 add r0,r0,1h //Increment TrackPositionPtr 02072494 E1D210B0 ldrh r1,[r2] //Load previous Master interupt control state 02072498 E1C240B0 strh r4,[r2] //Restore previous Master Interrupt state 0207249C E8BD8038 pop r3-r5,r15 // ---- Event 0xE4 (Address 020724A8) ---- 020724A8 E92D4038 push r3-r5,r14 020724AC E5D05000 ldrb r5,[r0] 020724B0 E5D01001 ldrb r1,[r0,1h] 020724B4 E5D04002 ldrb r4,[r0,2h] 020724B8 E5D0E003 ldrb r14,[r0,3h] 020724BC E5D0C004 ldrb r12,[r0,4h] 020724C0 E3A02001 mov r2,1h 020724C4 E0851401 add r1,r5,r1,lsl 8h 020724C8 E1A01801 mov r1,r1,lsl 10h 020724CC E5C32085 strb r2,[r3,85h] 020724D0 E3A02002 mov r2,2h 020724D4 E5C32086 strb r2,[r3,86h] 020724D8 E5C3C087 strb r12,[r3,87h] 020724DC E1A01841 mov r1,r1,asr 10h 020724E0 E5831088 str r1,[r3,88h] 020724E4 E084140E add r1,r4,r14,lsl 8h 020724E8 E1C318BC strh r1,[r3,8Ch] 020724EC E3A01000 mov r1,0h 020724F0 E1C318BE strh r1,[r3,8Eh] 020724F4 E1C319B0 strh r1,[r3,90h] 020724F8 E5C31092 strb r1,[r3,92h] 020724FC E2800005 add r0,r0,5h 02072500 E8BD8038 pop r3-r5,r15 // ---- Event 0xE5 (Address 02072504) ---- 02072504 E5D02000 ldrb r2,[r0] 02072508 E5D01001 ldrb r1,[r0,1h] 0207250C E0821401 add r1,r2,r1,lsl 8h 02072510 E1C318BE strh r1,[r3,8Eh] 02072514 E5D02002 ldrb r2,[r0,2h] 02072518 E5D01003 ldrb r1,[r0,3h] 0207251C E2800004 add r0,r0,4h 02072520 E0821401 add r1,r2,r1,lsl 8h 02072524 E1C319B0 strh r1,[r3,90h] 02072528 E12FFF1E bx r14 // ---- Event 0xE6 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xE7 (Address 0207252C) ---- 0207252C E5D01000 ldrb r1,[r0] 02072530 E2800001 add r0,r0,1h 02072534 E3510002 cmp r1,2h if( R1 == 2 ) 02072538 03A01001 moveq r1,1h 0207253C E5C31085 strb r1,[r3,85h] 02072540 E3510000 cmp r1,0h if( R1 == 0 ) 02072544 03A01000 moveq r1,0h else 02072548 13A01002 movne r1,2h 0207254C E5C31086 strb r1,[r3,86h] 02072550 E12FFF1E bx r14 // ---- Event 0xE8 (Address 02072554) ---- 02072554 E92D4008 push r3,r14 02072558 E5D0E000 ldrb r14,[r0] 0207255C E3A0C000 mov r12,0h 02072560 E35E007F cmp r14,7Fh if( R14 > 0x7F ) //signed 02072564 C3A0E07F movgt r14,7Fh 02072568 E1A0180E mov r1,r14,lsl 10h 0207256C E5831044 str r1,[r3,44h] 02072570 E583103C str r1,[r3,3Ch] 02072574 E1C3C4B8 strh r12,[r3,48h] 02072578 E59320C4 ldr r2,[r3,0C4h] 0207257C E59F104C ldr r1,=4000208h 02072580 E1D220D7 ldrsb r2,[r2,7h] 02072584 E2422040 sub r2,r2,40h 02072588 E08E2002 add r2,r14,r2 0207258C E1C321BA strh r2,[r3,1Ah] 02072590 E1D1E0B0 ldrh r14,[r1] 02072594 E1C1C0B0 strh r12,[r1] 02072598 E59320B4 ldr r2,[r3,0B4h] 0207259C E3520000 cmp r2,0h if( R2 == 0 ) 020725A0 0A000005 beq 20725BCh 020725A4 E1D210B6 ldrh r1,[r2,6h] 020725A8 E3811040 orr r1,r1,40h 020725AC E1C210B6 strh r1,[r2,6h] 020725B0 E5922154 ldr r2,[r2,154h] 020725B4 E3520000 cmp r2,0h if( R2 != 0 ) 020725B8 1AFFFFF9 bne 20725A4h 020725BC E59F200C ldr r2,=4000208h 020725C0 E2800001 add r0,r0,1h 020725C4 E1D210B0 ldrh r1,[r2] 020725C8 E1C2E0B0 strh r14,[r2] 020725CC E8BD8008 pop r3,r15 // ---- Event 0xE9 (Address 020725D4) ---- 020725D4 E92D4008 push r3,r14 020725D8 E1D020D0 ldrsb r2,[r0] 020725DC E593103C ldr r1,[r3,3Ch] 020725E0 E082E841 add r14,r2,r1,asr 10h 020725E4 E35E007F cmp r14,7Fh if( R14 > 0x7F ) //signed 020725E8 C3A0E07F movgt r14,7Fh 020725EC CA000001 bgt 20725F8h 020725F0 E35E0000 cmp r14,0h if( R14 < 0 ) //signed 020725F4 B3A0E000 movlt r14,0h 020725F8 E1A0180E mov r1,r14,lsl 10h 020725FC E5831044 str r1,[r3,44h] 02072600 E583103C str r1,[r3,3Ch] 02072604 E3A0C000 mov r12,0h 02072608 E1C3C4B8 strh r12,[r3,48h] 0207260C E59320C4 ldr r2,[r3,0C4h] 02072610 E59F104C ldr r1,=4000208h 02072614 E1D220D7 ldrsb r2,[r2,7h] 02072618 E2422040 sub r2,r2,40h 0207261C E08E2002 add r2,r14,r2 02072620 E1C321BA strh r2,[r3,1Ah] 02072624 E1D1E0B0 ldrh r14,[r1] 02072628 E1C1C0B0 strh r12,[r1] 0207262C E59320B4 ldr r2,[r3,0B4h] 02072630 E3520000 cmp r2,0h if( R2 == 0 ) 02072634 0A000005 beq 2072650h 02072638 E1D210B6 ldrh r1,[r2,6h] 0207263C E3811040 orr r1,r1,40h 02072640 E1C210B6 strh r1,[r2,6h] 02072644 E5922154 ldr r2,[r2,154h] 02072648 E3520000 cmp r2,0h if( R2 != 0 ) 0207264C 1AFFFFF9 bne 2072638h 02072650 E59F200C ldr r2,=4000208h 02072654 E2800001 add r0,r0,1h 02072658 E1D210B0 ldrh r1,[r2] 0207265C E1C2E0B0 strh r14,[r2] 02072660 E8BD8008 pop r3,r15 // ---- Event 0xEA (Address 02072668) ---- 02072668 E92D4070 push r4-r6,r14 0207266C E1A05000 mov r5,r0 02072670 E1D510D2 ldrsb r1,[r5,2h] 02072674 E5D52000 ldrb r2,[r5] 02072678 E5D50001 ldrb r0,[r5,1h] 0207267C E1A04003 mov r4,r3 02072680 E1A01801 mov r1,r1,lsl 10h 02072684 E0820400 add r0,r2,r0,lsl 8h 02072688 E1A00800 mov r0,r0,lsl 10h 0207268C E5841044 str r1,[r4,44h] 02072690 E1B06820 movs r6,r0,lsr 10h if( R6 == 0 ) { 02072694 0584103C streq r1,[r4,3Ch] 02072698 0A000006 beq 20726B8h } 0207269C E594003C ldr r0,[r4,3Ch] 020726A0 E0510000 subs r0,r1,r0 if( R0 == 0 ) { 020726A4 03A06000 moveq r6,0h 020726A8 0A000002 beq 20726B8h } 020726AC E1A01006 mov r1,r6 020726B0 EB0075FB bl 208FEA4h 020726B4 E5840040 str r0,[r4,40h] 020726B8 E1C464B8 strh r6,[r4,48h] 020726BC E2850003 add r0,r5,3h 020726C0 E8BD8070 pop r4-r6,r15 // ---- Event 0xEB (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xEC (Address 020726C4) ---- 020726C4 E92D4038 push r3-r5,r14 020726C8 E5D05000 ldrb r5,[r0] 020726CC E5D01001 ldrb r1,[r0,1h] 020726D0 E5D04002 ldrb r4,[r0,2h] 020726D4 E5D0E003 ldrb r14,[r0,3h] 020726D8 E5D0C004 ldrb r12,[r0,4h] 020726DC E3A02001 mov r2,1h 020726E0 E0851401 add r1,r5,r1,lsl 8h 020726E4 E1A01801 mov r1,r1,lsl 10h 020726E8 E5C32095 strb r2,[r3,95h] 020726EC E3A02003 mov r2,3h 020726F0 E5C32096 strb r2,[r3,96h] 020726F4 E5C3C097 strb r12,[r3,97h] 020726F8 E1A01841 mov r1,r1,asr 10h 020726FC E5831098 str r1,[r3,98h] 02072700 E084140E add r1,r4,r14,lsl 8h 02072704 E1C319BC strh r1,[r3,9Ch] 02072708 E3A01000 mov r1,0h 0207270C E1C319BE strh r1,[r3,9Eh] 02072710 E1C31AB0 strh r1,[r3,0A0h] 02072714 E5C310A2 strb r1,[r3,0A2h] 02072718 E2800005 add r0,r0,5h 0207271C E8BD8038 pop r3-r5,r15 // ---- Event 0xED (Address 02072720) ---- 02072720 E5D02000 ldrb r2,[r0] 02072724 E5D01001 ldrb r1,[r0,1h] 02072728 E0821401 add r1,r2,r1,lsl 8h 0207272C E1C319BE strh r1,[r3,9Eh] 02072730 E5D02002 ldrb r2,[r0,2h] 02072734 E5D01003 ldrb r1,[r0,3h] 02072738 E2800004 add r0,r0,4h 0207273C E0821401 add r1,r2,r1,lsl 8h 02072740 E1C31AB0 strh r1,[r3,0A0h] 02072744 E12FFF1E bx r14 // ---- Event 0xEE (Address 0207191C) ---- //Same as 0x96 0x0207191C, // ---- Event 0xEF (Address 02072748) ---- 02072748 E5D01000 ldrb r1,[r0] 0207274C E2800001 add r0,r0,1h 02072750 E3510002 cmp r1,2h if( R1 == 2 ) 02072754 03A01001 moveq r1,1h 02072758 E5C31095 strb r1,[r3,95h] 0207275C E3510000 cmp r1,0h if( R1 == 0 ) 02072760 03A01000 moveq r1,0h else 02072764 13A01003 movne r1,3h 02072768 E5C31096 strb r1,[r3,96h] 0207276C E12FFF1E bx r14 // ---- Event 0xF0 (Address 02072770) ---- 02072770 E92D4010 push r4,r14 02072774 E5D02000 ldrb r2,[r0] 02072778 E5D01001 ldrb r1,[r0,1h] 0207277C E5D3C061 ldrb r12,[r3,61h] 02072780 E2833074 add r3,r3,74h 02072784 E0821401 add r1,r2,r1,lsl 8h 02072788 E1A01801 mov r1,r1,lsl 10h 0207278C E5D04002 ldrb r4,[r0,2h] 02072790 E5D0E003 ldrb r14,[r0,3h] 02072794 E5D02004 ldrb r2,[r0,4h] 02072798 E083320C add r3,r3,r12,lsl 4h 0207279C E1A01841 mov r1,r1,asr 10h 020727A0 E5C32003 strb r2,[r3,3h] 020727A4 E5831004 str r1,[r3,4h] 020727A8 E084140E add r1,r4,r14,lsl 8h 020727AC E1C310B8 strh r1,[r3,8h] 020727B0 E3A01000 mov r1,0h 020727B4 E1C310BA strh r1,[r3,0Ah] 020727B8 E1C310BC strh r1,[r3,0Ch] 020727BC E5C3100E strb r1,[r3,0Eh] 020727C0 E2800005 add r0,r0,5h 020727C4 E8BD8010 pop r4,r15 // ---- Event 0xF1 (Address 020727C8) ---- 020727C8 E5D3C061 ldrb r12,[r3,61h] 020727CC E5D02000 ldrb r2,[r0] 020727D0 E5D01001 ldrb r1,[r0,1h] 020727D4 E2833074 add r3,r3,74h 020727D8 E083320C add r3,r3,r12,lsl 4h 020727DC E0821401 add r1,r2,r1,lsl 8h 020727E0 E1C310BA strh r1,[r3,0Ah] 020727E4 E5D02002 ldrb r2,[r0,2h] 020727E8 E5D01003 ldrb r1,[r0,3h] 020727EC E2800004 add r0,r0,4h 020727F0 E0821401 add r1,r2,r1,lsl 8h 020727F4 E1C310BC strh r1,[r3,0Ch] 020727F8 E12FFF1E bx r14 // ---- Event 0xF2 (Address 020727FC) ---- 020727FC E5D31061 ldrb r1,[r3,61h] 02072800 E5D0C000 ldrb r12,[r0] 02072804 E2832074 add r2,r3,74h 02072808 E0821201 add r1,r2,r1,lsl 4h 0207280C E5D02001 ldrb r2,[r0,1h] 02072810 E35C000A cmp r12,0Ah if( R12 <= 0xA ) //unsigned 02072814 908FF10C addls r15,r15,r12,lsl 2h 02072818 EA000044 b 2072930h 0207281C EA000043 b 2072930h 02072820 EA000008 b 2072848h 02072824 EA000009 b 2072850h 02072828 EA00000A b 2072858h 0207282C EA00000B b 2072860h 02072830 EA00000C b 2072868h 02072834 EA000029 b 20728E0h 02072838 EA00002B b 20728ECh 0207283C EA00002E b 20728FCh 02072840 EA000032 b 2072910h 02072844 EA000036 b 2072924h 02072848 E5C32061 strb r2,[r3,61h] 0207284C EA000037 b 2072930h 02072850 E5C12001 strb r2,[r1,1h] 02072854 EA000035 b 2072930h 02072858 E5C12002 strb r2,[r1,2h] 0207285C EA000033 b 2072930h 02072860 E5C12003 strb r2,[r1,3h] 02072864 EA000031 b 2072930h 02072868 E5D13002 ldrb r3,[r1,2h] 0207286C E3530004 cmp r3,4h if( R3 <= 4 ) 02072870 908FF103 addls r15,r15,r3,lsl 2h 02072874 EA000014 b 20728CCh 02072878 EA000013 b 20728CCh 0207287C EA000002 b 207288Ch 02072880 EA000005 b 207289Ch 02072884 EA000008 b 20728ACh 02072888 EA00000B b 20728BCh 0207288C E3A0300A mov r3,0Ah 02072890 E0030392 mul r3,r2,r3 02072894 E1A02003 mov r2,r3 02072898 EA00000E b 20728D8h 0207289C E3E03013 mvn r3,13h 020728A0 E0030392 mul r3,r2,r3 020728A4 E1A02003 mov r2,r3 020728A8 EA00000A b 20728D8h 020728AC E3A03014 mov r3,14h 020728B0 E0030392 mul r3,r2,r3 020728B4 E1A02003 mov r2,r3 020728B8 EA000006 b 20728D8h 020728BC E3A0300A mov r3,0Ah 020728C0 E0030392 mul r3,r2,r3 020728C4 E1A02003 mov r2,r3 020728C8 EA000002 b 20728D8h 020728CC E3A03014 mov r3,14h 020728D0 E0030392 mul r3,r2,r3 020728D4 E1A02003 mov r2,r3 020728D8 E5812004 str r2,[r1,4h] 020728DC EA000013 b 2072930h 020728E0 E0822102 add r2,r2,r2,lsl 2h 020728E4 E1C120B8 strh r2,[r1,8h] 020728E8 EA000010 b 2072930h 020728EC E3A03014 mov r3,14h 020728F0 E0030392 mul r3,r2,r3 020728F4 E1C130BA strh r3,[r1,0Ah] 020728F8 EA00000C b 2072930h 020728FC E1D130BA ldrh r3,[r1,0Ah] 02072900 E2033CFF and r3,r3,0FF00h 02072904 E1832002 orr r2,r3,r2 02072908 E1C120BA strh r2,[r1,0Ah] 0207290C EA000007 b 2072930h 02072910 E1D130BA ldrh r3,[r1,0Ah] 02072914 E20330FF and r3,r3,0FFh 02072918 E1832402 orr r2,r3,r2,lsl 8h 0207291C E1C120BA strh r2,[r1,0Ah] 02072920 EA000002 b 2072930h 02072924 E3A03014 mov r3,14h 02072928 E0030392 mul r3,r2,r3 0207292C E1C130BC strh r3,[r1,0Ch] 02072930 E2800002 add r0,r0,2h 02072934 E12FFF1E bx r14 // ---- Event 0xF3 (Address 02072938) ---- 02072938 E92D4008 push r3,r14 0207293C E5D0C001 ldrb r12,[r0,1h] 02072940 E5D02000 ldrb r2,[r0] 02072944 E5D0E002 ldrb r14,[r0,2h] 02072948 E2831074 add r1,r3,74h 0207294C E35C0002 cmp r12,2h 02072950 E5C32061 strb r2,[r3,61h] 02072954 E0811202 add r1,r1,r2,lsl 4h if( R12 == 2 ) 02072958 03A0C001 moveq r12,1h 0207295C E5C1C001 strb r12,[r1,1h] 02072960 E5C1E002 strb r14,[r1,2h] 02072964 E2800003 add r0,r0,3h 02072968 E8BD8008 pop r3,r15 // ---- Event 0xF4 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xF5 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xF6 (Address 0207296C) ---- 0207296C E92D4010 push r4,r14 02072970 E1A04000 mov r4,r0 02072974 E5D42000 ldrb r2,[r4] 02072978 E1A0C001 mov r12,r1 0207297C E3A01008 mov r1,8h 02072980 E5CC2016 strb r2,[r12,16h] 02072984 E59C0028 ldr r0,[r12,28h] 02072988 E59C30A0 ldr r3,[r12,0A0h] 0207298C E59CC09C ldr r12,[r12,9Ch] 02072990 E12FFF3C blx r12 02072994 E2840001 add r0,r4,1h 02072998 E8BD8010 pop r4,r15 // ---- Event 0xF7 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xF8 (Address 0207299C) ---- 0207299C E2800002 add r0,r0,2h 020729A0 E12FFF1E bx r14 // ---- Event 0xF9 (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xFA (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xFB (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xFC (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xFD (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xFE (Address 0207191C) ---- //Same as 0x96 // ---- Event 0xFF (Address 0207191C) ---- //Same as 0x96[/font] Apparently that the code at line 0x0207191C is basically some kind of no-op, or invalid event perhaps ? Its re-used on a lot events like event 0x96. It only sets a value in memory to 0, and then that value is re-used later on in the event parsing loop, at line 0x020713AC. When the value is 0, it breaks the loop, and make the function return.. Here's the event parsing function for reference: [font=Fixedsys]///LBL10 02071248 E5D53000 ldrb r3,[r5] //Loads an event 0207124C E2850001 add r0,r5,1h //Increment the track position pointer 02071250 E1A05000 mov r5,r0 02071254 E3530080 cmp r3,80h if( Event < 0x80 ) { 02071258 3A000010 bcc 20712A0h ///GOTO LBL1 } 0207125C E3530090 cmp r3,90h if( Event < 0x90 ) { 02071260 3A000008 bcc 2071288h ///GOTO LBL2 } 02071264 E59F2170 ldr r2,=20B0B90h //Event handler function table address 02071268 E1A01007 mov r1,r7 0207126C E0822103 add r2,r2,r3,lsl 2h 02071270 E5125240 ldr r5,[r2,-240h] //Get function pointer to handler for this event 02071274 E1A02006 mov r2,r6 02071278 E1A03004 mov r3,r4 0207127C E12FFF35 blx r5 ///EXEC EventHandler 02071280 E1A05000 mov r5,r0 //Update our read position with return value! 02071284 EA000048 b 20713ACh ///GOTO LBL3 ///LBL2 02071288 E59F0150 ldr r0,=20B0B7Ch //Address of delay duration table in ticks for events 0x80 to 0x8F 0207128C E0800003 add r0,r0,r3 02071290 E5500080 ldrb r0,[r0,-80h] 02071294 E5860010 str r0,[r6,10h] //Set last delay 02071298 E586000C str r0,[r6,0Ch] //Set current delay 0207129C EA000042 b 20713ACh ///GOTO LBL3 ///LBL1 020712A0 E5CD3003 strb r3,[r13,3h] 020712A4 E5D01000 ldrb r1,[r0] //Load note pitch byte (param1) 020712A8 E5D65004 ldrb r5,[r6,4h] //Load TrackOctave value ! 020712AC E3A0300C mov r3,0Ch 020712B0 E1A02A01 mov r2,r1,lsl 14h //Shift note param1 20 bits to the left (pitch indicator) 020712B4 E1A02C42 mov r2,r2,asr 18h //Shift it back left by 24 bits, keeping the sign bit ( Basically, same as applying this mask : 0xF0 ) 020712B8 E2022003 and r2,r2,3h //R2 = R2 & 3 (0011) 020712BC E2422002 sub r2,r2,2h //R2 = R2 - 2 020712C0 E1A02C02 mov r2,r2,lsl 18h //R2 = R2 << 24 020712C4 E0852C42 add r2,r5,r2,asr 18h //R2 = R5 + ( R2 >> 24 ) (signed shift right) (Basically, if( (Param1 >> 4) & 0x1 > 0 )Then add 1 to TrackOctave! ) 020712C8 E1A02C02 mov r2,r2,lsl 18h //R2 = R2 << 24 020712CC E1A05C42 mov r5,r2,asr 18h //R5 = R2 >> 24 (signed shift right) 020712D0 E201200F and r2,r1,0Fh //R2 = Param1 & 0xF 020712D4 E1022385 smlabb r2,r5,r3,r2 //R2 = (R5 & 0x0000FFFF * R3 & 0x0000FFFF) + R2 (R3 is always 0xC here) => MidiNote = (TrackOctave * 12) + Param1 & 0xF 020712D8 E5CD2002 strb r2,[r13,2h] //Put the note number on the stack at 0x229AADA (Track 5) 020712DC E1A01341 mov r1,r1,asr 6h //R1 = Param1 >> 6 (signed shift right) (Basically keep the 2 highest bits) 020712E0 E5C65004 strb r5,[r6,4h] //Overwrite TrackOctave with the newly calculated octave! 020712E4 E21110FF ands r1,r1,0FFh //R1 = (Param1 >> 6) & 0xFF (Why would they do that ?) 020712E8 E2805001 add r5,r0,1h //Increment track position pointer, and put it in R5 020712EC 05963014 ldreq r3,[r6,14h] //If( (Param1 >> 6) == 0 ) Then load NoteHoldDur at 0x2291D98 into R3 020712F0 0A000008 beq 2071318h ///GOTO LBL4 020712F4 E3510000 cmp r1,0h //If (Param1 >> 6) == 0 020712F8 E3A03000 mov r3,0h 020712FC 0A000004 beq 2071314h ///GOTO LBL5 ///LBL6 - Basically a loop to append the hold duration bytes of the note 02071300 E4D50001 ldrb r0,[r5],1h //Load next byte in the track, then increment the position pointer 02071304 E2411001 sub r1,r1,1h //Subtract 1 from (Param1 >> 6) 02071308 E21110FF ands r1,r1,0FFh //If (Param1 >> 6) != 0 then 0207130C E0803403 add r3,r0,r3,lsl 8h //R3 = Param2 + (R3 << 8) 02071310 1AFFFFFA bne 2071300h ///GOTO LBL6 - Loop if we still have duration bytes to append ///LBL5 02071314 E5863014 str r3,[r6,14h] //Store NoteHoldDur at 0x2291D98 ///LBL4 02071318 E5D62005 ldrb r2,[r6,5h] //NoteVolume ? 0207131C E3A01000 mov r1,0h 02071320 E59F00BC ldr r0,=2040811h 02071324 E0020293 mul r2,r3,r2 //R2 = NoteHoldDur * NoteVolume? 02071328 E0830092 umull r0,r3,r2,r0 //( R2 * 0x2040811 ) (Put the resulting 64bits integer into R0(low 32bits), and R3(high 32bits)) 0207132C E0420003 sub r0,r2,r3 //R0 = R2 - R3 02071330 E08330A0 add r3,r3,r0,lsr 1h //R3 = R3 + (R0 >> 1) 02071334 E1A03323 mov r3,r3,lsr 6h //R3 = (R3 >> 6) 02071338 E58D3004 str r3,[r13,4h] // 0207133C E5CD1000 strb r1,[r13] 02071340 E1D600D8 ldrsb r0,[r6,8h] 02071344 E3500000 cmp r0,0h 02071348 1A000012 bne 2071398h ///GOTO LBL7 0207134C E5D40004 ldrb r0,[r4,4h] 02071350 E28D1000 add r1,r13,0h 02071354 E3100002 tst r0,2h 02071358 0A000003 beq 207136Ch ///GOTO LBL8 0207135C E5D62007 ldrb r2,[r6,7h] 02071360 E1A00004 mov r0,r4 02071364 EB000AA9 bl 2073E10h ///EXEC Fun_02073E10 02071368 EA00000A b 2071398h ///GOTO LBL7 ///LBL8 0207136C E1A00004 mov r0,r4 02071370 EB000ACA bl 2073EA0h ///EXEC Fun_02073EA0 02071374 E3A02000 mov r2,0h 02071378 E28D1000 add r1,r13,0h 0207137C E1A00004 mov r0,r4 02071380 E584201C str r2,[r4,1Ch] 02071384 EB000A53 bl 2073CD8h ///EXEC Fun_02073CD8 02071388 E1B01000 movs r1,r0 0207138C 0A000001 beq 2071398h ///GOTO LBL7 02071390 E1A00004 mov r0,r4 02071394 EB000AD0 bl 2073EDCh ///EXEC Fun_02073EDC ///LBL7 02071398 E5DD0002 ldrb r0,[r13,2h] 0207139C E5C60007 strb r0,[r6,7h] 020713A0 E5D40004 ldrb r0,[r4,4h] 020713A4 E3C00002 bic r0,r0,2h 020713A8 E5C40004 strb r0,[r4,4h] ///LBL3 020713AC E1D600D2 ldrsb r0,[r6,2h] //This is the byte that the events like event 0x96 change to 0 020713B0 E3500000 cmp r0,0h if( R0 == 0 ) 020713B4 0A000002 beq 20713C4h ///GOTO LBL9 020713B8 E596000C ldr r0,[r6,0Ch] 020713BC E3500000 cmp r0,0h if( R0 == 0 ) 020713C0 0AFFFFA0 beq 2071248h ///GOTO LBL10 (Goes back to start of event parsing loop) ///LBL9 020713C4 E596000C ldr r0,[r6,0Ch] 020713C8 E2400001 sub r0,r0,1h 020713CC E586000C str r0,[r6,0Ch] 020713D0 E586501C str r5,[r6,1Ch] 020713D4 E28DD008 add r13,r13,8h 020713D8 E8BD80F8 pop r3-r7,r15[/font]
-
Oh, and I kinda forgot to specify how to extract the rom's data ^^; I'm fairly sure this is not the best way to do it, but I haven't found an easier way. At least it gets the job done.. First you need to get a decrypted ROM. I got a decrypted eshop package, as a ".cia". You'll know that its decrypted if you find the string "paradise" in the cia file, by doing a a string search in an hex editor. If its encrypted, you won't find it, as it will be scrambled. (Careful because a lot of 3ds roms floating around are just useless encrypted wastes of spaces ) Next, the tools currently available won't be able to extract the rom from the ".cia", or at least, I wasn't able to. So we need to get our hands dirty and grab an hex editor to cut out the actual ROM from all that junk. You'll need to search for the string "NCCH", or in bytes 0x4E, 0x43, 0x43, 0x48. That's the header we'll need to locate for the next part. Since the NCCH header begins 256 bytes before the magic number, with a SHA-256 key, we need to start copying/exporting bytes from the offset of the NCCH header - 0x100. (Details on the NCCH header : http://3dbrew.org/wiki/NCCH#NCCH_Header ) I use Hex Edit, so I just set my mark at the offset of the NCCH header - 0x100, went to the end of the entire file, and pressed CTRL+SHIFT+F9, this selected all the data past the beginning of the NCCH header. And then you can either copy paste this into another file, or if you use Hex Edit right click and in the menu click on "write selection..". Save the content to a file. Next, open that file in the hex editor, go to offset 0x1B0, copy the 32bits integer value in there that's the offset of the romfs chunk. Then copy the 32bits integer at 0x1B4, that's the size of the romfs chunk. Since they're not in bytes, but in "media units" we multiply both value by 0x200, as one media unit is 0x200 bytes. We'll need both of them, so write them both down ! (Details on the romfs header :http://3dbrew.org/wiki/RomFS#Format) Take the romfs offset we calculated earlier and press CTRL+G, enter that offset. If everything went right, the offset should bring you to the string "IVFC" in the file. That's the beginning of the romfs chunk we'll want to extract. Then select all the bytes from that place, to the offset of the romfs + the size of the romfs. Put all those bytes into a new file named "pmd_romfs". Now, we're almost done ! The next phase involves using ctrtool to extract the romfs. Ctrtool is pretty hard to get, and you need to compile it yourself with visual studio or with a build script. Its part of the ctr-sdk project: https://github.com/ctrdev/ctrsdk/tree/master/tools/ctrtool (For convenience I compiled a version and zipped it here: ) Once you have ctrtool.exe, place it in the same folder as the "pmd_romfs" file, and open a command prompt. (If you have anything newer than windows XP hold shift and right click on the background of the folder window with no file selected, select "open command window here". Otherwise, press Windows key + R, type in cmd, and then type cd followed with the path to the folder where "pmd_romfs" is. If you got linux, you probably already know how to do this ) In the command prompt, type: [font=Fixedsys] ctrtool.exe -t romfs --romfsdir=outputdir pmd_romfs[/font] If all goes well, the program should extract the filesystem into the outputdir directory! The binaries aren't included in the romfs though, they're in the exefs, and I haven't attempted to extract them yet. ctrtool.zip
-
So the first thing I'll contribute will be about the game's script engine. The game uses regular compiled Lua 5.1 scripts! Which means they can be decompiled using existing lua decompilers! We don't know yet if we can recompile them, or if we even need to recompile them however. Here's a nice little batch script to decompile all scripts in PMD:GTI's "script" folder: [font=Fixedsys] For /R .\ %%G in (*.lua) do ( java -jar unluac_2015_06_13.jar "%%G" > "%%~dG%%~pG%%~nG.txt" ) [/font] And here's a little batch script to delete the compiled original, and rename the decompiled .txt files into .lua ! [font=Fixedsys] Echo Deleting lua files... For /R .\ %%G in (*.lua) do ( Del "%%G" ) Echo Renaming txt files... For /R .\ %%G in (*.txt) do ( Ren "%%~G" "*.lua" ) [/font] Here's a little step-by step guide on how to use those: 0. Make sure you got Java installed, and have the rom extracted! 1. Get the unluac jar : http://sourceforge.net/projects/unluac/ (Be very careful on sourceforge! They may try to scam you with an automated downloader/installer. unluac has no installer and should come in a compressed archive as a .jar, not a .exe!) 2. Copy PMD:GTI's "script" folder somewhere else, to avoid deleting the original script files. 3. Go to that folder. 4. Create a text file, rename it "decompile.bat", and paste into it the first script above. 5. Create a text file, rename it "cleanandrename.bat" and paste into it the second script above. 6. Place unluac_2015_06_13.jar in the folder with the two batch script we just made. 7. Run the decompile.bat script 8. Run the cleanandrename.bat script 9. Done ! You should now have all the scripts decompiled ! Have a nice read
-
Please be sure to hide any PSMD spoilers within spoiler tags, until the game is released in all regions ! About This Thread: This thread is mostly for posting on-going research notes/progress and findings for the Pokemon Mystery Dungeon Gates to Infinity and Pokemon Super Mystery Dungeon games. Both games use very similar formats, and work generally the same way, which is why they both share the same thread. Information: Here are links to interesting posts in the thread, and to external websites. How to extract PMD:GTI rom's content How to batch decompile the lua scripts A nice little cheat sheet + Lua primer for those interested! Lua 5.1 experimental sandbox escape exploit Notes: Here are some links to notes, or to the wiki on the various file formats and etc of the games. SIR0 format Megadrifter's notes on the IMG format Utilities: Here are some utilities for dealing with the file formats in PSMD/PMD:GTI : ... Current Problematic Issues: Here are some of the things that are currently holding us back right now: No way to test modifications/investigate on a 3DS/emulator. My 3DS isn't unlocked. So having someone with one willing to try things out would be nice! (EDIT: Actually,thanks to ironhax I can run homebrew on it now But not much else ) This post will fill up as time goes.
-
Well, that's not exactly what I meant by volume envelope. Besides the expression, track volume, and main volume, there is another volume value that is taken into account. Its the volume envelope of the sample that is being played. Those are stored in the .swd file for each samples/splits. The value obtained from the volume envelope of the sample is also included in the equation to get the volume that is written into the NDS's sound channel registers. Basically, the volume envelope changes the volume of the sample over time, in 4-5 different phases. The Phases are AHDSR, Attack, Hold, Decay, Sustain, and Release. Additionally, the DSE driver allows setting the volume the Attack phase begins at. All phases but the Sustain phase are optional. And if the Decay2 phase is toggled on, when the the sustain phase is reached, it switch instantly to the Decay2 phase, so it becomes AHDSDR basically. Here's a little graphic of how it works (From what I understand): And this might explain better what's an envelope: http://en.wikiaudio.org/ADSR_envelope But, seeing your disassembly notes for the E0 and E3 events gave me a few ideas! Here's the disassembly I got from the code handling the volume envelope. I re-organized it to get a better feel of what is executed when: [font=Fixedsys] //This code picks the phase the envelope begins at. 02074E0C E92D4010 push r4,r14 02074E10 E1A04000 mov r4,r0 02074E14 E5D41000 ldrb r1,[r4] //Load "mulatk" (Its possible that this is also just a boolean to enable/disable envelope.) 02074E18 E3510000 cmp r1,0h //If "mulatk" is 0 02074E1C 0A000025 beq 2074EB8h //Then jump to 02074EB8 if( mulatk == 0 ) { //"mulatk" is 0 02074EB8 E5D4001C ldrb r0,[r4,1Ch] //Load envelope state 02074EBC E3500001 cmp r0,1h //If envelope state == 1 return if( EnvelopePhase == 1 ) { 02074EC0 08BD8010 popeq r4,r15 //Return } else { 02074EC4 E3A00000 mov r0,0h 02074EC8 E5C4001C strb r0,[r4,1Ch] //Set Envelope state to 0 02074ECC E3A005FE mov r0,3F800000h // 0x7F << 0x17 == 0x3F800000 02074ED0 E5840010 str r0,[r4,10h] //Set the volume to 0x3F800000(Maximum) 02074ED4 E8BD8010 pop r4,r15 //Return } } else { //The attack duration multiplier isn't 0.. 02074E20 E5D41009 ldrb r1,[r4,9h] //Load "Attack" parameter 02074E24 E3510000 cmp r1,0h 02074E28 0A000008 beq 2074E50h if( Attack == 0 ) { //If the attack is 0, we go straight to the "Hold" phase 02074E50 E3A015FE mov r1,3F800000h // 0x7F << 0x17 == 0x3F800000 02074E54 E5841010 str r1,[r4,10h] //Set the volume to 0x3F800000 (Maximum) 02074E58 E5D4200C ldrb r2,[r4,0Ch] //Load Hold 02074E5C E3520000 cmp r2,0h 02074E60 0A000004 beq 2074E78h if( Hold == 0 ) { //If the Hold is 0, we go to the decay phase 02074E78 E5D4200A ldrb r2,[r4,0Ah] //Load decay 02074E7C E3520000 cmp r2,0h 02074E80 0A000004 beq 2074E98h if( Decay == 0 ) { //If the decay is 0, we go to the second decay phase 02074E98 E5D4200D ldrb r2,[r4,0Dh] //Load Decay2 02074E9C E3A01000 mov r1,0h //Set TargetVolume to 0 02074EA0 EBFFFFAC bl 2074D58h //This function handles parsing all envelope duration parameter values . R0=EnvelopeBegAddress, R1=TargetVolume, R2=EnvelopeParam 02074EA4 E3A00006 mov r0,6h 02074EA8 E5C4001C strb r0,[r4,1Ch] //Set envelope state to 6(Decay2) //Continues to 02074EAC } else { //If the decay isn't 0 02074E84 E1D410DB ldrsb r1,[r4,0Bh] //Load Sustain as TargetVolume 02074E88 EBFFFFB2 bl 2074D58h //This function handles parsing all envelope duration parameter values . R0=EnvelopeBegAddress, R1=TargetVolume, R2=EnvelopeParam 02074E8C E3A00005 mov r0,5h 02074E90 E5C4001C strb r0,[r4,1Ch] //Set Envelope state to 5(Decay) 02074E94 EA000004 b 2074EACh //Continues to 02074EAC } } else { //If the Hold isn't 0 02074E64 E3A0107F mov r1,7Fh //Set 0x7F(Max) as TargetVolume 02074E68 EBFFFFBA bl 2074D58h //This function handles parsing all envelope duration parameter values . R0=EnvelopeBegAddress, R1=TargetVolume, R2=EnvelopeParam 02074E6C E3A00004 mov r0,4h 02074E70 E5C4001C strb r0,[r4,1Ch] //Set Envelope state to 4(Hold) 02074E74 EA00000C b 2074EACh //Continues to 02074EAC } } else { //If the attack is not 0, we start in attack phase 02074E2C E5D43008 ldrb r3,[r4,8h] //Load initial attack volume 02074E30 E3A02003 mov r2,3h 02074E34 E3A0107F mov r1,7Fh //Set TargetVolume as 0x7F(Max) 02074E38 E1A03B83 mov r3,r3,lsl 17h // 0x7F << 0x17 == 0x3F800000 (Maximum) 02074E3C E5843010 str r3,[r4,10h] //Possibly stores the initial volume value, and process it later 02074E40 E5C4201C strb r2,[r4,1Ch] //Set the envelope phase to 3(Attack) 02074E44 E5D42009 ldrb r2,[r4,9h] //Load Attack into R2 to be processed by the envelope param processing function 02074E48 EBFFFFC2 bl 2074D58h //This function handles parsing all envelope duration parameter values . R0=EnvelopeBegAddress, R1=TargetVolume, R2=EnvelopeParam 02074E4C EA000016 b 2074EACh //Continues to 02074EAC } 02074EAC E3A00001 mov r0,1h 02074EB0 E5C4001E strb r0,[r4,1Eh] //Probably a boolean to indicate an envelope is being processed ? 02074EB4 E8BD8010 pop r4,r15 //Return } [/font] And here's the function that handles all envelope parameters that are a duration: [font=Fixedsys] //Target volume is the volume the channel should have after the envelope parameter's duration Fun_02074D58( R0(SplitEnvelopeAddress), R1(TargetVolume), R2(EnvelopeParam) ) { 02074D58 E92D4038 push r3-r5,r14 02074D5C E1A05000 mov r5,r0 02074D60 E1A04001 mov r4,r1 02074D64 E352007F cmp r2,7Fh //See if the envelope parameter is == 0x7F 02074D68 1A000004 bne 02074D80 if( EnvelopeParam != 0x7F ) { 02074D80 E5C5401D strb r4,[r5,1Dh] //Put the TargetVolume here 02074D84 E5D53001 ldrb r3,[r5,1h] //Load multiplier2 02074D88 E3530000 cmp r3,0h 02074D8C 1A000007 bne 02074DB0 if( multiplier2 != 0 ) { 02074DB0 E59F0050 ldr r0,=20B0F50h //16 bits lookup table for durations 02074DB4 E1A01082 mov r1,r2,lsl 1h //R1 = EnvelopeParam << 1 (Basically, multiply by 2 the envelope param, so that we get a byte offset in a 16bits integer array) 02074DB8 E19020B1 ldrh r2,[r0,r1] //Get the duration from the table 02074DBC E59F1040 ldr r1,=22B7330h //That's the static address of DSE driver's memory 02074DC0 E3A00FFA mov r0,3E8h 02074DC4 E0020293 mul r2,r3,r2 //We multiply the duration with multiplier2 (the envelope duration multiplier) 02074DC8 E0000092 mul r0,r2,r0 //We multiply our duration by 1000 02074DCC E1D112F8 ldrsh r1,[r1,28h] //This address always contains the value 10000 02074DD0 EB006C33 bl 0208FEA4 //(Division signed R0 = R0 / R1) //Continues to 02074DD4.. } else { 02074D90 E59F0068 ldr r0,=20B1050h //32 bits lookup table for durations 02074D94 E59F1068 ldr r1,=22B7330h //That's the static address of DSE driver's memory 02074D98 E7902102 ldr r2,[r0,r2,lsl 2h] //Multiply the EnvelopeParam by 4( EnvelopeParam << 2 ) to get the byte offset in a int32 array 02074D9C E3A00FFA mov r0,3E8h 02074DA0 E0000092 mul r0,r2,r0 //We multiply our duration by 1000 02074DA4 E1D112F8 ldrsh r1,[r1,28h] //This address always contains the value 10000 02074DA8 EB006CC0 bl 020900B0 //(Unsigned division R0 = R0 / R1) 02074DAC EA000008 b 02074DD4 //Continues to 02074DD4.. } 02074DD4 E5850018 str r0,[r5,18h] //Put the duration of the envelope phase in there 02074DD8 E5951018 ldr r1,[r5,18h] //Read it back into R1 02074DDC E3510000 cmp r1,0h if( EnvelopePhaseDuration == 0 ) { 02074DE0 03A00000 moveq r0,0h 02074DE4 05850014 streq r0,[r5,14h] //Set the actual volume to 0 (This may also be the difference between initial and target volume) 02074DE8 08BD8038 popeq r3-r5,r15 //Return } 02074DEC E5950010 ldr r0,[r5,10h] //Load InitialVolume for the envelope phase 02074DF0 E0600B84 rsb r0,r0,r4,lsl 17h // (TargetVolume << 0x17) - InitialVolume, or (2^23 * TargetVolume) - InitialVolume 02074DF4 EB006C2A bl 0208FEA4 //(Division signed R0 = R0 / R1) 02074DF8 E5850014 str r0,[r5,14h] //Set the actual volume (This may also be the difference between initial and target volume) 02074DFC E8BD8038 pop r3-r5,r15 } else { //Envelope disabled 02074D6C E3A00000 mov r0,0h 02074D70 E5850014 str r0,[r5,14h] //Set the actual volume to 0 (This may also be the difference between initial and target volume) 02074D74 E2400106 sub r0,r0,80000001h //This basically puts 0x7FFFFFFF into R0 (Aka the maximum signed, positive value for a signed 16bits integer ) 02074D78 E5850018 str r0,[r5,18h] //Put that as duration for the envelope phase 02074D7C E8BD8038 pop r3-r5,r15 } } [/font] And here are the 2 duration lookup tables used in the function above: [font=Fixedsys] const int16_t Lookup_Table_020B0F50 [128] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0023, 0x0028, 0x002D, 0x0033, 0x0039, 0x0040, 0x0048, 0x0050, 0x0058, 0x0062, 0x006D, 0x0078, 0x0083, 0x0090, 0x009E, 0x00AC, 0x00BC, 0x00CC, 0x00DE, 0x00F0, 0x0104, 0x0119, 0x012F, 0x0147, 0x0160, 0x017A, 0x0196, 0x01B3, 0x01D2, 0x01F2, 0x0214, 0x0238, 0x025E, 0x0285, 0x02AE, 0x02D9, 0x0307, 0x0336, 0x0367, 0x039B, 0x03D1, 0x0406, 0x0442, 0x047E, 0x04C4, 0x0500, 0x0546, 0x058C, 0x0622, 0x0672, 0x06CC, 0x071C, 0x0776, 0x07DA, 0x0834, 0x0898, 0x0906, 0x096A, 0x09D8, 0x0A50, 0x0ABE, 0x0B40, 0x0BB8, 0x0C3A, 0x0CBC, 0x0D48, 0x0DDE, 0x0E6A, 0x0F00, 0x0FA0, 0x1040, 0x10EA, 0x1194, 0x123E, 0x12F2, 0x13B0, 0x146E, 0x1536, 0x15FE, 0x16D0, 0x17A2, 0x187E, 0x195A, 0x1A40, 0x1B30, 0x1C20, 0x1D1A, 0x1E1E, 0x1F22, 0x2030, 0x2148, 0x2260, 0x2382, 0x2710, 0x7FFF }; const int32_t Lookup_Table_020B1050 [128] = { 0x00000000, 0x00000004, 0x00000007, 0x0000000A, 0x0000000F, 0x00000015, 0x0000001C, 0x00000024, 0x0000002E, 0x0000003A, 0x00000048, 0x00000057, 0x00000068, 0x0000007B, 0x00000091, 0x000000A8, 0x00000185, 0x000001BE, 0x000001FC, 0x0000023F, 0x00000288, 0x000002D6, 0x0000032A, 0x00000385, 0x000003E5, 0x0000044C, 0x000004BA, 0x0000052E, 0x000005A9, 0x0000062C, 0x000006B5, 0x00000746, 0x00000BCF, 0x00000CC0, 0x00000DBD, 0x00000EC6, 0x00000FDC, 0x000010FF, 0x0000122F, 0x0000136C, 0x000014B6, 0x0000160F, 0x00001775, 0x000018EA, 0x00001A6D, 0x00001BFF, 0x00001DA0, 0x00001F51, 0x00002C16, 0x00002E80, 0x00003100, 0x00003395, 0x00003641, 0x00003902, 0x00003BDB, 0x00003ECA, 0x000041D0, 0x000044EE, 0x00004824, 0x00004B73, 0x00004ED9, 0x00005259, 0x000055F2, 0x000059A4, 0x000074CC, 0x000079AB, 0x00007EAC, 0x000083CE, 0x00008911, 0x00008E77, 0x000093FF, 0x000099AA, 0x00009F78, 0x0000A56A, 0x0000AB80, 0x0000B1BB, 0x0000B81A, 0x0000BE9E, 0x0000C547, 0x0000CC17, 0x0000FD42, 0x000105CB, 0x00010E82, 0x00011768, 0x0001207E, 0x000129C4, 0x0001333B, 0x00013CE2, 0x000146BB, 0x000150C5, 0x00015B02, 0x00016572, 0x00017015, 0x00017AEB, 0x000185F5, 0x00019133, 0x0001E16D, 0x0001EF07, 0x0001FCE0, 0x00020AF7, 0x0002194F, 0x000227E6, 0x000236BE, 0x000245D7, 0x00025532, 0x000264CF, 0x000274AE, 0x000284D0, 0x00029536, 0x0002A5E0, 0x0002B6CE, 0x0002C802, 0x000341B0, 0x000355F8, 0x00036A90, 0x00037F79, 0x000394B4, 0x0003AA41, 0x0003C021, 0x0003D654, 0x0003ECDA, 0x000403B5, 0x00041AE5, 0x0004326A, 0x00044A45, 0x00046277, 0x00047B00, 0x7FFFFFFF };[/font] If you look at this, I wonder if the you got is the same variable as the R5 + 0x18 I got ? Here's a breakpoint for it : [0x22B7AC0]!? Though, for me its the time left for the current volume envelope phase. And the value decreases while the note is played. Do you have the address contained in the R3 register when the code was run ? Most of the DSE stuff is stored in a static memory location, so it could help seeing when the volume envelope's value is added to all that.
-
I really can't say much about that. The best way to be sure would be to run the game in the debugger, load a state where something with exclusive items is happening, and place some breakpoints. You could also just try setting the value to 0xA on another item and try to see what happens in the game, using an edited savegame or something. All I've done in statsutil was just export/import everything to/from XML, no processing at all. So I can't really say much on this.. I'm glad you like it ! And don't worry about it, its my fault for not updating my notes ^^; Thanks for mentioning it though ! I'll fix that right away ! And If I can help you with anything in particular feel free to ask ! By the way, you wouldn't happen to have messed around with the volume envelopes by any chances ? I've been having some difficulties reproducing them correctly. And I'm not very good yet with reading assembly code
-
So, I've been trying to fix whatever I ended up breaking in gfxutils while coding the base for audioutil, just so I can eventually merge my branch to master without issues. But then I just broke everything even more, and I think I'll have to rewrite the image handling code.. It was a nice little experiment with templates, but I didn't put enough thoughts into it and the code is pretty gross, and now gfxutils can't seem to export sprites correctly anymore.. Also, I've noticed that I left a lot of things unfinished in gfxutil and I haven't even published statsutil yet.. If anyone would like to help with researching some of the file formats, or even looking at the game during debug and figuring out how things are loaded, it would be really appreciated ! The dungeon tiles format, and the sprite file format are particularly hard to figure out, and possibly that having someone else look at them would help. I'd like to have a toolkit ready to mod PMD2 by the time PSMD is released, and I don't think I'll manage on my own at this rate.. Also, I'm going to begin working on PSMD once its out, and once I can get access to its content. But, since the engine for the game will most likely be the same as GTI and Etrian Mystery dungeon, I'm also trying to get a head start and reverse the file formats from those games, since they're nearly identical.
-
It works ! I figured out how the play note events are actually changing the track's current octave, which fixed notes playing way too high. Here's how the note's first parameter is actually supposed to be parsed (there's probably some unneeded fluff): [font=Fixedsys] static const uint8_t NoteEvParam1NoteMask = 0x0F; //( 0000 1111 ) The id of the note "eDSENote" is stored in the lower nybble static const uint8_t NoteEvParam1PitchMask = 0x30; //( 0011 0000 ) The value of those 2 bits in the "param1" of a NoteOn event indicate if/how to modify the track's current pitch. static const uint8_t NoteEvParam1NbParamsMask = 0xC0; //( 1100 0000 ) The value of those two bits indicates the amount of bytes to be parsed as parameters for the note on event static const int8_t NoteEvOctaveShiftRange = 2; //The Nb of octave the note event can modify the track's current octave //... void ParsePlayNoteParam1( uint8_t noteparam1, uint8_t & inout_curoctave, uint8_t & out_param2len, uint8_t & out_midinote ) { //1. Get param2's len out_param2len = ( ( noteparam1 & NoteEvParam1NbParamsMask ) >> 6 ) & 0x3; //(0011) just to be sure no sign bits slip through somehow //2. Get and apply the octave modifiere int8_t octavemod = ( ( (noteparam1 & NoteEvParam1PitchMask) >> 4 ) & 0x3 ) - NoteEvOctaveShiftRange; inout_curoctave = static_cast<int8_t>(inout_curoctave) + octavemod; //3. Get the midi note out_midinote = ( inout_curoctave * static_cast<uint8_t>(eNote::nbNotes) ) + (noteparam1 & 0xF); //eNote::nbNotes == 12 }[/font] Param2 is the duration the note is held, it can be stored on a variable amount of bytes from 0 to 3. I completely fixed the envelopes, apparently that the duration within the tables were in milliseconds! I had to use a pretty dumb way to simulate the initial attack volume parameter, making another instrument with no attack phase that was attenuated to the initial attack volume. But it works! And to simulate the second decay, I just added the durations of both the first and second decay together, and whenever the second decay isn't 0x7F, the sustain volume is set to the absolute minimum, which simulates the actual effect of the parameter very well ! Here are some mp3 : https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/august05/25_B_DUN_ENGANNOIW.mp3 https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/august05/32_B_DUN_EREKIHEIG.mp3 https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/august05/33_B_DUN_NISHINOSA.mp3 Still have some issues with this one : https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/august05/81_B_EVENT_SEPARAT.mp3 After I just need to fix some issues with some tracks and figure out some missing events. And I still have to add LFO/Modulator support, which will handle the missing vibrato effects.
-
Finally fixed my soundfont library ! I just ran a VM and loaded the soundfont into fluidsynth via commandline with the verbose option, and it immediately told me the exact issue It was a bad chunk length, because I forgot to count the ending 0 of a string.. And there was also another little issue to fix, I forgot to sort my generators properly.. But now looping works pretty damn well. I think I'm close to figuring out the time unit for the volume envelope. They're still off, as you can probably tell from the mp3s. And there is still an issue with pitch correction on multi-zone instruments where it suddenly plays the higher sample at a completely wrong pitch. https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/august03/10_B_SYS_MONSTERHO.mp3 https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/august03/81_B_EVENT_SEPARAT.mp3 This one is nearly perfect: https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/august03/3_B_SYS_MINIGAME.mp3 But there is something breaking the loop for some reasons..
-
Progress on SWD: Welp, I still can't turn the duration values I got from the table into time properly.. I know that, when an envelope parameter is 0x7E, the duration of the corresponding envelope phase is then ~10 seconds, from a recording I've made. So setting the "Hold" to 0x7E will have the note held at maximum volume for at most ~10 seconds, if its held for longer than that. Now if you look at the duration lookup table: [font=Fixedsys] const int16_t Lookup_Table_20B0F50 [128] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0023, 0x0028, 0x002D, 0x0033, 0x0039, 0x0040, 0x0048, 0x0050, 0x0058, 0x0062, 0x006D, 0x0078, 0x0083, 0x0090, 0x009E, 0x00AC, 0x00BC, 0x00CC, 0x00DE, 0x00F0, 0x0104, 0x0119, 0x012F, 0x0147, 0x0160, 0x017A, 0x0196, 0x01B3, 0x01D2, 0x01F2, 0x0214, 0x0238, 0x025E, 0x0285, 0x02AE, 0x02D9, 0x0307, 0x0336, 0x0367, 0x039B, 0x03D1, 0x0406, 0x0442, 0x047E, 0x04C4, 0x0500, 0x0546, 0x058C, 0x0622, 0x0672, 0x06CC, 0x071C, 0x0776, 0x07DA, 0x0834, 0x0898, 0x0906, 0x096A, 0x09D8, 0x0A50, 0x0ABE, 0x0B40, 0x0BB8, 0x0C3A, 0x0CBC, 0x0D48, 0x0DDE, 0x0E6A, 0x0F00, 0x0FA0, 0x1040, 0x10EA, 0x1194, 0x123E, 0x12F2, 0x13B0, 0x146E, 0x1536, 0x15FE, 0x16D0, 0x17A2, 0x187E, 0x195A, 0x1A40, 0x1B30, 0x1C20, 0x1D1A, 0x1E1E, 0x1F22, 0x2030, 0x2148, 0x2260, 0x2382, 0x2710, 0x7FFF };[/font] The value at 0x7E (126) is 0x2710, or 10,000.(Funny coincidence, considering we divide values from that table by 0x2710 later on!) And then the game takes this value we got from the table, and multiplies it by 1,000, and then divide it by 10,000. I think it may be centiseconds, which would fit with the envelope timers ticking much faster than the DSE timer.. But all conversions I attempted to the sounfont format didn't work very well at all.. I might be doing something wrong.. Progress on SMD: Also, as an extra bonus, here's the lookup table used for music track events with values above 0x90 : [font=Fixedsys] /* Table for events codes that are higher than 0x90. Just subtract 144 (0x90) from the event's code, and use the result as index in the table ! Located at 0x20B0B90 in RAM. */ static const std::array<uint32_t, 240> EventHandlers { 0x02071928, 0x02071934, 0x0207194C, 0x0207195C, //Ev 0x90 - 0x93 0x02071978, 0x0207199C, 0x0207191C, 0x0207191C, //Ev 0x94 - 0x97 0x020719C8, 0x02071A14, 0x0207191C, 0x0207191C, //Ev 0x98 - 0x9B 0x02071A1C, 0x02071A5C, 0x02071A98, 0x0207191C, //Ev 0x9C - 0x9F 0x02071AC0, 0x02071ACC, 0x0207191C, 0x0207191C, //Ev 0xA0 - 0xA3 0x02071AE0, 0x02071B20, 0x0207191C, 0x0207191C, //Ev 0xA4 - 0xA7 0x02071B60, 0x02071B8C, 0x02071BBC, 0x02071BEC, //Ev 0xA8 - 0xAB 0x02071BF4, 0x0207191C, 0x0207191C, 0x02071C3C, //Ev 0xAC - 0xAF 0x02071CC8, 0x02071CE0, 0x02071D00, 0x02071D20, //Ev 0xB0 - 0xB3 0x02071D40, 0x02071D70, 0x02071D90, 0x0207191C, //Ev 0xB4 - 0xB7 0x0207191C, 0x0207191C, 0x0207191C, 0x0207191C, //Ev 0xB8 - 0xBB 0x02071DB0, 0x0207191C, 0x02071DBC, 0x02071DD8, //Ev 0xBC - 0xBF 0x02071E10, 0x0207191C, 0x0207191C, 0x02071E20, //Ev 0xC0 - 0xC3 0x0207191C, 0x0207191C, 0x0207191C, 0x0207191C, //Ev 0xC4 - 0xC7 0x0207191C, 0x0207191C, 0x0207191C, 0x02071E2C, //Ev 0xC8 - 0xCB 0x0207191C, 0x0207191C, 0x0207191C, 0x0207191C, //Ev 0xCC - 0xCF 0x02071E34, 0x02071EB4, 0x02071F3C, 0x02071FC4, //Ev 0xD0 - 0xD3 0x02072054, 0x02072144, 0x0207216C, 0x02072184, //Ev 0xD4 - 0xD7 0x020721B0, 0x0207191C, 0x0207191C, 0x020721C8, //Ev 0xD8 - 0xDB 0x020721D4, 0x0207222C, 0x0207191C, 0x02072254, //Ev 0xDC - 0xDF 0x0207227C, 0x02072310, 0x020723C0, 0x0207241C, //Ev 0xE0 - 0xE3 0x020724A8, 0x02072504, 0x0207191C, 0x0207252C, //Ev 0xE4 - 0xE7 0x02072554, 0x020725D4, 0x02072668, 0x0207191C, //Ev 0xE8 - 0xEB 0x020726C4, 0x02072720, 0x0207191C, 0x02072748, //Ev 0xEC - 0xEF 0x02072770, 0x020727C8, 0x020727FC, 0x02072938, //Ev 0xEC - 0xEF 0x0207191C, 0x0207191C, 0x0207296C, 0x0207191C, //Ev 0xF0 - 0xF3 0x0207299C, 0x0207191C, 0x0207191C, 0x0207191C, //Ev 0xF4 - 0xF7 0x0207191C, 0x0207191C, 0x0207191C, 0x0207191C, //Ev 0xF8 - 0xFB 0x02072D9C, 0x02072DDC, 0x00000000, 0x00000000, //Ev 0xFC - 0xFF 0x00000000, 0x02072DF4, 0x02072FA4, 0x02072E04, //No ideas what the rest is for.. 0x00000000, 0x00000000, 0x02072E90, 0x02072EE8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x020731F4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x020731FC, 0x02073200, 0x02073204, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02072DBC, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02072F3C, 0x02072F64, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02073094, 0x020730A8, 0x00000000, 0x020730BC, 0x020730E4, 0x0207312C, 0x020731C4, 0x020730F8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02072F68, 0x020730A8, 0x020730BC, 0x020730D0, 0x02073094, 0x020731DC, 0x0207311C, 0x02072F6C, 0x00000000, 0x02072F70, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02072F84, 0x02072F94, 0x02072F74, 0x02072F74, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02072F34, 0x02072FA8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x02072FAC, 0x02072FD8, 0x00000000, 0x02072FFC, 0x00000000, 0x00000000, 0x0207307C, 0x02073088 }; [/font] Basically, each events has a corresponding handler function in this table. And here's a text file disassembly of the WRAM as the code using this was run (Its just disassembler output, not a memory dump or anything of the sort) : I just thought others might like to know about this Its going to take a long while to document all those though... And this is the table containing the 16 possible events "DT" durations. (Event code 0x80 to 0x8F (0x80 is the longest, 0x8F is the shortest) ) // Location 0x20B0B7C const std::array<uint8_t, 16> delays { 96, 72, 64, 48, 36, 32, 24, 18, 16, 12, 9, 8, 6, 4, 3, 2 }; Here's the code that handles all music track events (with some notes and some added "if" to better illustrate) : [font=Fixedsys] [color="#008000"]///LBL10[/color] 02071248 E5D53000 ldrb r3,[r5] //Reads an event 0207124C E2850001 add r0,r5,1h //Increment the track-reading pointer 02071250 E1A05000 mov r5,r0 //Increment the track-reading pointer 02071254 E3530080 cmp r3,80h if( Event < 0x80 ) { 02071258 3A000010 bcc 20712A0h [color="#008000"]///GOTO LBL1[/color] } 0207125C E3530090 cmp r3,90h if( Event < 0x90 ) { 02071260 3A000008 bcc 2071288h [color="#008000"]///GOTO LBL2[/color] } 02071264 E59F2170 ldr r2,=20B0B90h //Put the address of the event lookup table into R2 ! 02071268 E1A01007 mov r1,r7 0207126C E0822103 add r2,r2,r3,lsl 2h 02071270 E5125240 ldr r5,[r2,-240h] 02071274 E1A02006 mov r2,r6 02071278 E1A03004 mov r3,r4 0207127C E12FFF35 blx r5 02071280 E1A05000 mov r5,r0 02071284 EA000048 b 20713ACh [color="#008000"]///GOTO LBL3[/color] [color="#008000"]///LBL2[/color] 02071288 E59F0150 ldr r0,=20B0B7Ch //This is the address of the table containing the "DT" durations in ticks 0207128C E0800003 add r0,r0,r3 02071290 E5500080 ldrb r0,[r0,-80h] 02071294 E5860010 str r0,[r6,10h] 02071298 E586000C str r0,[r6,0Ch] 0207129C EA000042 b 20713ACh [color="#008000"]///GOTO LBL3[/color] [color="#008000"]///LBL1[/color] 020712A0 E5CD3003 strb r3,[r13,3h] 020712A4 E5D01000 ldrb r1,[r0] 020712A8 E5D65004 ldrb r5,[r6,4h] 020712AC E3A0300C mov r3,0Ch 020712B0 E1A02A01 mov r2,r1,lsl 14h 020712B4 E1A02C42 mov r2,r2,asr 18h 020712B8 E2022003 and r2,r2,3h 020712BC E2422002 sub r2,r2,2h 020712C0 E1A02C02 mov r2,r2,lsl 18h 020712C4 E0852C42 add r2,r5,r2,asr 18h 020712C8 E1A02C02 mov r2,r2,lsl 18h 020712CC E1A05C42 mov r5,r2,asr 18h 020712D0 E201200F and r2,r1,0Fh 020712D4 E1022385 smlabb r2,r5,r3,r2 020712D8 E5CD2002 strb r2,[r13,2h] 020712DC E1A01341 mov r1,r1,asr 6h 020712E0 E5C65004 strb r5,[r6,4h] 020712E4 E21110FF ands r1,r1,0FFh 020712E8 E2805001 add r5,r0,1h 020712EC 05963014 ldreq r3,[r6,14h] 020712F0 0A000008 beq 2071318h [color="#008000"]///GOTO LBL4[/color] 020712F4 E3510000 cmp r1,0h 020712F8 E3A03000 mov r3,0h 020712FC 0A000004 beq 2071314h [color="#008000"]///GOTO LBL5[/color] [color="#008000"]///LBL6[/color] 02071300 E4D50001 ldrb r0,[r5],1h 02071304 E2411001 sub r1,r1,1h 02071308 E21110FF ands r1,r1,0FFh 0207130C E0803403 add r3,r0,r3,lsl 8h 02071310 1AFFFFFA bne 2071300h [color="#008000"]///GOTO LBL6[/color] [color="#008000"]///LBL5[/color] 02071314 E5863014 str r3,[r6,14h] [color="#008000"]///LBL4[/color] 02071318 E5D62005 ldrb r2,[r6,5h] 0207131C E3A01000 mov r1,0h 02071320 E59F00BC ldr r0,=2040811h 02071324 E0020293 mul r2,r3,r2 02071328 E0830092 umull r0,r3,r2,r0 0207132C E0420003 sub r0,r2,r3 02071330 E08330A0 add r3,r3,r0,lsr 1h 02071334 E1A03323 mov r3,r3,lsr 6h 02071338 E58D3004 str r3,[r13,4h] 0207133C E5CD1000 strb r1,[r13] 02071340 E1D600D8 ldrsb r0,[r6,8h] 02071344 E3500000 cmp r0,0h 02071348 1A000012 bne 2071398h [color="#008000"]///GOTO LBL7[/color] 0207134C E5D40004 ldrb r0,[r4,4h] 02071350 E28D1000 add r1,r13,0h 02071354 E3100002 tst r0,2h 02071358 0A000003 beq 207136Ch [color="#008000"]///GOTO LBL8[/color] 0207135C E5D62007 ldrb r2,[r6,7h] 02071360 E1A00004 mov r0,r4 02071364 EB000AA9 bl 2073E10h [color="#FF8C00"]///EXEC Fun_02073E10[/color] 02071368 EA00000A b 2071398h [color="#008000"]///GOTO LBL7[/color] [color="#008000"]///LBL8[/color] 0207136C E1A00004 mov r0,r4 02071370 EB000ACA bl 2073EA0h [color="#FF8C00"]///EXEC Fun_02073EA0[/color] 02071374 E3A02000 mov r2,0h 02071378 E28D1000 add r1,r13,0h 0207137C E1A00004 mov r0,r4 02071380 E584201C str r2,[r4,1Ch] 02071384 EB000A53 bl 2073CD8h [color="#FF8C00"]///EXEC Fun_02073CD8[/color] 02071388 E1B01000 movs r1,r0 0207138C 0A000001 beq 2071398h [color="#008000"]///GOTO LBL7[/color] 02071390 E1A00004 mov r0,r4 02071394 EB000AD0 bl 2073EDCh [color="#FF8C00"]///EXEC Fun_02073EDC[/color] [color="#008000"]///LBL7[/color] 02071398 E5DD0002 ldrb r0,[r13,2h] 0207139C E5C60007 strb r0,[r6,7h] 020713A0 E5D40004 ldrb r0,[r4,4h] 020713A4 E3C00002 bic r0,r0,2h 020713A8 E5C40004 strb r0,[r4,4h] [color="#008000"]///LBL3[/color] 020713AC E1D600D2 ldrsb r0,[r6,2h] 020713B0 E3500000 cmp r0,0h 020713B4 0A000002 beq 20713C4h [color="#008000"]///GOTO LBL9[/color] 020713B8 E596000C ldr r0,[r6,0Ch] 020713BC E3500000 cmp r0,0h 020713C0 0AFFFFA0 beq 2071248h [color="#008000"]///GOTO LBL10[/color] [color="#008000"]///LBL9[/color] 020713C4 E596000C ldr r0,[r6,0Ch] 020713C8 E2400001 sub r0,r0,1h 020713CC E586000C str r0,[r6,0Ch] 020713D0 E586501C str r5,[r6,1Ch] 020713D4 E28DD008 add r13,r13,8h 020713D8 E8BD80F8 pop r3-r7,r15 [/font] FullWramDisassembly.zip
-
Wow.. you ninja-ed me Well, it wasn't easy to get this far, don't worry too much about it I've been trying on and off to figure them out for over a year now. I had to do a lot of trial and error and modifying the files myself to play specific notes or events. And nobody apparently even bothered trying reversing the DSE format before, so you had to start from scratch Here's the dropbox link to my current notes, if you're interested : https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/PMD2_MusicAndSoundFormats.txt Its always fairly messy and not always fully up to date though. And I constantly write and erase stuff as I go. But anyways. I mostly fixed the issues with the notes, it was mainly the root note, and pitch correction of each samples that wasn't parsed correctly. There is still a bit of an issue with the pitch correction, because the NDS can do 255 semitones pitch correction while soundfont supports like 2 per sample. So I have to use the per instrument pitch correction, but then its limited between -120 and 120.. I might shift the root note with the remaining semitones, but IDK if it wouldn't mess things up more.. And all the sample/preset/splits data is located in the matching SWD, and in the master SWD file. The SMD is strictly for the event tracks. And yeah, those are called "Splits" by the DSE devs. And the Sounfont format has a very unintuitive way of handling those, dealing with bag and zone nonsense when things could have been so much simpler.. I wish DLS had caught on I'm actually dealing with issues with the sounfont format itself now.. Samples won't loop at all for some reasons, in anything but polyphone. And loops are still creating audio artifacts even though I followed their sample looping requirements.. I couldn't find a single library to write those to disk. And the official documentation is terrible. And thanks for the midis, but I'll probably be fine at this point. Several months ago someone linked me to an utility that could rip the PMD2 midis, and we got some pretty accurate midis from those. Though it didn't do anything about the samples at all.
-
When you realize that elusive, very complex, function 0x0208FEA4 you've been trying to figure out was actually the NDS's implementation of a signed division.. Alright, so after much messing around in the game's code, I managed to kind of understand how durations are parsed from the envelope. The value of the envelope parameter for durations is used as index in one of two table containing a 16 bits value, and the other a 32 bits value. If the value is obtained from the 16 bits table, its multiplied by 1,000, and divided by 10,000. The result is used in a counter for each phases of the envelope. Though, now the challenge is figuring out, how to turn that value into seconds ? Those aren't DSE ticks, like the music track uses.. I also figured out the loop point data. I decided to take a look at the NDS's sound registers while it was playing a sample I knew about. It turns out the loop data from the SWD is just copied exactly as-is into the sound registers. And they're in int32, not in bytes or samples..
-
Alright ! So I made a bit more progress. I found out that envelope parameters are actually used as indexes in 2 possible 128 slots lookup tables. I noticed that, the values I labeled unk35 to unk38 are in fact multipliers for the envelope parameters. And whether the values are 0, or not decides what lookup table to use to get the duration of the envelope paramter. If its 0, we get the value from the 32 bits lookup table: (Located at 0x20B1050) [font=Fixedsys] const int32_t Duration_Lookup_Table_B1 [128] = { 0x00000000, 0x00000004, 0x00000007, 0x0000000A, 0x0000000F, 0x00000015, 0x0000001C, 0x00000024, 0x0000002E, 0x0000003A, 0x00000048, 0x00000057, 0x00000068, 0x0000007B, 0x00000091, 0x000000A8, 0x00000185, 0x000001BE, 0x000001FC, 0x0000023F, 0x00000288, 0x000002D6, 0x0000032A, 0x00000385, 0x000003E5, 0x0000044C, 0x000004BA, 0x0000052E, 0x000005A9, 0x0000062C, 0x000006B5, 0x00000746, 0x00000BCF, 0x00000CC0, 0x00000DBD, 0x00000EC6, 0x00000FDC, 0x000010FF, 0x0000122F, 0x0000136C, 0x000014B6, 0x0000160F, 0x00001775, 0x000018EA, 0x00001A6D, 0x00001BFF, 0x00001DA0, 0x00001F51, 0x00002C16, 0x00002E80, 0x00003100, 0x00003395, 0x00003641, 0x00003902, 0x00003BDB, 0x00003ECA, 0x000041D0, 0x000044EE, 0x00004824, 0x00004B73, 0x00004ED9, 0x00005259, 0x000055F2, 0x000059A4, 0x000074CC, 0x000079AB, 0x00007EAC, 0x000083CE, 0x00008911, 0x00008E77, 0x000093FF, 0x000099AA, 0x00009F78, 0x0000A56A, 0x0000AB80, 0x0000B1BB, 0x0000B81A, 0x0000BE9E, 0x0000C547, 0x0000CC17, 0x0000FD42, 0x000105CB, 0x00010E82, 0x00011768, 0x0001207E, 0x000129C4, 0x0001333B, 0x00013CE2, 0x000146BB, 0x000150C5, 0x00015B02, 0x00016572, 0x00017015, 0x00017AEB, 0x000185F5, 0x00019133, 0x0001E16D, 0x0001EF07, 0x0001FCE0, 0x00020AF7, 0x0002194F, 0x000227E6, 0x000236BE, 0x000245D7, 0x00025532, 0x000264CF, 0x000274AE, 0x000284D0, 0x00029536, 0x0002A5E0, 0x0002B6CE, 0x0002C802, 0x000341B0, 0x000355F8, 0x00036A90, 0x00037F79, 0x000394B4, 0x0003AA41, 0x0003C021, 0x0003D654, 0x0003ECDA, 0x000403B5, 0x00041AE5, 0x0004326A, 0x00044A45, 0x00046277, 0x00047B00, 0x7FFFFFFF };[/font] If its not 0, we get the value from the 16 bits lookup table: (Located at 0x20B0F50) [font=Fixedsys] const int16_t Duration_Lookup_Table_A1 [128] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F, 0x0020, 0x0023, 0x0028, 0x002D, 0x0033, 0x0039, 0x0040, 0x0048, 0x0050, 0x0058, 0x0062, 0x006D, 0x0078, 0x0083, 0x0090, 0x009E, 0x00AC, 0x00BC, 0x00CC, 0x00DE, 0x00F0, 0x0104, 0x0119, 0x012F, 0x0147, 0x0160, 0x017A, 0x0196, 0x01B3, 0x01D2, 0x01F2, 0x0214, 0x0238, 0x025E, 0x0285, 0x02AE, 0x02D9, 0x0307, 0x0336, 0x0367, 0x039B, 0x03D1, 0x0406, 0x0442, 0x047E, 0x04C4, 0x0500, 0x0546, 0x058C, 0x0622, 0x0672, 0x06CC, 0x071C, 0x0776, 0x07DA, 0x0834, 0x0898, 0x0906, 0x096A, 0x09D8, 0x0A50, 0x0ABE, 0x0B40, 0x0BB8, 0x0C3A, 0x0CBC, 0x0D48, 0x0DDE, 0x0E6A, 0x0F00, 0x0FA0, 0x1040, 0x10EA, 0x1194, 0x123E, 0x12F2, 0x13B0, 0x146E, 0x1536, 0x15FE, 0x16D0, 0x17A2, 0x187E, 0x195A, 0x1A40, 0x1B30, 0x1C20, 0x1D1A, 0x1E1E, 0x1F22, 0x2030, 0x2148, 0x2260, 0x2382, 0x2710, 0x7FFF };[/font] The locations are static, so its at the same place at every restarts. There's also another large static table that is used to both store and load sound related data from, its located at 0x22B7330. However, after looking up the value in the 16 bits Duration_Lookup table, a lot of things are happening to the values and I can't really tell what exactly.. First it gets multiplied by the corresponding multiplier stored between Unk35 to Unk38(I think), then, its multiplied by 1,000. (Jumped in from 0x02074D8C) [font=Fixedsys] 02074DB0 E59F0050 ldr r0,=20B0F50h //Load the address of "Attack_Lookup_Table_A1" 02074DB4 E1A01082 mov r1,r2,lsl 1h //Shift "Attack" by one to the left, and put it in R1. R1 = 0x46. (Equivalent to multiplying by 2 !(Accessing the table by index wouldn't require multiplying)) 02074DB8 E19020B1 ldrh r2,[r0,r1] //Load unsigned half-word, from lookup table #1 at 0x20B0F50 + 0x46( the "Attack" value multiplied by 2 ). R2 = 0x2D 02074DBC E59F1040 ldr r1,=22B7330h //Set R1 to the address of a static table in memory where we store our envelope stuff 02074DC0 E3A00FFA mov r0,3E8h //R0 = 0x3E8 (1,000) 02074DC4 E0020293 mul r2,r3,r2 //R2 = 1 * 0x2D ( Unk36 * ConvertedAttackValueFromLookupTable ) 02074DC8 E0000092 mul r0,r2,r0 //R0 = 0x2D(45) * 0x3E8(1,000) => 0xAFC8(45,000) 02074DCC E1D112F8 ldrsh r1,[r1,28h] //Load Signed Half-word from That static table at 0x22B7330. At byte 0x28. R1 = 0x2710 (10,000) 02074DD0 EB006C33 bl 208FEA4h //Exec sub-routine at 208FEA4[/font] .. ..But then the function at 208FEA4 is executed, and I have no clue what it does.. The value inside R0 is stored to memory after the function has run its course. When I ran it, it returned me 4 through R0.. I have no clues what could return 4 from 45,000, and be this elaborate.. (Sorry for the messy notes btw.. I just tend to put lots of stuff to keep track of what is going on.) [font=Fixedsys] (BRANCH and LINK 0208FEA4 ( R14 = 2074E4C -> 2074DD4, R15 = 2074DD0 -> 0208FEA4 ) ) 0208FEA4 E020C001 eor r12,r0,r1 //R12 = 0xAFC8(45,000) ^ 0x2710(10,000) => 0x88D8(35,032) 0208FEA8 E20CC102 and r12,r12,80000000h //R12 = 0x88D8 & 0x80000000 => 0 0208FEAC E3500000 cmp r0,0h //Check if 0xAFC8 < 0 if( R0 < 0 ) { 0208FEB0 B2600000 rsblt r0,r0,0h //RSB – Reverse Subtract, R0 = (0 - R0) 0208FEB4 B28CC001 addlt r12,r12,1h } 0208FEB8 E3510000 cmp r1,0h //Check if 0x2710 < 0 if( R1 < 0 ) { 0208FEBC B2611000 rsblt r1,r1,0h //RSB – Reverse Subtract, R1 = (0 - R1) 0208FEC0 0A000075 beq 209009Ch } 0208FEC4 E1500001 cmp r0,r1 if( ( (R0 - R1) < 0xFFFFFFFF ) (Actually more like !C) //Check if result of subtraction(cmp subtract its operands) was smaller than 32 bits(No carry) { 0208FEC8 31A01000 movcc r1,r0 0208FECC 33A00000 movcc r0,0h 0208FED0 3A000071 bcc 209009Ch } 0208FED4 E3A0201C mov r2,1Ch //R2 = 0x1C. 0208FED8 E1A03220 mov r3,r0,lsr 4h //R3 = 0xAFC8(45,000) >> 4 => 0xAFC(2,812) (Remove the lowest 4 bits) 0208FEDC E1510623 cmp r1,r3,lsr 0Ch //0x2710 - ( 0xAFC(2,812) >> 0xC )(Keep only the highest 3 bits ) ) if( ( 0x2710 - (0xAFC >> 12) ) == 0 || ( ( 0x2710 - (0xAFC >> 12) ) < 0) != (( 0x2710 - (0xAFC >> 12) ) < 0x7FFFFFFF) ) //Approximation { 0208FEE0 D2422010 suble r2,r2,10h // 0208FEE4 D1A03823 movle r3,r3,lsr 10h // } 0208FEE8 E1510223 cmp r1,r3,lsr 4h // 0x2710 - ( 0xAFC >> 4 ) if( ( 0x2710 - (0xAFC >> 4) ) == 0 || ( ( 0x2710 - (0xAFC >> 4) ) < 0) != (( 0x2710 - (0xAFC >> 4) ) <= 0x7FFFFFFF) ) { 0208FEEC D2422008 suble r2,r2,8h 0208FEF0 D1A03423 movle r3,r3,lsr 8h } 0208FEF4 E1510003 cmp r1,r3 //(0x2710 - 0xAFC) if( (0x2710 - 0xAFC) == 0 || ( (0x2710 - 0xAFC) < 0 ) != ( (0x2710 - 0xAFC) <= 0x7FFFFFFF ) ) { 0208FEF8 D2422004 suble r2,r2,4h 0208FEFC D1A03223 movle r3,r3,lsr 4h } 0208FF00 E1A00210 mov r0,r0,lsl r2 //R0 = 0xAFC8(45,000) << 0x1C => 0x80000000 0208FF04 E2611000 rsb r1,r1,0h //R1 = (0 - 0x2710) => 0xFFFFD8F0 0208FF08 E0900000 adds r0,r0,r0 //R0 = 0x80000000 + 0x80000000 => 0 0208FF0C E0822082 add r2,r2,r2,lsl 1h //R2 = 0x1C + (0x1C << 1) => 0x54 0208FF10 E08FF102 add r15,r15,r2,lsl 2h //R15 = 0x0208FF10 + (0x54 << 2) => 0x2090060 0208FF14 E1A00000 nop //Apparently the No-op here got R15 to +4, before it was incremented by +4, so we landed at 0x2090068 !! //The next part is a loop done 31 times at most. The operation that modifies R15 basically sets the amount of times to iterate through the loop { 0208FF18 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF1C 30433001 subcc r3,r3,r1 0208FF20 E0B00000 adcs r0,r0,r0 0208FF24 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF28 30433001 subcc r3,r3,r1 0208FF2C E0B00000 adcs r0,r0,r0 0208FF30 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF34 30433001 subcc r3,r3,r1 0208FF38 E0B00000 adcs r0,r0,r0 0208FF3C E0B13083 adcs r3,r1,r3,lsl 1h 0208FF40 30433001 subcc r3,r3,r1 0208FF44 E0B00000 adcs r0,r0,r0 0208FF48 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF4C 30433001 subcc r3,r3,r1 0208FF50 E0B00000 adcs r0,r0,r0 0208FF54 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF58 30433001 subcc r3,r3,r1 0208FF5C E0B00000 adcs r0,r0,r0 0208FF60 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF64 30433001 subcc r3,r3,r1 0208FF68 E0B00000 adcs r0,r0,r0 0208FF6C E0B13083 adcs r3,r1,r3,lsl 1h 0208FF70 30433001 subcc r3,r3,r1 0208FF74 E0B00000 adcs r0,r0,r0 0208FF78 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF7C 30433001 subcc r3,r3,r1 0208FF80 E0B00000 adcs r0,r0,r0 0208FF84 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF88 30433001 subcc r3,r3,r1 0208FF8C E0B00000 adcs r0,r0,r0 0208FF90 E0B13083 adcs r3,r1,r3,lsl 1h 0208FF94 30433001 subcc r3,r3,r1 0208FF98 E0B00000 adcs r0,r0,r0 0208FF9C E0B13083 adcs r3,r1,r3,lsl 1h 0208FFA0 30433001 subcc r3,r3,r1 0208FFA4 E0B00000 adcs r0,r0,r0 0208FFA8 E0B13083 adcs r3,r1,r3,lsl 1h 0208FFAC 30433001 subcc r3,r3,r1 0208FFB0 E0B00000 adcs r0,r0,r0 0208FFB4 E0B13083 adcs r3,r1,r3,lsl 1h 0208FFB8 30433001 subcc r3,r3,r1 0208FFBC E0B00000 adcs r0,r0,r0 0208FFC0 E0B13083 adcs r3,r1,r3,lsl 1h 0208FFC4 30433001 subcc r3,r3,r1 0208FFC8 E0B00000 adcs r0,r0,r0 0208FFCC E0B13083 adcs r3,r1,r3,lsl 1h 0208FFD0 30433001 subcc r3,r3,r1 0208FFD4 E0B00000 adcs r0,r0,r0 0208FFD8 E0B13083 adcs r3,r1,r3,lsl 1h 0208FFDC 30433001 subcc r3,r3,r1 0208FFE0 E0B00000 adcs r0,r0,r0 0208FFE4 E0B13083 adcs r3,r1,r3,lsl 1h 0208FFE8 30433001 subcc r3,r3,r1 0208FFEC E0B00000 adcs r0,r0,r0 0208FFF0 E0B13083 adcs r3,r1,r3,lsl 1h 0208FFF4 30433001 subcc r3,r3,r1 0208FFF8 E0B00000 adcs r0,r0,r0 0208FFFC E0B13083 adcs r3,r1,r3,lsl 1h 02090000 30433001 subcc r3,r3,r1 02090004 E0B00000 adcs r0,r0,r0 02090008 E0B13083 adcs r3,r1,r3,lsl 1h 0209000C 30433001 subcc r3,r3,r1 02090010 E0B00000 adcs r0,r0,r0 02090014 E0B13083 adcs r3,r1,r3,lsl 1h 02090018 30433001 subcc r3,r3,r1 0209001C E0B00000 adcs r0,r0,r0 02090020 E0B13083 adcs r3,r1,r3,lsl 1h 02090024 30433001 subcc r3,r3,r1 02090028 E0B00000 adcs r0,r0,r0 0209002C E0B13083 adcs r3,r1,r3,lsl 1h 02090030 30433001 subcc r3,r3,r1 02090034 E0B00000 adcs r0,r0,r0 02090038 E0B13083 adcs r3,r1,r3,lsl 1h 0209003C 30433001 subcc r3,r3,r1 02090040 E0B00000 adcs r0,r0,r0 02090044 E0B13083 adcs r3,r1,r3,lsl 1h 02090048 30433001 subcc r3,r3,r1 0209004C E0B00000 adcs r0,r0,r0 02090050 E0B13083 adcs r3,r1,r3,lsl 1h 02090054 30433001 subcc r3,r3,r1 02090058 E0B00000 adcs r0,r0,r0 0209005C E0B13083 adcs r3,r1,r3,lsl 1h 02090060 30433001 subcc r3,r3,r1 02090064 E0B00000 adcs r0,r0,r0 /////////////////////////////////////////////// Entered loop here !! //////////////////////////// 02090068 E0B13083 adcs r3,r1,r3,lsl 1h //R3 = 0xFFFFD8F0 + ( 0xAFC << 1 ) + Carry(1) => 0xFFFFEEE9 (N flag ticked) if( R3 < 0 ) (Actually more like !C) // 0xFFFFEEE9 (-4,375) is smaller than 0 !! 0209006C 30433001 subcc r3,r3,r1 //R3 = 0xFFFFEEE9(-4,375) - 0xFFFFD8F0(-10,000) => 0x15F9(5,625) 02090070 E0B00000 adcs r0,r0,r0 //R0 = 0 + 0 + Carry(0) => 0 02090074 E0B13083 adcs r3,r1,r3,lsl 1h //R3 = 0xFFFFD8F0(-10,000) + ( 0x15F9(5,625) << 1 )(11,250) + Carry(0) => 0x4E2(1,250) (C flag ticked) if( R3 < 0 ) (Actually more like !C) 02090078 30433001 subcc r3,r3,r1 0209007C E0B00000 adcs r0,r0,r0 //R0 = 0 + 0 + Carry (1) => 1 02090080 E0B13083 adcs r3,r1,r3,lsl 1h //R3 = 0xFFFFD8F0(-10,000) + ( 0x4E2(5,625) << 1 )(2,500) + Carry(0) => 0xFFFFE2B4(-7,500) (C=1) if( R3 < 0 ) (Actually more like !C) // -7,500 is smaller than 0 02090084 30433001 subcc r3,r3,r1 //R3 = 0xFFFFE2B4(-7,500) - 0xFFFFD8F0(-10,000) => 0x9C4(2,500) 02090088 E0B00000 adcs r0,r0,r0 //R0 = 1 + 1 + Carry(0) => 2 } 0209008C E0B13083 adcs r3,r1,r3,lsl 1h //R3 = 0xFFFFD8F0(-10,000) + ( 0x9C4 << 1 )(5,000) + Carry(0) => 0xFFFFEC78(-5,000) if( R3 < 0 ) (Actually more like !C) //-5,000 is smaller than 0 02090090 30433001 subcc r3,r3,r1 //R3 = 0xFFFFEC78(-5,000) - 0xFFFFD8F0(-10,000) => 0x1388(5,000) 02090094 E0B00000 adcs r0,r0,r0 //R0 = 2 + 2 + Carry(0) => 4 02090098 E1A01003 mov r1,r3 //R1 = 0x1388(5,000) 0209009C E21C3102 ands r3,r12,80000000h //R3 = 0 & 0x80000000 => 0 (Z=1,C=1) if( !Z ) 020900A0 12600000 rsbne r0,r0,0h // 020900A4 E21C3001 ands r3,r12,1h //R3 = 0 & 1 (Z=1,C=1) if( !Z ) 020900A8 12611000 rsbne r1,r1,0h 020900AC E12FFF1E bx r14 //Return from subroutine to 0x2074DD4 (RETURN to 2074DD4, from 0208FEA4 ) [/font]
-
Yet again out of ideas as to how samples loop info is stored. The two values that do affect the loop points while the game is running don't seem to indicate the actual starting loop point or the loop end point.. I tried multiplying them by 4, to convert the value from adpcm samples to pcm16 samples, the format in which I'm trying to loop them. I also tried adding both together and using the sample length as end point. I tried using the values as an offset from the end of the sample. But nothing worked quite right.. And to top it of, the sf2 files generated by my utility refuses to make its samples loop, unless I load it in Polyphone. And I triple checked to make sure they're loop legal according to the SF2 format's confusing and dumb prerequisites.. : - At least 8 data points before the begining of the loop - Loops are at least 32 data points long. - 8 data points between the loop end and the sample's end. - And at least 46 zeros after the sample's end.. And, I'm trying to convert the volume envelope to the SF2 format, but the data is stored as 0-127 values, which is just a proportion.. I need to convert those into "timecents" (which I'm not even sure what its supposed to represent..) Then I tried to convert the value myself using equations I found in the Polyphone's source code, and in GBA Music Ripper, but I didn't get a great result. And I can't just fallback to doing a rule of 3 between proportions, because the envelopes would be linear instead of logarithmic.. (Actually maybe they're linear.. I can't really think of a way to test that out reliably.. But considering the GBA's were apparently logarithmic, they likely are as well..) So, today I've been trying to reverse the process that decodes the envelope from the ROM. With little success this far.. I tend to step by step through the code, and it takes me hours.. In the end, I ended up with only these notes as the program was handling a split from the flute program while Hidden Land was playing : [font=Fixedsys] // // Ran until break on reading value UNK35 from Program 0x51's first Split. // 02074E14 E5D41000 ldrb r1,[r4] ;2 75 //This reads Unk35, which is 1 02074E18 E3510000 cmp r1,0h ;1 76 //This check if Unk35 is 0 02074E1C 0A000025 beq 2074EB8h ;3 79 //If its 0 run the code at 2074EB8 02074E20 E5D41009 ldrb r1,[r4,9h] ;2 81 //Read the "attack" byte 02074E24 E3510000 cmp r1,0h ;1 82 //Check if "attack" is 0 02074E28 0A000008 beq 2074E50h ;3 85 //If 0, jump to 2074E50 (JUMP) 02074E50 E3A015FE mov r1,3F800000h ;1 101 02074E54 E5841010 str r1,[r4,10h] ;1 102 //Put 0x3F800000 right after the envelope of Program 0x51's first Split. 02074E58 E5D4200C ldrb r2,[r4,0Ch] ;2 104 //Read "Hold"'s value! (0) 02074E5C E3520000 cmp r2,0h ;1 105 //Check if Hold is 0 02074E60 0A000004 beq 2074E78h ;3 108 //If Hold is 0, jump to 2074E78 (JUMP) 02074E78 E5D4200A ldrb r2,[r4,0Ah] ;2 119 //Read "Decay"'s value (0) 02074E7C E3520000 cmp r2,0h ;1 120 //Check if Decay == 0 02074E80 0A000004 beq 2074E98h ;3 123 //If its 0, then jump to 2074E98 (JUMP) 02074E98 E5D4200D ldrb r2,[r4,0Dh] ;2 135 //Read "Decay2"'s value (0x7F) 02074E9C E3A01000 mov r1,0h ;1 136 //Zero R1 02074EA0 EBFFFFAC bl 2074D58h ;3 139 //Jump to 2074D58 (JUMP) 02074D58 E92D4038 push r3-r5,r14 ;1 44 //Return address is 0x2074EA4 02074D5C E1A05000 mov r5,r0 ;1 45 02074D60 E1A04001 mov r4,r1 ;1 46 02074D64 E352007F cmp r2,7Fh ;1 47 //Check if Decay2 == 0x7F 02074D68 1A000004 bne 2074D80h ;3 50 //If Decay2 != 0x7F Jump to 2074D80 02074D6C E3A00000 mov r0,0h ;1 51 // 02074D70 E5850014 str r0,[r5,14h] ;1 52 //Zero out memory location 4 bytes after last envelope parameter 02074D74 E2400106 sub r0,r0,80000001h ;1 53 //R0 => 0x7FFFFFFF 02074D78 E5850018 str r0,[r5,18h] ;1 54 //Put 0x7FFFFFFF 8 bytes after last envelope parameter 02074D7C E8BD8038 pop r3-r5,r15 ;4 58 //Return to 2074EA4 (RETURN) 02074EA4 E3A00006 mov r0,6h ;1 199 //R0 => 6 02074EA8 E5C4001C strb r0,[r4,1Ch] ;1 200 //Put 6 right after the 0x7FFFFFFF we just wrote 02074EAC E3A00001 mov r0,1h ;1 201 //R0 => 1 02074EB0 E5C4001E strb r0,[r4,1Eh] ;1 202 //Put 1, 2 bytes from where we wrote 6 02074EB4 E8BD8010 pop r4,r15 ;4 206 //Return to 20747BC (RETURN) 020747BC E5940158 ldr r0,[r4,158h] ;2 82 //We loaded 0, which was stored at 0x22B7BC4 020747C0 E1500005 cmp r0,r5 ;1 83 //false 020747C4 08BD8038 popeq r3-r5,r15 ;4 87 //Jump to 2074138 if r0 and r5 are equal 020747C8 E59500B4 ldr r0,[r5,0B4h] ;2 89 //Loaded 0, from 0x22950C 020747CC E5840154 str r0,[r4,154h] ;1 90 //wrote 0, at 0x22B7BC0 020747D0 E58540B4 str r4,[r5,0B4h] ;1 91 // 020747D4 E5845158 str r5,[r4,158h] ;1 92 020747D8 E8BD8038 pop r3-r5,r15 ;4 96 //2074138 (RETURNED) 02074138 EAFFFF80 b 2073F40h ;3 31 (JUMPED) 02073F40 E5D92002 ldrb r2,[r9,2h] ;2 132 //Overwrote Decay2 in R2, with 0x59 02073F44 E1D930D3 ldrsb r3,[r9,3h] ;2 134 //R3 => 0x7F 02073F48 E1A00006 mov r0,r6 ;1 135 // 02073F4C E1A01005 mov r1,r5 ;1 136 // 02073F50 EBFFE59C bl 206D5C8h ;3 139 // (JUMPED) 0206D5C8 E92D4008 push r3,r14 ;1 54 //Pushed return address 2073F54 onto the stack 0206D5CC E5D0E002 ldrb r14,[r0,2h] ;2 56 //Reads "nbsplits" for Program 0x51! 0206D5D0 E35E0000 cmp r14,0h ;1 57 //Check if has no splits 0206D5D4 03A00000 moveq r0,0h ;1 58 //If no splits, put 0 in R0 0206D5D8 08BD8008 popeq r3,r15 ;4 62 //If no splits, return 0206D5DC E3510000 cmp r1,0h ;1 63 // 0x228137C != 0 (This is probably a pointer ? being checked for being null ?) 0206D5E0 02801060 addeq r1,r0,60h ;1 64 //Add R1 to R0 if R0 was not null, and R1 is null ! 0206D5E4 0A000005 beq 206D600h ;3 67 // 0206D5E8 E5D1C001 ldrb r12,[r1,1h] ;2 69 // Reads the first Split's ID 0206D5EC E24E0001 sub r0,r14,1h ;1 70 // R0 = 1 - 1 0206D5F0 E15C0000 cmp r12,r0 ;1 71 // 0 == 0 0206D5F4 A3A00000 movge r0,0h ;1 72 // True 0206D5F8 A8BD8008 popge r3,r15 ;4 76 //Returns to 2073F54 (RETURNED) 02073F54 E1B05000 movs r5,r0 ;1 25 // 02073F58 028DD00C addeq r13,r13,0Ch ;1 26 // R13 => 229AAA8 + 0xC => 229AAB4 02073F5C 08BD8FF0 popeq r4-r11,r15 ;4 145 //Return to 2071398 (RETURN 2071398)[/font] If anyone wants to give it a go themselves, feel free to set a few breakpoints on some of these lines and see if you can't find anything.
-
Thanks. I didn't know audacity could do that, but I was looking for something to use in my utility. Anyways, it doesn't matter, because I found out where they were storing the root key and pitch correction of each sample ! https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/2_B_SYS_TRAINING_Pitchfixed.mp3 Now, I just need to fix sample looping, properly convert sample envelopes, and fix issues with some instruments and it should work pretty well ! And I guess I'll give a try to musescore.
-
I've been messing around some more, and apparently, I'm not setting the correct root key for each samples, which makes them play at a too high or too low pitch. Then, my soundfont lib seem to produce soundfonts that are at least partly defective. I need to find a software that loads soundfonts and that we can get a detailed log, or that has its sources up for download and can be compiled and debugged on windows, with visual studio preferably. But this far, I wasn't too lucky with that. BASSMIDI and Polyphone both load the soundfont with little problems, but as soon as I try it in anything else, like FL studios and LMMS some pretty weird things happen, before it just crashes.. The soundfont format specification is way too cryptic to validate a sf2 using it.. I still can't be sure I truly understand how the format works. Anyone has any ideas or suggestions ? Also, does anyone here have any experience with audio signal processing at all ? I'd like to find a way to figure out the root key for each samples, if it turns out that data isn't stored in the SWDL.
-
Aaannnd I've hit another wall.. This one is much harder to break through though.. I can't get the samples to play at the right pitch. And some of the synthy samples have some extra processing applied to them, and I can't figure out what is going on.. Also, I can't figure out at all how come an instrument may play a note in the tenth octave.. That's beyond MIDI range, and DSE is largely based around importing MIDI data.. I'm completely stuck again. >_< And I'm not expecting to have much luck with map tiles either.. That's depressing..
-
I managed to somewhat improve conversion a bit. But some things just sound weird, and I don't know what is to blame. The midi exporter, my soundfont library, or the sample parameters not being exported correctly.. Example: https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/11_B_SYS_MONSTERHO.mp3 A lot of samples for higher notes are just completely warped and distorted for some reasons..
-
Finally, got the soundfont format right ! The documentation is so bad... And so vague.. I wonder why DLS didn't get more popular than sounfont ? And I managed to export some midis and play them with the "correct" samples in the sounfont! : https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/B_MAP_HOME_01.mp3 https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/converted_with_audioutil/B_DUN_MABOROSHI.mp3 The samples still have bad looping data, no pitch correction, and no envelope and etc.. So they sound pretty bad! And I've been plagued with this issue where the note pitch keeps climbing and go out of range.. So I'm guessing something might not be right with the octave change events and note octave change parameters.. That, or some samples are automatically shifted down in octave maybe ?
-
So, I've been stuck on a pretty annoying issue.. After writing a library to write soundfont files from scratch (ugh..), I came back to figuring out the missing bits I still haven't figured out in SWDL files. And I can't figure out how they assign samples to parts of the full note range.. They clearly have something that somehow contains keygroups: But I can't think of how this could define a group of key... Modifying that chunk of data was also kinda inconclusive.. Filling with junk had less effects than expected. Any ideas ? EDIT: Figured out how samples are assigned to key ranges. But I still have no ideas what the kgrp chunk is for !
-
That's interesting! Though the image is really tiny and can't be scaled up for some reasons.
-
I haven't had the chance to take a look at minecraft forge mod packs. But yeah that could work. The utility could parse the XML data of each sub-mods and install them itself one after the other. Though, I don't know what advantage it would have over putting them all together into a modpack. Considering modpacks are meant to be distributed together anyways. That sounds good. But, one possible problem with patching only some part of the file is that, its done assuming the file was in a certain default state. If some extra lines were added by another mod, its hard to know if the lines another mod would change would be the right ones. However, most of the tools I've made extract things in a format that could be rebuilt with many changes properly and re-distributed.. It might be possible to basically rebuild the ROM piece by piece doing it that way ? Though, it might be a little extreme.. Especially since we don't know if it will catch on. But, who knows, with the new PMD game coming out, it could possibly be applied to it as well ? (I'm planning on reversing that game as soon as I can get a decrypted ROM of it ! I sold my old 3DS and well, it was already updated past the firmware that could decrypt games easily.. I've actually taken a look at gates to infinity and etrian mystery dungeon and it seems pretty familiar. They even use compiled lua scripts for nearly everything ! The 3d model format looks pretty straightforward as well. But they're using a compression format that I've seen in other chunsoft games, but never found out what it was.. Probably another LZ compression variant. ) Now that you mention it. It might be better not to put too much relatively unrelated features into sky editors, if I could say so. Because SkyEditor seems to be heading towards being more of a powerful dev tool. And while devs would feel at home with it, the average users might freak out if they're offered too many options. And well, it would be easier to debug two smaller programs and codebases than a single larger one. Anyways, that's just my opinion, feel free to disregard ^^; But, I digress. I also considered making a patching program, but its way easier to have the patcher distributed in with the rest.. And people wouldn't have to go looking for the right version of the program and etc.. Then again, some people might see it as a security risk.. And they'd be right, really.. given anyone could put whatever they want instead of that utility.. But, the mods could also be applied using an external utility. There would be the light-weight redistributable patcher utility, and the full-size one would combine the patch maker and a patcher together. So that people that don't want to trust the utility in a modpack can just use the full-size stand-alone program instead. The XML data is really what would contain all the important mod specific details. And I grabbed the source code for xdelta and ndstools. It shouldn't be too hard to work with and combine them, as long as the dependencies can be dealt with. EDIT: Scratch that, I took a deeper look and they're both true C-style references salads I think it would be much easier to just include them in the same package as separate executable.. Those are the entity names used in the scripts ! BIPPA is the name of some Pokemon in romanized japanese. I guess I was looking at the wrong place on my end.. ^^; Its interesting that it can work that way too. I thought it could only be used on the speaker.. lol, nice one. I really wonder what shiftry is up to