News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

What the role the inline assembly play ?

Started by vigour_lu, July 07, 2008, 08:50:15 AM

Previous topic - Next topic

vigour_lu

What the role the inline assembly play ? Please help me.


void VUMeter_48K_16b_stereo(void *pSamples, int nSampleCount, sVUMeter *pVUMeter)
{
    if (pVUMeter == NULL)
        return;

    if (pSamples == NULL || nSampleCount == 0) {
        // Treat it as silence audio
        pVUMeter->fPeakLeft = pVUMeter->fPeakRight = NS_MIN_VOL_IN_DB;
        pVUMeter->fVULeft = pVUMeter->fPeakRight = NS_MIN_VOL_IN_DB;
        pVUMeter->bClippedLeft = pVUMeter->bClippedRight = FALSE;
        return;
    }

    int32_t A2 = g_i32A2;
    int32_t B1 = g_i32B1;
    int32_t B2 = g_i32B1;
    int32_t WnLeft;                            // W(n)   Right channel
    int32_t WnRight;                        // W(n)   Left channel 
    int32_t Wnm1Left;                        // W(n-1) Right channel
    int32_t Wnm1Right;                        // W(n-1) Left channel
    int32_t ScaleFactor = g_i32ScaleFactor;    // Pi/2

    int32_t MaxLeft;                        // Peak   Right channel
    int32_t MaxRight;                        // Peak   Left channel
    int32_t VUResultLeft;                    // VU     Right channel
    int32_t VUResultRight;                    // VU     Left channel

    float fdBFSResult;

    // Get Dfilter memory W(n-1)
    Wnm1Left = pVUMeter->i32LastWLeft;
    Wnm1Right = pVUMeter->i32LastWRight;

    // Set peak original value to 0 (no feedback from previous buffer)
    MaxLeft = 0;
    MaxRight = 0;

    __asm {
        // Pre-loop setup
        mov            ecx, 0                    // Init loop counter and index
        mov            esi, [pSamples]            // Load audio samples data pointer
        movd        mm3, [MaxLeft]            // [       0        |     MaxLeft    ]
        movd        mm2, [MaxRight]            // [       0        |     MaxRight   ]
        punpcklwd    mm3, mm2                // [       0        |MaxRight|MaxLeft]
        movd        mm4, [Wnm1Left]            // [       0        |     WL(n-1)    ]
        movd        mm5, [Wnm1Right]        // [       0        |     WR(n-1)    ]

        // Core loop
VuLoopMMX2:         
        movd        mm0, [esi + ecx * 4]    // [       0        |    R   |   L   ]
        movq        mm1, mm0                // [       0        |    R   |   L   ]
        psraw        mm1, 15                    // Make a mask with the sign bit
        pxor        mm0, mm1                // Complement the number if was negative

        // The most negative sample will be converted to 0x7FFF instead of 0x8000.
        // 0x8000 would be interpreted as a negative value next in the "pcmpgtw  mm1,mm0"
        // so that the most negative value would not be seen as a peak and clip...

        movd        ebx, mm0                // [R L]

        // Peak detection
        movq        mm1, mm3                // [       0        |MaxRight|MaxLeft]
        pcmpgtw        mm1, mm0                // Mask where max value > sample value
        movq        mm2, mm1                // Copy the result mask
        pandn        mm1, mm0                // Now become 0 where max value > sample value
        pand        mm3, mm2                // Now become 0 where max value <= sample value
        por            mm3, mm1                // Produce the new max value

        // Compute W(n) = sample - (A2*W(n-1)) for left channel
        movd        edx, mm4                // [WL(n-1)]
        movd        mm6, edx                // [       0        |     WL(n-1)    ]
        shl            edx, 4
        mov            eax, [A2]
        imul        edx                        // EDX:EAX = (-A2) * WL(n-1)
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part
        mov            eax, ebx                // [R L]
        and            eax, 0xFFFF                // [ L ]
        add            edx, eax                // EDX = L - A2 * WL(n-1)
        movd        mm4, edx                // [       0        |L - A2 * WL(n-1)]

        // Compute W(n) = sample - (A2*W(n-1)) for right channel
        movd        edx, mm5                // [WR(n-1)]
        movd        mm7, edx                // [       0        |     WR(n-1)    ]
        shl            edx, 4
        mov            eax, [A2]
        imul        edx                        // EDX:EAX = (-A2) * WR(n-1)
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part
        shr            ebx, 16                    // [ R ]
        add            edx, ebx                // EDX = R - A2 * WR(n-1)
        movd        mm5, edx                // [       0        |L - A2 * WR(n-1)]

        add            ecx, 1
        cmp            ecx, [nSampleCount]        // compare to nbSample in buffers
        jne            VuLoopMMX2

        // Post-loop computations
        movd        eax, mm3                // [MaxRight|MaxLeft]
        and            eax, 0x7FFF                // [MaxLeft]
        mov            [MaxLeft], eax
        movd        eax, mm3                // [MaxRight|MaxLeft]
        shr            eax, 16                    // [MaxRight]
        mov            [MaxRight], eax
        movd        [WnLeft], mm4
        movd        [WnRight], mm5

        // Compute B1 * W0(n)
        mov            eax, [B1]
        movd        edx, mm4                // [WL(n)]
        shl            edx, 4
        imul        edx                        // EDX:EAX = (B1 * WL(n))
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part
        mov            ebx, edx                // Keep this result for later

        // Compute B2 * W0(n-1)
        mov            eax, [B2]
        movd        edx, mm6                // [WL(n-1)]
        shl            edx, 4
        imul        edx                        // EDX:EAX = (B2 * WL(n-1))
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part

        // Compute VUL = (B2 * WL(n-1)) + (B1 * WL(n))
        add            edx, ebx                // EDX = VUL(n) = (B1 * WL(n)) + (B2 * WL(n-1))

        // Compute VUL *= pi/2
        shl            edx, 4
        mov            eax, [ScaleFactor]
        imul        edx                        // EDX:EAX = VUL(n) * pi/2
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part
        mov            [VUResultLeft], edx        // Store VUL(n)

        // Compute B1 * W1(n)
        mov            eax, [B1]
        movd        edx, mm5                // [WR(n)]
        shl            edx, 4
        imul        edx                        // EDX:EAX = (B1 * WR(n))
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part
        mov            ebx, edx                // Keep this result for later

        // Compute B2 * W1(n-1)
        mov            eax, [B2]
        movd        edx, mm7                //  [WR(n-1)]
        shl            edx, 4
        imul        edx                        // EDX:EAX = (B2 * WR(n-1))
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part

        // Compute VUR = (B2 * WR(n-1)) + (B1 * WR(n))
        add            edx, ebx                // EDX = VUR(n) = (B1 * WR(n)) + (B2 * WR(n-1))

        // Compute VUR *= pi/2
        shl            edx, 4
        mov            eax, [ScaleFactor]
        imul        edx                        // EDX:EAX = VUR(n) * pi/2
        shr            eax, 31                    // MSB of EAX, the fractional part
        add            edx, eax                // Round EDX with fractional part
        mov            [VUResultRight], edx    // Store VUR(n)

        emms                                // Empty MMX state
    }

    // Store results in the tables
    pVUMeter->i32LastWLeft = WnLeft;
    pVUMeter->i32LastWRight = WnRight;
}


I added the code tags so it was easier to read.

hutch--

vigour_lu,

I am not quite sure what you are after with your question, you have posted C code with inline assembler but no explanation of your question. Could you tell us a little more ?
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

vigour_lu

I am very sorry for that I have not said clearly.  I want to know what function the inline assembly have .  Can this inline assembly's operation be explained by math expressions?

Tedd

The code is well commented - try reading them.

The function name is a nice giveaway -- VUMeter_48K_16b_stereo
So it's a 'vu-meter' which works on a 48k sample-rate 16-bit stereo block of audio.
And from the comments it appears to be calculating the volume levels for left and right channels.
No snowflake in an avalanche feels responsible.

vigour_lu


Yes, You are right. It's a vu-meter. And  thank you for that you make I  know how to  explain my question clearly.  Yes ,the inline
assembly is used to  calculate the volume levels for left and right channels. But I don't konw how does it calculate. Please help me.
thank you.