Jump to content

wwylele

Member
  • Posts

    3
  • Joined

  • Last visited

Posts posted by wwylele

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

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

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

×
×
  • Create New...