You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdemultimedia/noatun/library/noatunarts/StereoVolumeControl_impl.cpp

182 lines
4.8 KiB

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <artsflow.h>
#include <stdsynthmodule.h>
#include <flowsystem.h>
#include "noatunarts.h"
using namespace Arts;
namespace Noatun
{
class StereoVolumeControl_impl : virtual public StereoVolumeControl_skel,
virtual public StdSynthModule
{
float mPercent;
float level;
public:
StereoVolumeControl_impl() : mPercent(1.0), level(0.0)
{ }
/*attribute float scaleFactor;*/
void percent(float p) { mPercent=p; }
float percent() { return mPercent; }
void calculateBlock(unsigned long samples)
{
float *left=inleft;
float *right=inright;
float *oleft=outleft;
float *oright=outright;
level = *right + *left;
float p=mPercent;
float *end=left+samples;
while (left<end)
{
*oleft=*left * p;
*oright=*right * p;
++left;
++right;
++oleft;
++oright;
}
}
AutoSuspendState autoSuspend()
{
return (level < 0.001) ? asSuspend : asNoSuspend;
}
};
class StereoVolumeControlSSE_impl : virtual public Noatun::StereoVolumeControlSSE_skel,
virtual public StdSynthModule
{
float mPercent;
float level;
public:
StereoVolumeControlSSE_impl() : mPercent(1.0), level(0.0)
{ }
/*attribute float scaleFactor;*/
void percent(float p) { mPercent=p; }
float percent() { return mPercent; }
void calculateBlock(unsigned long samples) __attribute__((noinline))
{
#ifdef HAVE_X86_SSE
float *left=inleft;
float *right=inright;
float *oleft=outleft;
float *oright=outright;
level = *right + *left;
// need to copy the data members to locals to get enough
// spare registers (malte)
long p = (long)(mPercent*100.0);
__asm__ __volatile__(
"pushl $100 \n"
"fildl (%%esp) \n"
#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2))
"addl $4, %%esp \n"
#endif
"fildl %5 \n"
"fdivp \n" // percent / 100.0
#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2))
"pushl $100 \n"
#endif
"fstps (%%esp) \n"
"movss (%%esp), %%xmm1 \n"
"shufps $0x00, %%xmm1, %%xmm1 \n" // percentage in all of xmm1
"addl $4, %%esp \n"
#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2))
"subl $4, %4 \n"
"jl .l2 \n" // samples < 4
#else
"pushl %4 \n" // save sample count
"shrl $2, %4 \n"
"jz .l2 \n" // samples < 4
#endif
"xorl %%ecx, %%ecx \n"
".l1: \n"
// left
"movups (%0, %%ecx, 8), %%xmm0 \n"
"mulps %%xmm1, %%xmm0 \n"
"movl %2, %%eax \n"
"movups %%xmm0, (%%eax, %%ecx, 8) \n"
// right
"movups (%1, %%ecx, 8), %%xmm0 \n"
"mulps %%xmm1, %%xmm0 \n"
"movl %3, %%eax \n"
"movups %%xmm0, (%%eax, %%ecx, 8) \n"
"incl %%ecx \n"
"incl %%ecx \n"
#if defined(__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2))
"subl $4, %4 \n"
"jge .l1 \n"
".l2: \n"
"addl $4, %4 \n"
#else
"decl %4 \n"
"jnz .l1 \n"
".l2: \n"
"popl %4 \n" // restore sample count
"andl $3, %4 \n"
#endif
"jz .l4 \n"
// calculate remaining samples for samples % 4 != 0
"shll $1, %%ecx \n"
".l3: \n"
"movss (%0, %%ecx, 4), %%xmm0 \n" // load left
"movss (%1, %%ecx, 4), %%xmm2 \n" // load right
"shufps $0x00, %%xmm2, %%xmm0 \n" // both channels in xmm0
"mulps %%xmm1, %%xmm0 \n"
"movl %2, %%eax \n"
"movss %%xmm0, (%%eax, %%ecx, 4) \n" // store left
"shufps $0x02, %%xmm0, %%xmm0 \n"
"movl %3, %%eax \n"
"movss %%xmm0, (%%eax, %%ecx, 4) \n" // store right
"incl %%ecx \n"
"decl %4 \n"
"jnz .l3 \n"
".l4: \n"
"emms \n"
:
: "r" (left), // %0
"r" (right), // %1
"m" (oleft), // %2
"m" (oright), // %3
"r" (samples), // %4
"m" (p) // %5
: "eax", "ecx"
);
#endif
}
AutoSuspendState autoSuspend()
{
return (level < 0.001) ? asSuspend : asNoSuspend;
}
};
REGISTER_IMPLEMENTATION(StereoVolumeControlSSE_impl);
REGISTER_IMPLEMENTATION(StereoVolumeControl_impl);
}