more question about the emu10k instruction

Discussion in 'Effects and the DSP' started by JoshuaChang, May 11, 2011.

  1. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    i'm now researching the aps pitch plugin, it has some strange instruction that i can't understand:

    1.
    Code:
    macw      tmp8019,  sti800c,  0x80000000,  0x80000000;
    does this mean: tmp8019 = -1 + sti800c ? for 0x80000000 * 0x80000000 should be 0x7fffffff

    2.
    Code:
    macints      sti800b,  0x0,  sti800b,  0x7fffffff;
    the Y operator is 0x7fffffff, with macints instruction, it's real 0x7fffffff and not 1.0 right? then if sti800b>0x0, then the result should always be 0x7fffffff?

    3.the pitch coefficient was calculated by a very complex expression :
    Code:
            x = (double)value; //range is -12.50 to 12.50
            x=x/100.0;
            y = x;
    
            x=(-3.372957086043240E-09+x*-8.859580403504260E-05)/(1.0+x*(-0.02887715356902830+x*0.0002749755844979194));
            set_dsp_register(_PITCH, _dbl_to_dspword(x));
            
            y=-4.002216357671908E-07+y*(-5.641437909059427E-05+    y*(-1.621408704872448E-06+y*(-3.204726841065972E-08+ y*-4.932649619664321E-10)));
            set_dsp_register(_PITCH2, _dbl_to_dspword(y));
    what's the algorithm behind it?

    someone please help me out~
     
  2. Max M.

    Max M. h/h member-shmember

    Joined:
    Dec 7, 2002
    Messages:
    2,690
    Likes Received:
    9
    Trophy Points:
    63
    Îòâåò: more question about the emu10k instruction

    1. I think yes - it's just -1*-1 (well, this code is produced by the original Emu "algebraic syntax" assembler which may result in quite ornate instructions for relatively trivial operations).

    2. Yes, it's basicaly a sort of "sign switch" (i.e. return -1, 0 or 1), (for example it can be used to convert sawtooth LFO wave to square one).

    3. Notice that all DLL parts of APS* plugins are complete quesswork (so the code just some approximation of most likely trivial trigonometric formulae used in original Emu plugin).
    I guess the pitch shift algorithm of this plugin is pretty much similiar to the one you can find here
     
    Last edited: May 11, 2011
  3. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    thanks for the answer and the pdf, it's very useful,
    another more question :

    Code:
    skip   0x0,  ccr,  0x200,  0x2;
    what does the cc_test 0x200 mean? i couldn't found any condition related to this number

    edit:have further research the as10k and found some rule(?), the 0x200 maybe the not saturation condition?(0x10<<5??)
     
    Last edited: May 12, 2011
  4. Max M.

    Max M. h/h member-shmember

    Joined:
    Dec 7, 2002
    Messages:
    2,690
    Likes Received:
    9
    Trophy Points:
    63
    Îòâåò: more question about the emu10k instruction

    I think yes - 0x200 is the saturation bit in "not frame" (i.e. "not saturation") - but that skip stuff always has been same black magic for me too :)
    The "skip forms" table in as10k1 manual came from the US5930158 patent - and since those patents are known to give some minor disinformation - you never know for sure till you test it with real hardware (though the "Form 1" seems to be correct - at least it works as expected for many programs).

    btw: http://www.hardwareheaven.com/effects-dsp/184465-skip-instruction-how-does-work.html#post1264845
     
    Last edited: May 12, 2011
  5. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    skip can makes the emu10k do some flow control based on cc_test, the Y operand define the number of instructions to be skiped

    i still have no idea when the saturation bit should be set:
    1.0x7fffffff+0x1, this is for sure
    2.0x80000000-0x1, this should affect borrow bit?
    3.0x80000000+0xffffffff, i've got lost......
     
  6. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    more question about delayline:
    Code:
    acc3 &rd, delay, &wrt, 0x0;
    1.seems &rd/&wrt, the delayline register address has a unit of 0x800 for one sample delay?maybe reflect to 2^32/2M samples?

    2.does &rd/&wrt, the delayline register address increment by 0x800 every circle, or they just have the static address value?
     
  7. Russ

    Russ Well-Known Member

    Joined:
    Jan 17, 2005
    Messages:
    5,722
    Likes Received:
    13
    Trophy Points:
    48
    These 2 are the same thing...
    i.e.
    -1 - 0.0000000004656612873077392578125
    -1 + (-0.0000000004656612873077392578125)

    Both should result in (negative) saturation (Result is 0x80000000 with the S and M (and N) flags set).

    I am not completely sure how the borrow or normalize flags are used.

    As for the delay line, did you read this page?: Emu10k1 Tram Engine
     
    Last edited: May 12, 2011
  8. stylus02

    stylus02 New Member

    Joined:
    Jan 11, 2008
    Messages:
    283
    Likes Received:
    2
    Trophy Points:
    0
    "I guess the pitch shift algorithm of this plugin is pretty much similiar to the one you can find here"

    this adsp paper is quite impressive. the programming and accessibility seems simple.
     
    Last edited: May 12, 2011
  9. stylus02

    stylus02 New Member

    Joined:
    Jan 11, 2008
    Messages:
    283
    Likes Received:
    2
    Trophy Points:
    0
    i was confused about the adress calculation too some years ago. important is the 11 bit shift of the read adress.

    [read address]=[write address]+[calculated number of delay samples]*0x800 (taken from russ's link to the tram engine)

    "0x800" = 11 bit

    "calculated number of delay samples" means the itramsize or xtramsize. i hope i remember right.

    if you do so, you will see it works. i used this to build a lookup table for the first keyboard unit for kxm. precalcuated "note" values were writen in the delay memory an maped exactly to incoming midi controller values 0-127 via kx control. russ did a better version, without using the delay line as a "memory bank", but allways in dane. later we had the smart c++ solution.

    btw: i wondered a bit because i expected a bit reduction to 16 bit while writing values in delay ram. can anyone confirm this bit reduction?
     
    Last edited: May 12, 2011
  10. Russ

    Russ Well-Known Member

    Joined:
    Jan 17, 2005
    Messages:
    5,722
    Likes Received:
    13
    Trophy Points:
    48
    Yes, but IIRC, it is not just a bit reduction, the data is also compressed (so depending on the specific value, you might get more or less than 16 bit accuracy).
     
  11. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    i've read the tram manual, seems the value in tram address register is static once it is defined(unless modify it manually)? and when i need to access the delayline data, the real delayline address should be tram address register+DBAC?
     
  12. Russ

    Russ Well-Known Member

    Joined:
    Jan 17, 2005
    Messages:
    5,722
    Likes Received:
    13
    Trophy Points:
    48
    To read and write to the delay line, you do not have to deal with any addresses, you just use the variables declared in your code.

    You only deal with the addresses if you want to change something dynamically (e.g. move a read pointer in order to change the delay length (maybe based on a slider position, or as a result of some DSP instructions), etc). This is where the 0x800 stuff comes in, and it is done as stated in the manual.

    e.g.
    [read address]=[write address]+[calculated number of delay samples]*0x800
    or maybe...
    [read address]=[write address]+[max number of delay samples]*0x800*[slider value]

    See the "Delay A" plugin for an example. It has a max delay size of 32000 samples for each of it's delay lines.
    32000 * 0x800 = 0x3E80000
    Note that there is a variable "maxdlysize" with this value.
    The following code changes the read addresses for each delay line in the plugin:
    Code:
    macs 	 &d1r,  &d1,  maxdlysize,  time1;  
    ;  read_addr1 = write_addr1 + (maxdlysize * time1_slider)
    macs 	 &d2r,  &d2,  maxdlysize,  time2;
    ;  read_addr2 = write_addr2 + (maxdlysize * time2_slider)
    
    You can also see how that 0x800 value is used in "APS Pitch" and "Stereo Chorus" to change the read addresses, etc (using an LFO (or whatever) instead of a slider value).

    The DBAC is not typically used with delay lines. As it says in the manual, it is used to find the start of TRAM space or to access TRAM in a non-circular fashion. AFAIK, it is used by the Creative driver to implement AC3 passthrough, but kX does not use TRAM this way.
     
    Last edited: May 13, 2011
  13. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    i can understand the usage of change address in delay A plugin, but i can't understand the usage in aps pitch...
    Code:
         macs          tmp8019,  &itr800f,  sti800c,  sti8005;
         macs          &itr8011,  tmp8019,  0x0,  0x0;
         macsn          &itr8013,  &itr8011,  sti8004,  0x80000000;
         macintw     dyn8008,  0x0,  tmp8019,  0x00100000;
         macw          tmp8019,  sti800c,  0x80000000,  0x80000000;
         macs          tmp8019,  &itr800f,  tmp8019,  sti8005;
         macs          &itr8015,  tmp8019,  0x0,  0x0;
         macsn          &itr8017,  &itr8015,  sti8004,  0x80000000;
         macintw     dyn8009,  0x0,  tmp8019,  0x00100000;
     
  14. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    if a line code like this:
    Code:
    macs          tmp8019,  &itr800f, 0x0, 0x0;
    does the value of tmp8019 decrement by 0x800 every circle?
     
  15. Russ

    Russ Well-Known Member

    Joined:
    Jan 17, 2005
    Messages:
    5,722
    Likes Received:
    13
    Trophy Points:
    48
    In APS Pitch, sti8004 = 0x800;

    It appears to be calculating it's new read addresses from previous read addresses, instead of the write address (which I guess would work in a similar way). The code is a bit confusing as the variable names are auto-generated, etc, and the algorithm used by the plugin to calculate the coefficients, etc, is not known (and as Max stated, some of the instructions are probably more complicated then is necessary).
     
  16. Russ

    Russ Well-Known Member

    Joined:
    Jan 17, 2005
    Messages:
    5,722
    Likes Received:
    13
    Trophy Points:
    48
    No, it stays constant.
     
    Last edited: May 13, 2011
  17. Russ

    Russ Well-Known Member

    Joined:
    Jan 17, 2005
    Messages:
    5,722
    Likes Received:
    13
    Trophy Points:
    48
    Maybe this is helpful?

    APS Pitch with some variable renaming and some quick notes (may not be 100% correct):
    Code:
        itramsize 2048
    
        input in0, in1;
        output out0, out1;
        control level=1;    
        static pitch1=0xfffffff9, pitch2=0xfffffca4;        -> calculated in C++
        static dyn1=0, dyn2=0;
        static sti1=0, sti2=1, sti3=-1;
        temp t1, t2;
        temp t_in0, t_in1;
        
        idelay write w at 0;
        idelay read r1 at 0x400;                            -> 1024
        idelay read r2 at 0x400;                            -> 1024
        idelay read r3 at 0x401;                            -> 1025
        idelay read r4 at 0x400;                            -> 1024
        idelay read r5 at 0x401;                            -> 1025
    
    ; Code
         macs    t_in0,  in0,  0,  0;                       -> buffer input 0
         macs    t_in1,  in1,  0,  0;                       -> buffer input 1
         
         macs    0,  0,  t_in0,  0.707;                     -> see below
         macs    w,  accum,  t_in1,  0.707;                 -> mono mix at half power and write to tram  
         
         macwn   sti3,  sti3,  pitch2,  -1;                 -> sti3 (LFO?) = sti3 + pitch2 *** (wraps around)
         skip    0,  ccr,  0x200,  0x2;                     -> if (S == 1)
         macs    sti1,  0,  0,  0;                              -> sti1 = 0
         macints     sti2,  0x0,  sti2,  0x7fffffff;            -> sti2 = -1 or 0 or 1
    
         macs    sti1,  sti1,  pitch1,  sti2;               -> sti1 = sti1 + (pitch1 * sti2) *** [I](crossfade coef)[/I]
         macsn   sti2,  sti2,  pitch1,  sti1;               -> sti2 = sti2 - (pitch1 * sti1) *** [I](crossfade coef)[/I]
         
         interp      t1,  r2,  dyn1,  r3;                   -> interpolate between r2 and r3
         interp      dyn1,  r4,  dyn2,  r5;                 -> interpolate between r4 and r5
         
         macs    0,  0,  t1,  sti1;                         -> see below
         macs    t1,  accum,  dyn1,  sti2;                  -> t1 = (t1 * sti1) + (dyn1 * sti2) *** (crossfading)
         
         interp      out0,  t_in0,  level,  t1;             -> wet/dry mix
         interp      out1,  t_in1,  level,  t1;             -> wet/dry mix
         
         macs    t1,  &r1,  sti3,  0x1ff800;                -> 0x1ff800 = 1023 samples * 0x800
         macs    &r2,  t1,  0,  0;                          -> &r2 is moved fractional amount from &r1
         macsn   &r3,  &r2,  0x800,  -1;                    -> move &r3 1 sample location after &r2
         macintw     dyn1,  0,  t1,  0x100000;              -> see Max's reply (below)
    
         macw    t1,  sti3,  -1,  -1;                       -> t1 = sti3 + 1 *** (wraps around)
    
         macs    t1,  &r1,  t1,  0x1ff800;                  -> 0x1ff800 = 1023 samples * 0x800
         macs    &r4,  t1,  0,  0;                          -> &r4 is moved fractional amount from &r1 (opposite direction of &r2)
         macsn   &r5,  &r4,  0x800,  -1;                    -> move &r5 1 sample location after &r4
         macintw     dyn2,  0,  t1,  0x100000;              -> see Max's reply (below)
    
    end
    
     
    Last edited: May 16, 2011
  18. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    big thanks, Russ

    i've tried to translate pitch fx to c language but failed, although it can shift tones, it produce more noise than the original one, maybe the plugin use the "fractional" delay mentioned in as10k1 manual...
     
  19. Russ

    Russ Well-Known Member

    Joined:
    Jan 17, 2005
    Messages:
    5,722
    Likes Received:
    13
    Trophy Points:
    48
    I am not completely sure what the purpose of the macintw instructions are in the code... The note I made there was just something I noticed but may not be relevant... It seems to be doing 20 bit left shift(?) (of a value ranging from 0 to 0x1ff7ff (0 to (+/-)1022 samples * 0x800)), and the result seems to be used for interpolation between 2 samples (I wrote crossfade there, but I think that is probably doing interpolation between 2 contiguous samples(?), and the instructions immediately above/below that are doing crossfading).

    @Max M.
    Can you explain those instructions? It seems to be same code you wrote here: http://www.hardwareheaven.com/effects-dsp/43445-macw-wraparound.html#post332782
    ...But, I do not completely follow how it works. Can you give a few more details (e.g. what is the significance of the 0x100000, and why macintw?)?

    Code:
    ...
    ; calculate an interpolation coeffs for mixing taps... 
    ; (or, in other words, 'fractional part of new address')
    ; (should be done one sample later, after writing t1/t2 to address regs)
    macintw	t1, 0, t1, 0x100000 
    macintw	t2, 0, t2, 0x100000   
    
    ; interpolate between taps and output (e.g. 'smoothing')
    interp	out1, d11, t1, d12;     
    interp	out2, d21, t2, d22; 
    ...
    
     
    Last edited: May 15, 2011
  20. JoshuaChang

    JoshuaChang New Member

    Joined:
    Mar 22, 2003
    Messages:
    127
    Likes Received:
    0
    Trophy Points:
    0
    i have tested macintw R, 0x0, X, 0x100000,
    seems it looks like this:
    R = X << 20;
    if(R<0) R= (~R+1)|0x80000000
     

Share This Page

visited