Jump to content

Recommended Posts

Posted

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) :

FullWramDisassembly.zip

I just thought others might like to know about this xD

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

Posted

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 xD

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..

Posted

It works ! :D

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.

Posted

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.

Posted

I've been looking at the item files, hoping to make a user-friendly GUI for editing items, and need a second opinion on item_s_p.bin. For each item, there's two values. One identifies the rarity, the other identifies the Pokémon or Type. I have an idea about rarity 0xA. It's only used for the Eevee and Tyrogue line, but I think it's because the criteria for trading. Normally when trading for a 3 star item, you have to give the two 1 star items and the 2 star item for the same Pokémon. With rarity 0xA (also a 3 star item), you have to trade the two 1 star items and the 2 star item for the previous Pokémon (Eevee's lower items for Glaceon's item, etc.). I think it's safe to just say this is the case and update the wiki, but before I actually do so I'd like a second opinion, since I'm focusing more on development than research right now.

Posted

Hello, I was working on SMD files of PMD2 these days, and found this forum by chance. You really did a great job!

I particularly read this note (not knowing if it is the most-updated one):https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/PMD2_MusicAndSoundFormats.txt

It helps me a lot. Also, everything I've been found before match with yours well, except for the following:

....

* 2 lowest bits of the nybble (0011):

A flag that tells us in what pitch to play the note in the low byte. So far it seems

that, when this nybble is:

- 0x2( 0010 ) : The note is played at the current pitch, either set by the 0xA0 event,

or by a previous play note event.

- 0x1( 0001 ) : The note is played at one octave LOWER than the current pitch, and the current

pitch is now equal to that!

- 0x3( 0011 ) : The note is played at one octave HIGHER the current pitch, and the current

pitch is now equal to that!

- 0x0( 0000 ) : Reset the pitch to the value of the last setoctave event (0xA0) !

....

The bold sentence is difference from what I found. I found that it is (expressed in your way):

- 0x0( 0000 ) : The note is played at TWO octaves LOWER the current pitch, and the current pitch is now equal to that

I came up with this by checking the code that handles the pitch changing:

020712A0 E5CD3003 strb    r3,[r13,3h]
020712A4 E5D01000 ldrb    r1,[r0] // r1 now is the first parameter of play event
020712A8 E5D65004 ldrb    r5,[r6,4h] //r5 now is the current pitch
020712AC E3A0300C mov     r3,0Ch
020712B0 E1A02A01 mov     r2,r1,lsl 14h //r2=r1<<0x14;
020712B4 E1A02C42 mov     r2,r2,asr 18h //r2>>=0x18
//now r2 is the high nybble of the first parameter
020712B8 E2022003 and     r2,r2,3h //now r2 is 2 lowest bits of the nybble (pitch change field) 
//The following code really confused me, but I believe that it is just "r5+=r2-2;"
020712BC E2422002 sub     r2,r2,2h //r2-=2;
020712C0 E1A02C02 mov     r2,r2,lsl 18h//r2<<=0x18;
020712C4 E0852C42 add     r2,r5,r2,asr 18h//r2=r5+(r2>>0x18);
020712C8 E1A02C02 mov     r2,r2,lsl 18h //r2<<=0x18;
020712CC E1A05C42 mov     r5,r2,asr 18h //r5=r2>>0x18;

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] // Store the new pitch

Hope it can help. If you have found it, just ignoring me is fine.

EDIT:

Oops, find this has been fixed in the post above...How can I reply without reading posts carefully...

Anyway I love your research. Wish you make more great process.

Posted

I've been looking at the item files, hoping to make a user-friendly GUI for editing items, and need a second opinion on item_s_p.bin. For each item, there's two values. One identifies the rarity, the other identifies the Pokémon or Type. I have an idea about rarity 0xA. It's only used for the Eevee and Tyrogue line, but I think it's because the criteria for trading. Normally when trading for a 3 star item, you have to give the two 1 star items and the 2 star item for the same Pokémon. With rarity 0xA (also a 3 star item), you have to trade the two 1 star items and the 2 star item for the previous Pokémon (Eevee's lower items for Glaceon's item, etc.). I think it's safe to just say this is the case and update the wiki, but before I actually do so I'd like a second opinion, since I'm focusing more on development than research right now.

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.. :/

Hello, I was working on SMD files of PMD2 these days, and found this forum by chance. You really did a great job!

I particularly read this note (not knowing if it is the most-updated one):https://dl.dropboxusercontent.com/u/13343993/my_pmd_research_files/PMD2_MusicAndSoundFormats.txt

It helps me a lot. Also, everything I've been found before match with yours well, except for the following:

The bold sentence is difference from what I found. I found that it is (expressed in your way):

- 0x0( 0000 ) : The note is played at TWO octaves LOWER the current pitch, and the current pitch is now equal to that

I came up with this by checking the code that handles the pitch changing:

020712A0 E5CD3003 strb    r3,[r13,3h]
020712A4 E5D01000 ldrb    r1,[r0] // r1 now is the first parameter of play event
020712A8 E5D65004 ldrb    r5,[r6,4h] //r5 now is the current pitch
020712AC E3A0300C mov     r3,0Ch
020712B0 E1A02A01 mov     r2,r1,lsl 14h //r2=r1<<0x14;
020712B4 E1A02C42 mov     r2,r2,asr 18h //r2>>=0x18
//now r2 is the high nybble of the first parameter
020712B8 E2022003 and     r2,r2,3h //now r2 is 2 lowest bits of the nybble (pitch change field) 
//The following code really confused me, but I believe that it is just "r5+=r2-2;"
020712BC E2422002 sub     r2,r2,2h //r2-=2;
020712C0 E1A02C02 mov     r2,r2,lsl 18h//r2<<=0x18;
020712C4 E0852C42 add     r2,r5,r2,asr 18h//r2=r5+(r2>>0x18);
020712C8 E1A02C02 mov     r2,r2,lsl 18h //r2<<=0x18;
020712CC E1A05C42 mov     r5,r2,asr 18h //r5=r2>>0x18;

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] // Store the new pitch

Hope it can help. If you have found it, just ignoring me is fine.

EDIT:

Oops, find this has been fixed in the post above...How can I reply without reading posts carefully...

Anyway I love your research. Wish you make more great process.

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 xD

Posted

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 xD

I disassembled the event handler for 0xE0 and 0xE3 and try understanding them. Here is my note for assembly code of 0xE0 handler (0xE3 is quite similar)

/*
Event Handler Parameter:
R0 event sequance pointer
R2 "Track Controller Structure" pointer
R3 "Audio Output Structure?" pointer

R3+0x18 (the final volume?)written by both event E0 and E3
R3+0x2C (the volume?)written by event E0(=parameter<<16), read by event E3
R3+0x34 (the volume?)written by event E0(=parameter<<16)
R3+0x38 cleared by event E0
R3+0x50 (the expression?) read by event E0, written by event E3(=parameter)
R3+0xB4 (a linked list head pointer?) read by both event E0 and E3
R3+0xC4 (a pointer, to the main audio output controller?) read by both event E0 and E3
*/
============================================================================
0207227C(Event E0 Handler)
0207227C STMDB SP!,{R3-R5,LR}
02072280 LDRSB R4,[R0,#0]//r4=parameter (as signed byte)
02072284 MOV R5,#0//r5=0
02072288 LDR R2,[02072308]//r2=0x82061029(whats this...)
0207228C MOV R1,R4,LSL #10//r1=r4<<0x10
02072290 STR R1,[R3,#34]//*(u32*)(r3+0x34)=r1(=parameter<<16)(store the track valume)
02072294 STR R1,[R3,#2C]//*(u32*)(r3+0x2C)=r1(=parameter<<16)(also store the track valume?)
02072298 STRH R5,[R3,#38]//*(u16*)(r3+0x38)=r5(=0)
0207229C LDR R12,[R3,#C4]//r12=*(u32*)(r3+0xC4) (= pointer to main audio controller?)
020722A0 LDRB R1,[R3,#50]//r1=*(u8*)(r3+0x50)( =track expression)
020722A4 LDRSB LR,[R12,#8]//LR=*(s8*)(r12+8) ( =main volume? it's often 0x7F in memory and decrease its value when the bgm fades out)
020722A8 LDR R12,[0207230C]//r12=0x04000208(=Register_IME)
//The following code looks like mixing the track volume ,expression and main volume together
//But by a quite strange method
//Note: now r1=track_expression, r4=track_volume, lr=main_volume?
020722AC SMULBB R1,R4,R1//r1*=r4
020722B0 MUL R4,LR,R1//r4=LR*r1
020722B4 SMULL R1,LR,R2,R4//(u64)(r1,LR)=r2*r4?
020722B8 ADD LR,R4,LR//LR+=r4
020722BC MOV R1,R4,LSR #1F//r1=r4>>0x1F
020722C0 ADD LR,R1,LR,ASR #D//LR=r1+(LR>>0xD)
020722C4 STRH LR,[R3,#18]//*(u16*)(r3+0x18)=LR (store final volume?)

020722C8 LDRH R4,[R12,#0]//r4=*(u16*)0x04000208(Get current IRQs state)
020722CC STRH R5,[R12,#0]//*(u16*)0x04000208=r5(=0)(Disable IRQs)
020722D0 LDR R2,[R3,#B4]//r2=*(u32*)(r3+0xB4)
//r2 looks like a linked list pointer
020722D4 CMP R2,#0
020722D8 BEQ 020722F4 //while(r2!=0){
//This loop looks like notifying every members in the list
020722DC LDRH R1,[R2,#6]//r1=*(u16*)(r2+6)
020722E0 ORR R1,R1,#20//r1|=0x20
020722E4 STRG R1,[R2,#6]//*(u16*)(r2+6)=r1
020722E8 LDR R2,[R2,#154]//r2=*(u16*)(r2+0x154)
020722EC CMP R2 #0
020722F0 BNE 020722DC //}

020722F4 LDR R2,[0207230C]//r2=0x04000208
020722F8 ADD R0,R0,#1//R0+=1 (r0 is the event sequance pointer)
020722FC LDRH R1,[R2,#0] r1=*(u16*)0x04000208
02072300 STRH R4,[R2,#0] *(u16*)0x04000208=r4(Restore IRQs state)
02072304 LDMIA SP!,{R3-R5,PC}//return

As you can see, the volume envelope staff looks strange, computing with a magic number 0x82061029.

I think maybe it is just "final_volume=track_volume*expression*main_volume/something;", which is in the most common way. Because ARM doesn't support division directly, it computes like that.

But if it is not the correct way to envelop the volume, I have no more idea at present.

Posted

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):

DSE_Envelope.png

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

R3+0x18 (the final volume?)written by both event E0 and E3

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.

DSE_Envelope.png.b662405a52add564372b9f3

Posted
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):

[ATTACH=CONFIG]12482[/ATTACH]

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.

Sorry for my misunderstanding and thanks. I really learn something new every times.

The adrress contained in R3 can be different for each track (it is also stored in the pointer R2+0x54), and can be changed when changing BGM.

The memory located at R2 I call it "track controller structure". I don't know if you've found it and how you call it. There is an array of "track controller structures", begin at 0x02291D28, and 0x5C bytes for each, corresponding to each track. The event handler receives R2 as the pointer to an element in the array.

Another structure array is located after "track controller structure array"( it is not static), 0xC8 bytes for each element. The parameter R3 is the pointer to an element in this array. I will call these structures "R3 structure".

For example, BGM#1(Pokémon Exploration Team Theme), the parameters that each track pass to event handlers (including E0 and E3) are:

track0: R2=0x02291D28, R3=0x02292370

track1: R2=0x02291D84, R3=0x02292370

track2: R2=0x02291DE0, R3=0x02292438

track3: R2=0x02291E3C, R3=0x02292500

track4: R2=0x02291E98, R3=0x022925C8

...

My R3+0x18 is not the same as your R5+0x18, for different address and different behavior.

I didn't dig deeply into swd files, so I can't help much about volume envelope.

Posted

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]

Posted

Apparently the volume calculation sums up to this..

( ( ( ( (( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) >> 31) + ( ( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) + ( ( 0xFFFFFFFF00000000 & ( 0x828CBFBF * (0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) ))) ) ) ) >> 12 ) ) * (( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) >> 31) + ( ( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) + ( ( 0xFFFFFFFF00000000 & ( 0x828CBFBF * (0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) ))) ) ) ) >> 12 ) )  + ( ( ( (( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) >> 31) + ( ( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) + ( ( 0xFFFFFFFF00000000 & ( 0x828CBFBF * (0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) ))) ) ) ) >> 12 ) ) * (( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) >> 31) + ( ( 0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) )) ) + ( ( 0xFFFFFFFF00000000 & ( 0x828CBFBF * (0x7F * (( ((0x7F * (0x64 * 0x73)) >> 31) + ( (0xFFFFFFFF00000000 & ( (0x7F * (0x64 * 0x73)) * 0x82061029 ) + (0x7F * (0x64 * 0x73))) >> 13 ) ) * ( SampleVolume + (0>>6) ))) ) ) ) >> 12 ) ) >> 8 ) >> 23 ) >> 9 )

;_;

So many shifts..

Now I need to simplify..

The result is 0x3F btw..

Looks like alot of progress has been made. It makes me happy to see we will soon see Explorers of sky ROM hacks soon hopefully. Also good job with the research.

Thanks.

But, not so much has been done really. That's just the music format we've been working on lately. Still, we're pretty far from importing midis and sample data back into the game..

If we could make some breakthroughs in the following areas, we'd be much closer to an actual devkit for pmd2 :

- Sprite files

- Map tiles

- Scripts

- Dungeon data files

To make a level editor, probably the most important part, we'll need to support fully the sprite and tile format, and have a better understanding of the scripts. And right now I have no ideas when we're going to make breakthroughs like that.. It would help if we weren't only ~3 doing that xD

Posted

We're almost to a point where simple hacks are possible. I've currently developing a ROM editor with support for editing item definitions, and I've successfully changed the name and price of Iron Thorns. Still needs more work (and I'm not even sure which I should focus on more: PMD editing or making 3DS mods easier to apply).

Posted

We're almost to a point where simple hacks are possible. I've currently developing a ROM editor with support for editing item definitions, and I've successfully changed the name and price of Iron Thorns. Still needs more work (and I'm not even sure which I should focus on more: PMD editing or making 3DS mods easier to apply).

That reminds me. I forgot I had only a few things to fix to get statutil out.. :/

I wish I wouldn't leave things half-done all the time..

And honestly I don't really know. But, the 3ds mods won't be very useful until we either get a good, easy, stable exploit, or a 3ds emulator actually gets decent enough.

Posted

I made some more research with DSE events. I'm trying to map the DSE memory. And find out what most events do.

I'm also working on a big cleanup of my code, so hopefully I can get statutil out next, and then get back into gfxutils.

I also found a nice pun to name an editor as.. So I might as well try to make one now XP

It might end up being for PSMD / GTI though. It depends really on what's left to cover.

And here are a few things I found on some events:

0x95, takes a duration in ticks as a byte, and its a wait loop that checks every nth ticks if the track is still playing a sample/has still a key pressed.

Event 0x96, along with every other events that directs to line 0x0207191C just disable the track completely.

Here's the complete list of invalid/track disabling events:

[font=Fixedsys]0x96
0x97
0x9A
0x9B
0x9F
0xA2
0xA3
0xA6
0xA7
0xAD
0xAE
0xB7
0xB8
0xB9
0xBA
0xBB
0xBD
0xC1
0xC2
0xC4
0xC5
0xC6
0xC7
0xC8
0xC9
0xCA
0xCC
0xCD
0xCE
0xCF
0xD9
0xDA
0xDE
0xE6
0xEB
0xEE
0xF4
0xF5
0xF7
0xF9
0xFA
0xFB
0xFC
0xFD
0xFE
0xFF[/font]

I also found out something funny about event 0x9C..

If you call it in a looping track, it will eventually corrupt the pointer to part of the sequencer's memory xD

I still have no ideas what its for though..

I'll be looking forward to the progress being made~ I really want to make a rom hack of EoS and turn it into GtI to fix its issues and add new content.

I don't think you can really turn it into GTI, if I understand what you mean. Core gameplay and most in-game menus appear hard-coded. You'd need to inject some code in there on your own.

Though it will eventually be possible to turn GTI or even PSMD into something close to EoS if someone really wanted. Those two use a lua script engine, and a significant part of the game is in script form, menus, debug routine, cutscenes, and etc.. Most of the stats data is loaded via script too. Not to mention that, with lua you could probably do way more than what they did !

Posted
I don't think you can really turn it into GTI, if I understand what you mean. Core gameplay and most in-game menus appear hard-coded. You'd need to inject some code in there on your own.

Though it will eventually be possible to turn GTI or even PSMD into something close to EoS if someone really wanted. Those two use a lua script engine, and a significant part of the game is in script form, menus, debug routine, cutscenes, and etc.. Most of the stats data is loaded via script too. Not to mention that, with lua you could probably do way more than what they did !

I don't mean copying it down to every single thing; basically edit the sprites, storyline/events, dungeons, items, moves, and pokemon. I'd keep the gameplay the same as EoS because GtI's gameplay was terrible (no healing during any weather is complete bull for example). That, and maybe add on to the story so it's longer and complex.

Might it be possible to edit GtI's view in the dungeon? Like make it the same size as the previous games (not all zoomed in in other words so you can see the dungeon layout better)? And perhaps edit the models so they have unique idle animations?

Posted

I don't mean copying it down to every single thing; basically edit the sprites, storyline/events, dungeons, items, moves, and pokemon. I'd keep the gameplay the same as EoS because GtI's gameplay was terrible (no healing during any weather is complete bull for example). That, and maybe add on to the story so it's longer and complex.

That should be mostly doable. Though I haven't tested adding more pokemon. And you'd have to ask Nerketur about dungeons and story event-related stuff. He's working on a PMD2 script editor.

But, I guess it might be possible to make a few tweaks to the game code to increase the amount of pokes in the game if we ever need to. We'd need some more testing..

The main problem is the way the stats file is made, and the way portraits are stored. Because pokemons are stored as entities, and there is 2 entities per regular pokemon, one for the male, and one for the female (There are invalid entities for genderless pokes and single gender pokemon). But the thing is that, half of the list is made of the male pokes, and the the other half is made of the female pokemon.. Which means that we'd need to shift the point where female pokemon entities begins from.. And I'm not sure what it implies..

Maybe its really stupidly simple though..

Might it be possible to edit GtI's view in the dungeon? Like make it the same size as the previous games (not all zoomed in in other words so you can see the dungeon layout better)? And perhaps edit the models so they have unique animations?

It might be possible.. At least I know you can absolutely move the camera, either by editing possibly a script, or just directly in memory. But I don't know if the graphic engine will render the level further around the characters.. Again, that's something to test.

The models and animations are definitely possible. I'm working in my other thread on reversing those among other things!

  • 2 weeks later...
Posted

I finally got a new version of statsutil ready for release!

https://github.com/PsyCommando/ppmdu/releases/download/ppmd_statsutil_0.2a/ppmd_statsutil_0.2.zip

I added support for item data from Explorers of Sky!

Don't use it with Explorers of Time/Darkness. Those are unsupported for now, and will crash the program.

I won't write a big announcement post because I'm a bit sick right now, and I have a huge headache. But hopefully, the readme will answer your questions.

Posted

So I found out that the game strings import was completely broken, and I fixed it!

https://github.com/PsyCommando/ppmdu/releases/download/ppmd_statsutil_0.21a/ppmd_statsutil_0.21.zip

I also spent the day working on a tiny GUI for statsutil. (I also added a bunch of useless features...) :

https://github.com/PsyCommando/ppmdu_gui_frontends/releases/download/ppmd_statsutil_gui_0.21/ppmd_statsutil_gui_0.21.zip

I got sick of trying to find ndstool's license, after years.. So I just slapped it into the executable, along with the statsutil stuff. Everything is just copied to the current working directory when the program is launched.

Posted

So, I realized that I completely overlooked the fact that people might use the program on multiple session..

And I'll have to rethink the whole user interface..

But in the meantime, here's a little temporary fix to make things a little easier:

https://github.com/PsyCommando/ppmdu_gui_frontends/releases/download/ppmd_statsutil_0.21_gui_0.11/ppmd_statsutil_0_21_gui_0_11.zip

It will automatically check if the rom data was already extracted and set it automatically as rom input path. Which means that you can just import your existing changes and then rebuild the rom.

Posted (edited)

I released the new gui for statsutil :

https://github.com/PsyCommando/ppmdu_gui_frontends/releases/download/ppmd_statsutil_0.21_gui_0.20/ppmd_statsutil_0_21_gui_0_20.7z

If I can get some feedback on it, I'll make a proper release with a readme and all xD

I got rid of the rom extraction/rebuilding, because it caused a lot of problems, and it made no sense, considering someone modifying the game probably won't only change some text strings and statistics..

I might make a project manager app, eventually. Something very simple that doesn't get in the way and would allow people to edit the game file with any means they want and and just repack everything in a single click.

Also, I've been trying to help with script research lately, because on one hand it will allow me to edit the game dialog stored within the script files, and on the other, it means we'll be able to do more with the game if I do find something.

Also, I'm still looking for information on how to translate the values in the NDS's sound registers into volume units. And I haven't heard back from anyone I asked questions on that matter to. And the documentation on the NDS DSP is pretty shallow apparently..

Edited by psy_commando
  • 4 weeks later...
Posted (edited)

Psy, i had some notes i made from before you even started this project. Back then i tried hex editing some preexisting dungeons, and in order to do that i dug deep into that gamefaqs topic for information. You might already have all this information, but i decided to post in here just in case you didn't. I hope this helps you even a tiny little bit:

http://pastebin.com/kWDYtbQe

I remember that it took me like 6 hours to dig this much information from that topic, and that i wasn't 100% sure that i didn't made a mistake when writing it. So while this might help, when in doubt presume that my notes are wrong okay.

edit: Also, once you figure out the rest (like what different values mean on each byte and which offsets are for which dungeons) making an utility to edit dungeons shouldn't be very difficult for you.

Edited by Kajur
Also...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...