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