audioconvert: pass state to functions

Pass some state to convert and channelmix functions. This makes it
possible to select per channel optimized convert functions but
also makes it possible to implement noise shaping later.
Pass the channelmix matrix and volume in the state.
Handle specialized 2 channel s16 -> f32 conversion
This commit is contained in:
Wim Taymans 2019-03-29 17:39:59 +01:00
parent d47353c0e6
commit d8e399dee9
17 changed files with 952 additions and 685 deletions

View file

@ -63,6 +63,9 @@ static void run_test1(const char *name, const char *impl, bool in_packed, bool o
void *op[n_channels];
struct timespec ts;
uint64_t count, t1, t2;
struct convert conv;
conv.n_channels = n_channels;
for (j = 0; j < n_channels; j++) {
ip[j] = &samp_in[j * n_samples * 4];
@ -74,7 +77,7 @@ static void run_test1(const char *name, const char *impl, bool in_packed, bool o
count = 0;
for (i = 0; i < MAX_COUNT; i++) {
func(NULL, op, ip, n_channels, n_samples);
func(&conv, op, ip, n_samples);
count++;
}
clock_gettime(CLOCK_MONOTONIC, &ts);
@ -223,8 +226,6 @@ int main(int argc, char *argv[])
{
uint32_t i;
find_conv_info(0, 0, 0);
test_f32_u8();
test_u8_f32();
test_f32_s16();

View file

@ -25,13 +25,13 @@
#include "channelmix-ops.h"
void
channelmix_copy_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_copy_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)
@ -51,14 +51,14 @@ channelmix_copy_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
#define _M(ch) (1UL << SPA_AUDIO_CHANNEL_ ## ch)
void
channelmix_f32_n_m_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_n_m_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, j, n;
uint32_t i, j, n;
float **d = (float **) dst;
const float **s = (const float **) src;
const float *m = matrix;
const float *m = mix->matrix;
float v = mix->volume;
for (n = 0; n < n_samples; n++) {
for (i = 0; i < n_dst; i++) {
@ -74,13 +74,13 @@ channelmix_f32_n_m_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
#define MASK_STEREO _M(FL)|_M(FR)|_M(UNKNOWN)
void
channelmix_f32_1_2_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int n;
uint32_t n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
memset(d[0], 0, n_samples * sizeof(float));
@ -97,13 +97,13 @@ channelmix_f32_1_2_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
}
void
channelmix_f32_2_1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_2_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int n;
uint32_t n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
memset(d[0], 0, n_samples * sizeof(float));
@ -116,13 +116,13 @@ channelmix_f32_2_1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
}
void
channelmix_f32_4_1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_4_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int n;
uint32_t n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
memset(d[0], 0, n_samples * sizeof(float));
@ -135,13 +135,13 @@ channelmix_f32_4_1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
}
void
channelmix_f32_3p1_1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_3p1_1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int n;
uint32_t n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
memset(d[0], 0, n_samples * sizeof(float));
@ -157,13 +157,13 @@ channelmix_f32_3p1_1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
#define MASK_QUAD _M(FL)|_M(FR)|_M(RL)|_M(RR)|_M(UNKNOWN)
void
channelmix_f32_2_4_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_2_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)
@ -185,13 +185,13 @@ channelmix_f32_2_4_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
#define MASK_3_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)
void
channelmix_f32_2_3p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_2_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)
@ -218,13 +218,13 @@ channelmix_f32_2_3p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
#define MASK_5_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
void
channelmix_f32_2_5p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_2_5p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)
@ -251,17 +251,17 @@ channelmix_f32_2_5p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR -> FL+FR */
void
channelmix_f32_5p1_2_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_5p1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int n;
uint32_t n;
float **d = (float **) dst;
const float **s = (const float **) src;
const float *m = matrix;
const float *m = mix->matrix;
const float clev = m[2];
const float llev = m[3];
const float slev = m[4];
float v = mix->volume;
if (v <= VOLUME_MIN) {
memset(d[0], 0, n_samples * sizeof(float));
@ -285,13 +285,13 @@ channelmix_f32_5p1_2_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR -> FL+FR+FC+LFE*/
void
channelmix_f32_5p1_3p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_5p1_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **) dst;
const float **s = (const float **) src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)
@ -310,16 +310,16 @@ channelmix_f32_5p1_3p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR -> FL+FR+RL+RR*/
void
channelmix_f32_5p1_4_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_5p1_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **) dst;
const float **s = (const float **) src;
const float *m = matrix;
const float *m = mix->matrix;
const float clev = m[2];
const float llev = m[3];
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)
@ -349,17 +349,17 @@ channelmix_f32_5p1_4_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR+RL+RR -> FL+FR */
void
channelmix_f32_7p1_2_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_7p1_2_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int n;
uint32_t n;
float **d = (float **) dst;
const float **s = (const float **) src;
const float *m = matrix;
const float *m = mix->matrix;
const float clev = m[2];
const float llev = m[3];
const float slev = m[4];
float v = mix->volume;
if (v <= VOLUME_MIN) {
memset(d[0], 0, n_samples * sizeof(float));
@ -383,13 +383,13 @@ channelmix_f32_7p1_2_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR+RL+RR -> FL+FR+FC+LFE*/
void
channelmix_f32_7p1_3p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_7p1_3p1_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **) dst;
const float **s = (const float **) src;
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)
@ -408,17 +408,17 @@ channelmix_f32_7p1_3p1_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR+RL+RR -> FL+FR+RL+RR*/
void
channelmix_f32_7p1_4_c(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_7p1_4_c(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n;
uint32_t i, n;
float **d = (float **) dst;
const float **s = (const float **) src;
const float *m = matrix;
const float *m = mix->matrix;
const float clev = m[2];
const float llev = m[3];
const float slev = m[4];
float v = mix->volume;
if (v <= VOLUME_MIN) {
for (i = 0; i < n_dst; i++)

View file

@ -26,14 +26,13 @@
#include <xmmintrin.h>
void
channelmix_copy_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
void channelmix_copy_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n, unrolled;
uint32_t i, n, unrolled;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
const __m128 vol = _mm_set1_ps(v);
if (v <= VOLUME_MIN) {
@ -73,13 +72,13 @@ channelmix_copy_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
}
void
channelmix_f32_2_4_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_2_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n, unrolled;
uint32_t i, n, unrolled;
float **d = (float **)dst;
const float **s = (const float **)src;
float v = mix->volume;
const __m128 vol = _mm_set1_ps(v);
__m128 in;
const float *sFL = s[0], *sFR = s[1];
@ -139,14 +138,14 @@ channelmix_f32_2_4_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR -> FL+FR */
void
channelmix_f32_5p1_2_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_5p1_2_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int n, unrolled;
uint32_t n, unrolled;
float **d = (float **) dst;
const float **s = (const float **) src;
const float *m = matrix;
float v = mix->volume;
const float *m = mix->matrix;
const __m128 clev = _mm_set1_ps(m[2]);
const __m128 llev = _mm_set1_ps(m[3]);
const __m128 slev = _mm_set1_ps(m[4]);
@ -231,14 +230,14 @@ channelmix_f32_5p1_2_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
/* FL+FR+FC+LFE+SL+SR -> FL+FR+FC+LFE*/
void
channelmix_f32_5p1_3p1_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_5p1_3p1_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n, unrolled;
uint32_t i, n, unrolled;
float **d = (float **) dst;
const float **s = (const float **) src;
const __m128 mix = _mm_set1_ps(v * 0.5f);
float v = mix->volume;
const __m128 slev = _mm_set1_ps(v * 0.5f);
const __m128 vol = _mm_set1_ps(v);
__m128 avg[2];
const float *sFL = s[0], *sFR = s[1], *sFC = s[2], *sLFE = s[3], *sSL = s[4], *sSR = s[5];
@ -266,12 +265,12 @@ channelmix_f32_5p1_3p1_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst]
for(n = 0; n < unrolled; n += 8) {
avg[0] = _mm_add_ps(_mm_load_ps(&sFL[n]), _mm_load_ps(&sSL[n]));
avg[1] = _mm_add_ps(_mm_load_ps(&sFL[n+4]), _mm_load_ps(&sSL[n+4]));
_mm_store_ps(&dFL[n], _mm_mul_ps(avg[0], mix));
_mm_store_ps(&dFL[n+4], _mm_mul_ps(avg[1], mix));
_mm_store_ps(&dFL[n], _mm_mul_ps(avg[0], slev));
_mm_store_ps(&dFL[n+4], _mm_mul_ps(avg[1], slev));
avg[0] = _mm_add_ps(_mm_load_ps(&sFR[n]), _mm_load_ps(&sSR[n]));
avg[1] = _mm_add_ps(_mm_load_ps(&sFR[n+4]), _mm_load_ps(&sSR[n+4]));
_mm_store_ps(&dFR[n], _mm_mul_ps(avg[0], mix));
_mm_store_ps(&dFR[n+4], _mm_mul_ps(avg[1], mix));
_mm_store_ps(&dFR[n], _mm_mul_ps(avg[0], slev));
_mm_store_ps(&dFR[n+4], _mm_mul_ps(avg[1], slev));
_mm_store_ps(&dFC[n], _mm_load_ps(&sFC[n]));
_mm_store_ps(&dFC[n+4], _mm_load_ps(&sFC[n+4]));
_mm_store_ps(&dLFE[n], _mm_load_ps(&sLFE[n]));
@ -279,9 +278,9 @@ channelmix_f32_5p1_3p1_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst]
}
for(; n < n_samples; n++) {
avg[0] = _mm_add_ss(_mm_load_ss(&sFL[n]), _mm_load_ss(&sSL[n]));
_mm_store_ss(&dFL[n], _mm_mul_ss(avg[0], mix));
_mm_store_ss(&dFL[n], _mm_mul_ss(avg[0], slev));
avg[0] = _mm_add_ss(_mm_load_ss(&sFR[n]), _mm_load_ss(&sSR[n]));
_mm_store_ss(&dFR[n], _mm_mul_ss(avg[0], mix));
_mm_store_ss(&dFR[n], _mm_mul_ss(avg[0], slev));
_mm_store_ss(&dFC[n], _mm_load_ss(&sFC[n]));
_mm_store_ss(&dLFE[n], _mm_load_ss(&sLFE[n]));
}
@ -290,12 +289,12 @@ channelmix_f32_5p1_3p1_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst]
for(n = 0; n < unrolled; n += 8) {
avg[0] = _mm_add_ps(_mm_load_ps(&sFL[n]), _mm_load_ps(&sSL[n]));
avg[1] = _mm_add_ps(_mm_load_ps(&sFL[n+4]), _mm_load_ps(&sSL[n+4]));
_mm_store_ps(&dFL[n], _mm_mul_ps(avg[0], mix));
_mm_store_ps(&dFL[n+4], _mm_mul_ps(avg[1], mix));
_mm_store_ps(&dFL[n], _mm_mul_ps(avg[0], slev));
_mm_store_ps(&dFL[n+4], _mm_mul_ps(avg[1], slev));
avg[0] = _mm_add_ps(_mm_load_ps(&sFR[n]), _mm_load_ps(&sSR[n]));
avg[1] = _mm_add_ps(_mm_load_ps(&sFR[n+4]), _mm_load_ps(&sSR[n+4]));
_mm_store_ps(&dFR[n], _mm_mul_ps(avg[0], mix));
_mm_store_ps(&dFR[n+4], _mm_mul_ps(avg[1], mix));
_mm_store_ps(&dFR[n], _mm_mul_ps(avg[0], slev));
_mm_store_ps(&dFR[n+4], _mm_mul_ps(avg[1], slev));
_mm_store_ps(&dFC[n], _mm_mul_ps(_mm_load_ps(&sFC[n]), vol));
_mm_store_ps(&dFC[n+4], _mm_mul_ps(_mm_load_ps(&sFC[n+4]), vol));
_mm_store_ps(&dLFE[n], _mm_mul_ps(_mm_load_ps(&sLFE[n]), vol));
@ -303,9 +302,9 @@ channelmix_f32_5p1_3p1_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst]
}
for(; n < n_samples; n++) {
avg[0] = _mm_add_ss(_mm_load_ss(&sFL[n]), _mm_load_ss(&sSL[n]));
_mm_store_ss(&dFL[n], _mm_mul_ss(avg[0], mix));
_mm_store_ss(&dFL[n], _mm_mul_ss(avg[0], slev));
avg[0] = _mm_add_ss(_mm_load_ss(&sFR[n]), _mm_load_ss(&sSR[n]));
_mm_store_ss(&dFR[n], _mm_mul_ss(avg[0], mix));
_mm_store_ss(&dFR[n], _mm_mul_ss(avg[0], slev));
_mm_store_ss(&dFC[n], _mm_mul_ss(_mm_load_ss(&sFC[n]), vol));
_mm_store_ss(&dLFE[n], _mm_mul_ss(_mm_load_ss(&sLFE[n]), vol));
}
@ -314,14 +313,14 @@ channelmix_f32_5p1_3p1_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst]
/* FL+FR+FC+LFE+SL+SR -> FL+FR+RL+RR*/
void
channelmix_f32_5p1_4_sse(void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void *matrix, float v, int n_samples)
channelmix_f32_5p1_4_sse(struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples)
{
int i, n, unrolled;
uint32_t i, n, unrolled;
float **d = (float **) dst;
const float **s = (const float **) src;
const float *m = matrix;
const float *m = mix->matrix;
float v = mix->volume;
const __m128 clev = _mm_set1_ps(m[2]);
const __m128 llev = _mm_set1_ps(m[3]);
const __m128 vol = _mm_set1_ps(v);

View file

@ -24,8 +24,11 @@
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <spa/param/audio/format-utils.h>
#include <spa/support/cpu.h>
#include <spa/support/log.h>
#include <spa/utils/defs.h>
#define VOLUME_MIN 0.0f
@ -41,29 +44,26 @@
#define MASK_5_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
#define MASK_7_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
typedef void (*channelmix_func_t) (void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void * SPA_RESTRICT matrix, float v, int n_samples);
#define ANY ((uint32_t)-1)
#define EQ ((uint32_t)-2)
typedef void (*channelmix_func_t) (struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples);
static const struct channelmix_info {
uint32_t src_chan;
uint64_t src_mask;
uint32_t dst_chan;
uint64_t dst_mask;
channelmix_func_t func;
#define FEATURE_SSE SPA_CPU_FLAG_SSE
uint32_t features;
channelmix_func_t process;
uint32_t cpu_flags;
} channelmix_table[] =
{
#if defined (HAVE_SSE)
{ 2, MASK_MONO, 2, MASK_MONO, channelmix_copy_sse, FEATURE_SSE },
{ 2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_sse, FEATURE_SSE },
{ EQ, 0, EQ, 0, channelmix_copy_sse, FEATURE_SSE },
{ 2, MASK_MONO, 2, MASK_MONO, channelmix_copy_sse, SPA_CPU_FLAG_SSE },
{ 2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_sse, SPA_CPU_FLAG_SSE },
{ EQ, 0, EQ, 0, channelmix_copy_sse, SPA_CPU_FLAG_SSE },
#endif
{ 2, MASK_MONO, 2, MASK_MONO, channelmix_copy_c, 0 },
{ 2, MASK_STEREO, 2, MASK_STEREO, channelmix_copy_c, 0 },
@ -74,22 +74,22 @@ static const struct channelmix_info {
{ 4, MASK_QUAD, 1, MASK_MONO, channelmix_f32_4_1_c, 0 },
{ 4, MASK_3_1, 1, MASK_MONO, channelmix_f32_3p1_1_c, 0 },
#if defined (HAVE_SSE)
{ 2, MASK_STEREO, 4, MASK_QUAD, channelmix_f32_2_4_sse, FEATURE_SSE },
{ 2, MASK_STEREO, 4, MASK_QUAD, channelmix_f32_2_4_sse, SPA_CPU_FLAG_SSE },
#endif
{ 2, MASK_STEREO, 4, MASK_QUAD, channelmix_f32_2_4_c, 0 },
{ 2, MASK_STEREO, 4, MASK_3_1, channelmix_f32_2_3p1_c, 0 },
{ 2, MASK_STEREO, 6, MASK_5_1, channelmix_f32_2_5p1_c, 0 },
#if defined (HAVE_SSE)
{ 6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_sse, FEATURE_SSE },
{ 6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_sse, SPA_CPU_FLAG_SSE },
#endif
{ 6, MASK_5_1, 2, MASK_STEREO, channelmix_f32_5p1_2_c, 0 },
#if defined (HAVE_SSE)
{ 6, MASK_5_1, 4, MASK_QUAD, channelmix_f32_5p1_4_sse, FEATURE_SSE },
{ 6, MASK_5_1, 4, MASK_QUAD, channelmix_f32_5p1_4_sse, SPA_CPU_FLAG_SSE },
#endif
{ 6, MASK_5_1, 4, MASK_QUAD, channelmix_f32_5p1_4_c, 0 },
#if defined (HAVE_SSE)
{ 6, MASK_5_1, 4, MASK_3_1, channelmix_f32_5p1_3p1_sse, FEATURE_SSE },
{ 6, MASK_5_1, 4, MASK_3_1, channelmix_f32_5p1_3p1_sse, SPA_CPU_FLAG_SSE },
#endif
{ 6, MASK_5_1, 4, MASK_3_1, channelmix_f32_5p1_3p1_c, 0 },
@ -101,15 +101,15 @@ static const struct channelmix_info {
};
#define MATCH_CHAN(a,b) ((a) == ANY || (a) == (b))
#define MATCH_FEATURES(a,b) ((a) == 0 || ((a) & (b)) != 0)
#define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a)
#define MATCH_MASK(a,b) ((a) == 0 || ((a) & (b)) == (b))
static const struct channelmix_info *find_channelmix_info(uint32_t src_chan, uint64_t src_mask,
uint32_t dst_chan, uint64_t dst_mask, uint32_t features)
uint32_t dst_chan, uint64_t dst_mask, uint32_t cpu_flags)
{
size_t i;
for (i = 0; i < SPA_N_ELEMENTS(channelmix_table); i++) {
if (!MATCH_FEATURES(channelmix_table[i].features, features))
if (!MATCH_CPU_FLAGS(channelmix_table[i].cpu_flags, cpu_flags))
continue;
if (src_chan == dst_chan && src_mask == dst_mask)
@ -123,3 +123,253 @@ static const struct channelmix_info *find_channelmix_info(uint32_t src_chan, uin
}
return NULL;
}
#define M 0
#define FL 1
#define FR 2
#define FC 3
#define LFE 4
#define SL 5
#define SR 6
#define FLC 7
#define FRC 8
#define RC 9
#define RL 10
#define RR 11
#define TC 12
#define TFL 13
#define TFC 14
#define TFR 15
#define TRL 16
#define TRC 17
#define TRR 18
#define NUM_CHAN 19
#define SQRT3_2 1.224744871f /* sqrt(3/2) */
#define SQRT1_2 0.707106781f
#define SQRT2 1.414213562f
#define MATRIX_NORMAL 0
#define MATRIX_DOLBY 1
#define MATRIX_DPLII 2
#define _MASK(ch) (1ULL << SPA_AUDIO_CHANNEL_ ## ch)
#define STEREO (_MASK(FL)|_MASK(FR))
static int make_matrix(struct channelmix *mix)
{
float matrix[NUM_CHAN][NUM_CHAN] = {{ 0.0f }};
uint32_t src_chan = mix->src_chan;
uint64_t src_mask = mix->src_mask;
uint32_t dst_chan = mix->dst_chan;
uint64_t dst_mask = mix->dst_mask;
uint64_t unassigned;
uint32_t i, j, matrix_encoding = MATRIX_NORMAL, c;
float clev = SQRT1_2;
float slev = SQRT1_2;
float llev = 0.5f;
float max = 0.0f;
for (i = 0; i < NUM_CHAN; i++) {
if (src_mask & dst_mask & (1ULL << (i + 2)))
matrix[i][i]= 1.0f;
}
if ((dst_mask & _MASK(MONO)) == _MASK(MONO))
dst_mask = _MASK(FC);
unassigned = src_mask & ~dst_mask;
spa_log_debug(mix->log, "unassigned %08lx", unassigned);
if (unassigned & _MASK(FC)){
if ((dst_mask & STEREO) == STEREO){
if(src_mask & STEREO) {
matrix[FL][FC] += clev;
matrix[FR][FC] += clev;
} else {
matrix[FL][FC] += SQRT1_2;
matrix[FR][FC] += SQRT1_2;
}
} else {
spa_log_warn(mix->log, "can't assign FC");
}
}
if (unassigned & STEREO){
if (dst_mask & _MASK(FC)) {
matrix[FC][FL] += SQRT1_2;
matrix[FC][FR] += SQRT1_2;
if (src_mask & _MASK(FC))
matrix[FC][FC] = clev * SQRT2;
} else {
spa_log_warn(mix->log, "can't assign STEREO");
}
}
if (unassigned & _MASK(RC)) {
if (dst_mask & _MASK(RL)){
matrix[RL][RC] += SQRT1_2;
matrix[RR][RC] += SQRT1_2;
} else if (dst_mask & _MASK(SL)) {
matrix[SL][RC] += SQRT1_2;
matrix[SR][RC] += SQRT1_2;
} else if(dst_mask & _MASK(FL)) {
if (matrix_encoding == MATRIX_DOLBY ||
matrix_encoding == MATRIX_DPLII) {
if (unassigned & (_MASK(RL)|_MASK(RR))) {
matrix[FL][RC] -= slev * SQRT1_2;
matrix[FR][RC] += slev * SQRT1_2;
} else {
matrix[FL][RC] -= slev;
matrix[FR][RC] += slev;
}
} else {
matrix[FL][RC] += slev * SQRT1_2;
matrix[FR][RC] += slev * SQRT1_2;
}
} else if (dst_mask & _MASK(FC)) {
matrix[FC][RC] += slev * SQRT1_2;
} else {
spa_log_warn(mix->log, "can't assign RC");
}
}
if (unassigned & _MASK(RL)) {
if (dst_mask & _MASK(RC)) {
matrix[RC][RL] += SQRT1_2;
matrix[RC][RR] += SQRT1_2;
} else if (dst_mask & _MASK(SL)) {
if (src_mask & _MASK(SL)) {
matrix[SL][RL] += SQRT1_2;
matrix[SR][RR] += SQRT1_2;
} else {
matrix[SL][RL] += 1.0f;
matrix[SR][RR] += 1.0f;
}
} else if (dst_mask & _MASK(FL)) {
if (matrix_encoding == MATRIX_DOLBY) {
matrix[FL][RL] -= slev * SQRT1_2;
matrix[FL][RR] -= slev * SQRT1_2;
matrix[FR][RL] += slev * SQRT1_2;
matrix[FR][RR] += slev * SQRT1_2;
} else if (matrix_encoding == MATRIX_DPLII) {
matrix[FL][RL] -= slev * SQRT3_2;
matrix[FL][RR] -= slev * SQRT1_2;
matrix[FR][RL] += slev * SQRT1_2;
matrix[FR][RR] += slev * SQRT3_2;
} else {
matrix[FL][RL] += slev;
matrix[FR][RR] += slev;
}
} else if (dst_mask & _MASK(FC)) {
matrix[FC][RL]+= slev * SQRT1_2;
matrix[FC][RR]+= slev * SQRT1_2;
} else {
spa_log_warn(mix->log, "can't assign RL");
}
}
if (unassigned & _MASK(SL)) {
if (dst_mask & _MASK(RL)) {
if (src_mask & _MASK(RL)) {
matrix[RL][SL] += SQRT1_2;
matrix[RR][SR] += SQRT1_2;
} else {
matrix[RL][SL] += 1.0f;
matrix[RR][SR] += 1.0f;
}
} else if (dst_mask & _MASK(RC)) {
matrix[RC][SL]+= SQRT1_2;
matrix[RC][SR]+= SQRT1_2;
} else if (dst_mask & _MASK(FL)) {
if (matrix_encoding == MATRIX_DOLBY) {
matrix[FL][SL] -= slev * SQRT1_2;
matrix[FL][SR] -= slev * SQRT1_2;
matrix[FR][SL] += slev * SQRT1_2;
matrix[FR][SR] += slev * SQRT1_2;
} else if (matrix_encoding == MATRIX_DPLII) {
matrix[FL][SL] -= slev * SQRT3_2;
matrix[FL][SR] -= slev * SQRT1_2;
matrix[FR][SL] += slev * SQRT1_2;
matrix[FR][SR] += slev * SQRT3_2;
} else {
matrix[FL][SL] += slev;
matrix[FR][SR] += slev;
}
} else if (dst_mask & _MASK(FC)) {
matrix[FC][SL] += slev * SQRT1_2;
matrix[FC][SR] += slev * SQRT1_2;
} else {
spa_log_warn(mix->log, "can't assign SL");
}
}
if (unassigned & _MASK(FLC)) {
if (dst_mask & _MASK(FL)) {
matrix[FC][FLC]+= 1.0f;
matrix[FC][FRC]+= 1.0f;
} else if(dst_mask & _MASK(FC)) {
matrix[FC][FLC]+= SQRT1_2;
matrix[FC][FRC]+= SQRT1_2;
} else {
spa_log_warn(mix->log, "can't assign FLC");
}
}
if (unassigned & _MASK(LFE)) {
if (dst_mask & _MASK(FC)) {
matrix[FC][LFE] += llev;
} else if (dst_mask & _MASK(FL)) {
matrix[FL][LFE] += llev * SQRT1_2;
matrix[FR][LFE] += llev * SQRT1_2;
} else {
spa_log_warn(mix->log, "can't assign LFE");
}
}
c = 0;
for (i = 0; i < NUM_CHAN; i++) {
float sum = 0.0f;
if ((dst_mask & (1UL << (i + 2))) == 0)
continue;
for (j = 0; j < NUM_CHAN; j++) {
if ((src_mask & (1UL << (j + 2))) == 0)
continue;
mix->matrix[c++] = matrix[i][j];
sum += fabs(matrix[i][j]);
}
max = SPA_MAX(max, sum);
}
mix->is_identity = dst_chan == src_chan;
for (i = 0; i < dst_chan; i++) {
for (j = 0; j < src_chan; j++) {
float v = mix->matrix[i * src_chan + j];
spa_log_debug(mix->log, "%d %d: %f", i, j, v);
if ((i == j && v != 1.0f) ||
(i != j && v != 0.0f))
mix->is_identity = false;
}
}
return 0;
}
static void impl_channelmix_free(struct channelmix *mix)
{
mix->process = NULL;
}
int channelmix_init(struct channelmix *mix)
{
const struct channelmix_info *info;
info = find_channelmix_info(mix->src_chan, mix->src_mask, mix->dst_chan, mix->dst_mask,
mix->cpu_flags);
if (info == NULL)
return -ENOTSUP;
mix->free = impl_channelmix_free;
mix->process = info->process;
mix->cpu_flags = info->cpu_flags;
return make_matrix(mix);
}

View file

@ -30,6 +30,8 @@
#define VOLUME_MIN 0.0f
#define VOLUME_NORM 1.0f
#define MAX_CHANNELS 64
#define _M(ch) (1UL << SPA_AUDIO_CHANNEL_ ## ch)
#define MASK_MONO _M(FC)|_M(MONO)|_M(UNKNOWN)
#define MASK_STEREO _M(FL)|_M(FR)|_M(UNKNOWN)
@ -38,15 +40,37 @@
#define MASK_5_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
#define MASK_7_1 _M(FL)|_M(FR)|_M(FC)|_M(LFE)|_M(SL)|_M(SR)|_M(RL)|_M(RR)
typedef void (*channelmix_func_t) (void *data, int n_dst, void * SPA_RESTRICT dst[n_dst],
int n_src, const void * SPA_RESTRICT src[n_src],
const void * SPA_RESTRICT matrix, float v, int n_samples);
struct channelmix {
uint32_t src_chan;
uint32_t dst_chan;
uint64_t src_mask;
uint64_t dst_mask;
uint32_t cpu_flags;
struct spa_log *log;
int is_identity:1;
float volume;
float matrix[MAX_CHANNELS * MAX_CHANNELS];
void (*process) (struct channelmix *mix, uint32_t n_dst, void * SPA_RESTRICT dst[n_dst],
uint32_t n_src, const void * SPA_RESTRICT src[n_src], uint32_t n_samples);
void (*free) (struct channelmix *mix);
void *data;
};
int channelmix_init(struct channelmix *mix);
#define channelmix_process(mix,...) (mix)->process(mix, __VA_ARGS__)
#define channelmix_free(mix) (mix)->free(mix)
#define DEFINE_FUNCTION(name,arch) \
void channelmix_##name##_##arch(void *data, \
int n_dst, void * SPA_RESTRICT dst[n_dst], \
int n_src, const void * SPA_RESTRICT src[n_src], \
const void *matrix, float v, int n_samples);
void channelmix_##name##_##arch(struct channelmix *mix, \
uint32_t n_dst, void * SPA_RESTRICT dst[n_dst], \
uint32_t n_src, const void * SPA_RESTRICT src[n_src], \
uint32_t n_samples);
DEFINE_FUNCTION(copy, c);
DEFINE_FUNCTION(f32_n_m, c);

View file

@ -25,9 +25,10 @@
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
//#include <math.h>
#include <spa/support/log.h>
#include <spa/support/cpu.h>
#include <spa/utils/list.h>
#include <spa/node/node.h>
#include <spa/node/io.h>
@ -95,7 +96,7 @@ struct port {
struct spa_list queue;
};
#include "channelmix-ops.c"
#include "channelmix-ops.h"
struct impl {
struct spa_handle handle;
@ -115,12 +116,10 @@ struct impl {
struct port in_port;
struct port out_port;
channelmix_func_t convert;
struct channelmix mix;
int started:1;
int is_passthrough:1;
uint32_t cpu_flags;
uint32_t n_matrix;
float matrix[4096];
};
#define CHECK_PORT(this,d,id) (id == 0)
@ -131,35 +130,6 @@ struct impl {
#define _MASK(ch) (1ULL << SPA_AUDIO_CHANNEL_ ## ch)
#define STEREO (_MASK(FL)|_MASK(FR))
#define M 0
#define FL 1
#define FR 2
#define FC 3
#define LFE 4
#define SL 5
#define SR 6
#define FLC 7
#define FRC 8
#define RC 9
#define RL 10
#define RR 11
#define TC 12
#define TFL 13
#define TFC 14
#define TFR 15
#define TRL 16
#define TRC 17
#define TRR 18
#define NUM_CHAN 19
#define SQRT3_2 1.224744871f /* sqrt(3/2) */
#define SQRT1_2 0.707106781f
#define SQRT2 1.414213562f
#define MATRIX_NORMAL 0
#define MATRIX_DOLBY 1
#define MATRIX_DPLII 2
static uint64_t default_mask(uint32_t channels)
{
uint64_t mask = 0;
@ -193,210 +163,14 @@ static uint64_t default_mask(uint32_t channels)
return mask;
}
static int make_matrix(struct impl *this,
uint32_t src_chan, uint64_t src_mask,
uint32_t dst_chan, uint64_t dst_mask)
{
float matrix[NUM_CHAN][NUM_CHAN] = {{ 0.0f }};
uint64_t unassigned;
uint32_t i, j, matrix_encoding = MATRIX_NORMAL, c;
float clev = SQRT1_2;
float slev = SQRT1_2;
float llev = 0.5f;
float max = 0.0f;
for (i = 0; i < NUM_CHAN; i++) {
if (src_mask & dst_mask & (1ULL << (i + 2)))
matrix[i][i]= 1.0f;
}
if ((dst_mask & _MASK(MONO)) == _MASK(MONO))
dst_mask = _MASK(FC);
unassigned = src_mask & ~dst_mask;
spa_log_debug(this->log, "unassigned %08lx", unassigned);
if (unassigned & _MASK(FC)){
if ((dst_mask & STEREO) == STEREO){
if(src_mask & STEREO) {
matrix[FL][FC] += clev;
matrix[FR][FC] += clev;
} else {
matrix[FL][FC] += SQRT1_2;
matrix[FR][FC] += SQRT1_2;
}
} else {
spa_log_warn(this->log, "can't assign FC");
}
}
if (unassigned & STEREO){
if (dst_mask & _MASK(FC)) {
matrix[FC][FL] += SQRT1_2;
matrix[FC][FR] += SQRT1_2;
if (src_mask & _MASK(FC))
matrix[FC][FC] = clev * SQRT2;
} else {
spa_log_warn(this->log, "can't assign STEREO");
}
}
if (unassigned & _MASK(RC)) {
if (dst_mask & _MASK(RL)){
matrix[RL][RC] += SQRT1_2;
matrix[RR][RC] += SQRT1_2;
} else if (dst_mask & _MASK(SL)) {
matrix[SL][RC] += SQRT1_2;
matrix[SR][RC] += SQRT1_2;
} else if(dst_mask & _MASK(FL)) {
if (matrix_encoding == MATRIX_DOLBY ||
matrix_encoding == MATRIX_DPLII) {
if (unassigned & (_MASK(RL)|_MASK(RR))) {
matrix[FL][RC] -= slev * SQRT1_2;
matrix[FR][RC] += slev * SQRT1_2;
} else {
matrix[FL][RC] -= slev;
matrix[FR][RC] += slev;
}
} else {
matrix[FL][RC] += slev * SQRT1_2;
matrix[FR][RC] += slev * SQRT1_2;
}
} else if (dst_mask & _MASK(FC)) {
matrix[FC][RC] += slev * SQRT1_2;
} else {
spa_log_warn(this->log, "can't assign RC");
}
}
if (unassigned & _MASK(RL)) {
if (dst_mask & _MASK(RC)) {
matrix[RC][RL] += SQRT1_2;
matrix[RC][RR] += SQRT1_2;
} else if (dst_mask & _MASK(SL)) {
if (src_mask & _MASK(SL)) {
matrix[SL][RL] += SQRT1_2;
matrix[SR][RR] += SQRT1_2;
} else {
matrix[SL][RL] += 1.0f;
matrix[SR][RR] += 1.0f;
}
} else if (dst_mask & _MASK(FL)) {
if (matrix_encoding == MATRIX_DOLBY) {
matrix[FL][RL] -= slev * SQRT1_2;
matrix[FL][RR] -= slev * SQRT1_2;
matrix[FR][RL] += slev * SQRT1_2;
matrix[FR][RR] += slev * SQRT1_2;
} else if (matrix_encoding == MATRIX_DPLII) {
matrix[FL][RL] -= slev * SQRT3_2;
matrix[FL][RR] -= slev * SQRT1_2;
matrix[FR][RL] += slev * SQRT1_2;
matrix[FR][RR] += slev * SQRT3_2;
} else {
matrix[FL][RL] += slev;
matrix[FR][RR] += slev;
}
} else if (dst_mask & _MASK(FC)) {
matrix[FC][RL]+= slev * SQRT1_2;
matrix[FC][RR]+= slev * SQRT1_2;
} else {
spa_log_warn(this->log, "can't assign RL");
}
}
if (unassigned & _MASK(SL)) {
if (dst_mask & _MASK(RL)) {
if (src_mask & _MASK(RL)) {
matrix[RL][SL] += SQRT1_2;
matrix[RR][SR] += SQRT1_2;
} else {
matrix[RL][SL] += 1.0f;
matrix[RR][SR] += 1.0f;
}
} else if (dst_mask & _MASK(RC)) {
matrix[RC][SL]+= SQRT1_2;
matrix[RC][SR]+= SQRT1_2;
} else if (dst_mask & _MASK(FL)) {
if (matrix_encoding == MATRIX_DOLBY) {
matrix[FL][SL] -= slev * SQRT1_2;
matrix[FL][SR] -= slev * SQRT1_2;
matrix[FR][SL] += slev * SQRT1_2;
matrix[FR][SR] += slev * SQRT1_2;
} else if (matrix_encoding == MATRIX_DPLII) {
matrix[FL][SL] -= slev * SQRT3_2;
matrix[FL][SR] -= slev * SQRT1_2;
matrix[FR][SL] += slev * SQRT1_2;
matrix[FR][SR] += slev * SQRT3_2;
} else {
matrix[FL][SL] += slev;
matrix[FR][SR] += slev;
}
} else if (dst_mask & _MASK(FC)) {
matrix[FC][SL] += slev * SQRT1_2;
matrix[FC][SR] += slev * SQRT1_2;
} else {
spa_log_warn(this->log, "can't assign SL");
}
}
if (unassigned & _MASK(FLC)) {
if (dst_mask & _MASK(FL)) {
matrix[FC][FLC]+= 1.0f;
matrix[FC][FRC]+= 1.0f;
} else if(dst_mask & _MASK(FC)) {
matrix[FC][FLC]+= SQRT1_2;
matrix[FC][FRC]+= SQRT1_2;
} else {
spa_log_warn(this->log, "can't assign FLC");
}
}
if (unassigned & _MASK(LFE)) {
if (dst_mask & _MASK(FC)) {
matrix[FC][LFE] += llev;
} else if (dst_mask & _MASK(FL)) {
matrix[FL][LFE] += llev * SQRT1_2;
matrix[FR][LFE] += llev * SQRT1_2;
} else {
spa_log_warn(this->log, "can't assign LFE");
}
}
c = 0;
for (i = 0; i < NUM_CHAN; i++) {
float sum = 0.0f;
if ((dst_mask & (1UL << (i + 2))) == 0)
continue;
for (j = 0; j < NUM_CHAN; j++) {
if ((src_mask & (1UL << (j + 2))) == 0)
continue;
this->matrix[c++] = matrix[i][j];
sum += fabs(matrix[i][j]);
}
max = SPA_MAX(max, sum);
}
this->n_matrix = c;
this->is_passthrough = dst_chan == src_chan;
for (i = 0; i < dst_chan; i++) {
for (j = 0; j < src_chan; j++) {
float v = this->matrix[i * src_chan + j];
spa_log_debug(this->log, "%d %d: %f", i, j, v);
if (i == j && v != 1.0f)
this->is_passthrough = false;
}
}
return 0;
}
static int setup_convert(struct impl *this,
enum spa_direction direction,
const struct spa_audio_info *info)
{
const struct spa_audio_info *src_info, *dst_info;
uint32_t i, src_chan, dst_chan;
const struct channelmix_info *chanmix_info;
uint64_t src_mask, dst_mask;
int res;
if (direction == SPA_DIRECTION_INPUT) {
src_info = info;
@ -431,17 +205,21 @@ static int setup_convert(struct impl *this,
if (src_info->info.raw.rate != dst_info->info.raw.rate)
return -EINVAL;
/* find convert function */
if ((chanmix_info = find_channelmix_info(src_chan, src_mask,
dst_chan, dst_mask, this->cpu_flags)) == NULL)
return -ENOTSUP;
this->mix.src_chan = src_chan;
this->mix.src_mask = src_mask;
this->mix.dst_chan = dst_chan;
this->mix.dst_mask = dst_mask;
this->mix.cpu_flags = this->cpu_flags;
this->mix.log = this->log;
this->mix.volume = this->props.mute ? 0.0f : this->props.volume;
if ((res = channelmix_init(&this->mix)) < 0)
return res;
spa_log_info(this->log, NAME " %p: got channelmix features %08x:%08x",
this, this->cpu_flags, chanmix_info->features);
this, this->cpu_flags, this->mix.cpu_flags);
this->convert = chanmix_info->func;
return make_matrix(this, src_chan, src_mask, dst_chan, dst_mask);
return 0;
}
static int impl_node_enum_params(struct spa_node *node, int seq,
@ -544,6 +322,9 @@ static int apply_props(struct impl *this, const struct spa_pod *param)
break;
}
}
if (changed)
this->mix.volume = p->mute ? 0.0f : p->volume;
return changed;
}
@ -850,7 +631,7 @@ static int port_set_format(struct spa_node *node,
port->have_format = false;
clear_buffers(this, port);
}
this->convert = NULL;
channelmix_free(&this->mix);
} else {
struct spa_audio_info info = { 0 };
@ -1131,10 +912,11 @@ static int impl_node_process(struct spa_node *node)
const void *src_datas[n_src_datas];
void *dst_datas[n_dst_datas];
bool is_passthrough;
float v;
v = this->props.mute ? 0.0f : this->props.volume;
is_passthrough = this->is_passthrough && v == 1.0f;
is_passthrough = this->is_passthrough &&
this->mix.volume == 1.0f &&
this->mix.is_identity;
n_samples = sb->datas[0].chunk->size / inport->stride;
for (i = 0; i < n_src_datas; i++)
@ -1146,9 +928,8 @@ static int impl_node_process(struct spa_node *node)
}
if (!is_passthrough)
this->convert(this, n_dst_datas, dst_datas,
n_src_datas, src_datas,
this->matrix, v, n_samples);
channelmix_process(&this->mix, n_dst_datas, dst_datas,
n_src_datas, src_datas, n_samples);
}
outio->status = SPA_STATUS_HAVE_BUFFER;

View file

@ -33,66 +33,75 @@
#include "fmt-ops.h"
void
conv_copy8d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy8d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i;
uint32_t i, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++)
spa_memcpy(dst[i], src[i], n_samples);
}
void
conv_copy8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
spa_memcpy(dst[0], src[0], n_samples * n_channels);
spa_memcpy(dst[0], src[0], n_samples * conv->n_channels);
}
void
conv_copy16d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy16d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i;
uint32_t i, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++)
spa_memcpy(dst[i], src[i], n_samples * sizeof(int16_t));
}
void
conv_copy16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy16_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
spa_memcpy(dst[0], src[0], n_samples * sizeof(int16_t) * n_channels);
spa_memcpy(dst[0], src[0], n_samples * sizeof(int16_t) * conv->n_channels);
}
void
conv_copy24d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy24d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i;
uint32_t i, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++)
spa_memcpy(dst[i], src[i], n_samples * 3);
}
void
conv_copy24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
spa_memcpy(dst[0], src[0], n_samples * 3 * n_channels);
spa_memcpy(dst[0], src[0], n_samples * 3 * conv->n_channels);
}
void
conv_copy32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i;
uint32_t i, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++)
spa_memcpy(dst[i], src[i], n_samples * sizeof(int32_t));
}
void
conv_copy32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_copy32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
spa_memcpy(dst[0], src[0], n_samples * sizeof(int32_t) * n_channels);
spa_memcpy(dst[0], src[0], n_samples * sizeof(int32_t) * conv->n_channels);
}
void
conv_u8d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_u8d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const uint8_t *s = src[i];
@ -104,17 +113,26 @@ conv_u8d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_u8_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_u8_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_u8d_to_f32d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;;
const uint8_t *s = src[0];
float *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = U8_TO_F32(s[i]);
}
void
conv_u8_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_u8_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint8_t *s = src[0];
float **d = (float **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -123,11 +141,12 @@ conv_u8_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRI
}
void
conv_u8d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_u8d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint8_t **s = (const uint8_t **) src;
float *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -136,9 +155,10 @@ conv_u8d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRI
}
void
conv_s16d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s16d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const int16_t *s = src[i];
@ -149,17 +169,26 @@ conv_s16d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_REST
}
void
conv_s16_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s16_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_s16d_to_f32d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const int16_t *s = src[0];
float *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = S16_TO_F32(s[i]);
}
void
conv_s16_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s16_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int16_t *s = src[0];
float **d = (float **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -168,11 +197,12 @@ conv_s16_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_s16d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s16d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int16_t **s = (const int16_t **) src;
float *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -181,9 +211,10 @@ conv_s16d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_s32d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s32d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const int32_t *s = src[i];
@ -195,17 +226,26 @@ conv_s32d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_REST
}
void
conv_s32_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s32_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_s32d_to_f32d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const int32_t *s = src[0];
float *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = S32_TO_F32(s[i]);
}
void
conv_s32_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s32_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int32_t *s = src[0];
float **d = (float **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -214,11 +254,12 @@ conv_s32_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_s32d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s32d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int32_t **s = (const int32_t **) src;
float *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -227,9 +268,10 @@ conv_s32d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_s24d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const int8_t *s = src[i];
@ -243,17 +285,28 @@ conv_s24d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_REST
}
void
conv_s24_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_s24d_to_f32d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const int8_t *s = src[0];
float *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++) {
d[i] = S24_TO_F32(read_s24(s));
s += 3;
}
}
void
conv_s24_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint8_t *s = src[0];
float **d = (float **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++) {
@ -264,11 +317,12 @@ conv_s24_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_s24d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint8_t **s = (const uint8_t **) src;
float *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++) {
@ -278,9 +332,10 @@ conv_s24d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_s24_32d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_32d_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const int32_t *s = src[i];
@ -292,17 +347,26 @@ conv_s24_32d_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_R
}
void
conv_s24_32_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_32_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_s24_32d_to_f32d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const int32_t *s = src[0];
float *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = S24_TO_F32(s[i]);
}
void
conv_s24_32_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_32_to_f32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int32_t *s = src[0];
float **d = (float **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -311,11 +375,12 @@ conv_s24_32_to_f32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RE
}
void
conv_s24_32d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_32d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int32_t **s = (const int32_t **) src;
float *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -324,9 +389,10 @@ conv_s24_32d_to_f32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RE
}
void
conv_f32d_to_u8d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_u8d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const float *s = src[i];
@ -338,17 +404,26 @@ conv_f32d_to_u8d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_f32_to_u8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_u8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_f32d_to_u8d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const float *s = src[0];
uint8_t *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = F32_TO_U8(s[i]);
}
void
conv_f32_to_u8d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_u8d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float *s = src[0];
uint8_t **d = (uint8_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -357,11 +432,12 @@ conv_f32_to_u8d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRI
}
void
conv_f32d_to_u8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_u8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float **s = (const float **) src;
uint8_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -370,9 +446,10 @@ conv_f32d_to_u8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRI
}
void
conv_f32d_to_s16d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s16d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const float *s = src[i];
@ -384,17 +461,26 @@ conv_f32d_to_s16d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_REST
}
void
conv_f32_to_s16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s16_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_f32d_to_s16d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const float *s = src[0];
int16_t *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = F32_TO_S16(s[i]);
}
void
conv_f32_to_s16d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s16d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float *s = src[0];
int16_t **d = (int16_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -403,11 +489,12 @@ conv_f32_to_s16d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_f32d_to_s16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s16_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float **s = (const float **) src;
int16_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -416,9 +503,10 @@ conv_f32d_to_s16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_f32d_to_s32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const float *s = src[i];
@ -430,17 +518,26 @@ conv_f32d_to_s32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_REST
}
void
conv_f32_to_s32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_f32d_to_s32d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const float *s = src[0];
int32_t *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = F32_TO_S32(s[i]);
}
void
conv_f32_to_s32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float *s = src[0];
int32_t **d = (int32_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -449,11 +546,12 @@ conv_f32_to_s32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_f32d_to_s32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float **s = (const float **) src;
int32_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -464,9 +562,10 @@ conv_f32d_to_s32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
void
conv_f32d_to_s24d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s24d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const float *s = src[i];
@ -480,17 +579,28 @@ conv_f32d_to_s24d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_REST
}
void
conv_f32_to_s24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_f32d_to_s24d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const float *s = src[0];
uint8_t *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++) {
write_s24(d, F32_TO_S24(s[i]));
d += 3;
}
}
void
conv_f32_to_s24d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s24d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float *s = src[0];
uint8_t **d = (uint8_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++) {
@ -500,11 +610,12 @@ conv_f32_to_s24d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
}
void
conv_f32d_to_s24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float **s = (const float **) src;
uint8_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++) {
@ -516,9 +627,10 @@ conv_f32d_to_s24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTR
void
conv_f32d_to_s24_32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s24_32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (i = 0; i < n_channels; i++) {
const float *s = src[i];
@ -530,17 +642,26 @@ conv_f32d_to_s24_32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_R
}
void
conv_f32_to_s24_32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s24_32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
conv_f32d_to_s24_32d_c(data, dst, src, 1, n_samples * n_channels);
uint32_t i, n_channels = conv->n_channels;
const float *s = src[0];
int32_t *d = dst[0];
n_samples *= n_channels;
for (i = 0; i < n_samples; i++)
d[i] = F32_TO_S24(s[i]);
}
void
conv_f32_to_s24_32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32_to_s24_32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float *s = src[0];
int32_t **d = (int32_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -549,11 +670,12 @@ conv_f32_to_s24_32d_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RE
}
void
conv_f32d_to_s24_32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s24_32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const float **s = (const float **) src;
int32_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -562,11 +684,12 @@ conv_f32d_to_s24_32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RE
}
void
conv_deinterleave_8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_deinterleave_8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint8_t *s = src[0];
uint8_t **d = (uint8_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -575,11 +698,12 @@ conv_deinterleave_8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RE
}
void
conv_deinterleave_16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_deinterleave_16_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint16_t *s = src[0];
uint16_t **d = (uint16_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -588,11 +712,12 @@ conv_deinterleave_16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_R
}
void
conv_deinterleave_24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_deinterleave_24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint8_t *s = src[0];
uint8_t **d = (uint8_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++) {
@ -603,11 +728,12 @@ conv_deinterleave_24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_R
}
void
conv_deinterleave_32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_deinterleave_32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const uint32_t *s = src[0];
uint32_t **d = (uint32_t **) dst;
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -616,11 +742,12 @@ conv_deinterleave_32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_R
}
void
conv_interleave_8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_interleave_8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int8_t **s = (const int8_t **) src;
uint8_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -629,11 +756,12 @@ conv_interleave_8_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_REST
}
void
conv_interleave_16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_interleave_16_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int16_t **s = (const int16_t **) src;
uint16_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)
@ -642,11 +770,12 @@ conv_interleave_16_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RES
}
void
conv_interleave_24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_interleave_24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int8_t **s = (const int8_t **) src;
uint8_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++) {
@ -657,11 +786,12 @@ conv_interleave_24_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RES
}
void
conv_interleave_32_c(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_interleave_32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int32_t **s = (const int32_t **) src;
uint32_t *d = dst[0];
uint32_t i, j;
uint32_t i, j, n_channels = conv->n_channels;
for (j = 0; j < n_samples; j++) {
for (i = 0; i < n_channels; i++)

View file

@ -27,7 +27,8 @@
#include <emmintrin.h>
static void
conv_s16_to_f32d_1_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
conv_s16_to_f32d_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const int16_t *s = src;
float **d = (float **) dst;
@ -60,18 +61,29 @@ conv_s16_to_f32d_1_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_
}
}
static void
conv_s16_to_f32d_2_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
void
conv_s16_to_f32d_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int16_t *s = src;
const int16_t *s = src[0];
uint32_t i = 0, n_channels = conv->n_channels;
for(; i < n_channels; i++)
conv_s16_to_f32d_1s_sse2(conv, &dst[i], &s[i], n_channels, n_samples);
}
void
conv_s16_to_f32d_2_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int16_t *s = src[0];
float **d = (float **) dst;
float *d0 = d[0], *d1 = d[1];
uint32_t n, unrolled;
__m128i in, t[2];
__m128 out[2], factor = _mm_set1_ps(1.0f / S16_SCALE);
if (n_channels == 2 &&
SPA_IS_ALIGNED(s, 16) &&
if (SPA_IS_ALIGNED(s, 16) &&
SPA_IS_ALIGNED(d0, 16) &&
SPA_IS_ALIGNED(d1, 16))
unrolled = n_samples & ~3;
@ -93,7 +105,7 @@ conv_s16_to_f32d_2_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_
_mm_store_ps(&d0[n], out[0]);
_mm_store_ps(&d1[n], out[1]);
s += 4*n_channels;
s += 8;
}
for(; n < n_samples; n++) {
out[0] = _mm_cvtsi32_ss(out[0], s[0]);
@ -102,24 +114,13 @@ conv_s16_to_f32d_2_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_
out[1] = _mm_mul_ss(out[1], factor);
_mm_store_ss(&d0[n], out[0]);
_mm_store_ss(&d1[n], out[1]);
s += n_channels;
s += 2;
}
}
void
conv_s16_to_f32d_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
{
const int16_t *s = src[0];
uint32_t i = 0;
for(; i + 1 < n_channels; i += 2)
conv_s16_to_f32d_2_sse2(data, &dst[i], &s[i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_s16_to_f32d_1_sse2(data, &dst[i], &s[i], n_channels, n_samples);
}
void
conv_s24_to_f32d_1_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const uint8_t *s = src;
float **d = (float **) dst;
@ -158,7 +159,8 @@ conv_s24_to_f32d_1_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_
}
static void
conv_s24_to_f32d_2_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_2s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const uint8_t *s = src;
float **d = (float **) dst;
@ -217,7 +219,8 @@ conv_s24_to_f32d_2_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_
}
}
static void
conv_s24_to_f32d_4_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_4s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const uint8_t *s = src;
float **d = (float **) dst;
@ -305,21 +308,23 @@ conv_s24_to_f32d_4_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_
}
void
conv_s24_to_f32d_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int8_t *s = src[0];
uint32_t i = 0;
uint32_t i = 0, n_channels = conv->n_channels;
for(; i + 3 < n_channels; i += 4)
conv_s24_to_f32d_4_sse2(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_4s_sse2(conv, &dst[i], &s[3*i], n_channels, n_samples);
for(; i + 1 < n_channels; i += 2)
conv_s24_to_f32d_2_sse2(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_2s_sse2(conv, &dst[i], &s[3*i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_s24_to_f32d_1_sse2(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_1s_sse2(conv, &dst[i], &s[3*i], n_channels, n_samples);
}
static void
conv_f32d_to_s32_1_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s32_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
uint32_t n_channels, uint32_t n_samples)
{
const float **s = (const float **) src;
const float *s0 = s[0];
@ -359,7 +364,8 @@ conv_f32d_to_s32_1_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RE
}
static void
conv_f32d_to_s32_2_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s32_2s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
uint32_t n_channels, uint32_t n_samples)
{
const float **s = (const float **) src;
const float *s0 = s[0], *s1 = s[1];
@ -410,7 +416,8 @@ conv_f32d_to_s32_2_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RE
}
static void
conv_f32d_to_s32_4_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s32_4s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
uint32_t n_channels, uint32_t n_samples)
{
const float **s = (const float **) src;
const float *s0 = s[0], *s1 = s[1], *s2 = s[2], *s3 = s[3];
@ -472,21 +479,23 @@ conv_f32d_to_s32_4_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RE
}
void
conv_f32d_to_s32_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s32_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
int32_t *d = dst[0];
uint32_t i = 0;
uint32_t i = 0, n_channels = conv->n_channels;
for(; i + 3 < n_channels; i += 4)
conv_f32d_to_s32_4_sse2(data, &d[i], &src[i], n_channels, n_samples);
conv_f32d_to_s32_4s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
for(; i + 1 < n_channels; i += 2)
conv_f32d_to_s32_2_sse2(data, &d[i], &src[i], n_channels, n_samples);
conv_f32d_to_s32_2s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_f32d_to_s32_1_sse2(data, &d[i], &src[i], n_channels, n_samples);
conv_f32d_to_s32_1s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
}
static void
conv_f32d_to_s16_1_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s16_1s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
uint32_t n_channels, uint32_t n_samples)
{
const float **s = (const float **) src;
const float *s0 = s[0];
@ -528,7 +537,8 @@ conv_f32d_to_s16_1_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RE
}
static void
conv_f32d_to_s16_2_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s16_2s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
uint32_t n_channels, uint32_t n_samples)
{
const float **s = (const float **) src;
const float *s0 = s[0], *s1 = s[1];
@ -578,7 +588,8 @@ conv_f32d_to_s16_2_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RE
}
static void
conv_f32d_to_s16_4_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s16_4s_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[],
uint32_t n_channels, uint32_t n_samples)
{
const float **s = (const float **) src;
const float *s0 = s[0], *s1 = s[1], *s2 = s[2], *s3 = s[3];
@ -641,15 +652,16 @@ conv_f32d_to_s16_4_sse2(void *data, void * SPA_RESTRICT dst, const void * SPA_RE
}
void
conv_f32d_to_s16_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_f32d_to_s16_sse2(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
int16_t *d = dst[0];
uint32_t i = 0;
uint32_t i = 0, n_channels = conv->n_channels;
for(; i + 3 < n_channels; i += 4)
conv_f32d_to_s16_4_sse2(data, &d[i], &src[i], n_channels, n_samples);
conv_f32d_to_s16_4s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
for(; i + 1 < n_channels; i += 2)
conv_f32d_to_s16_2_sse2(data, &d[i], &src[i], n_channels, n_samples);
conv_f32d_to_s16_2s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_f32d_to_s16_1_sse2(data, &d[i], &src[i], n_channels, n_samples);
conv_f32d_to_s16_1s_sse2(conv, &d[i], &src[i], n_channels, n_samples);
}

View file

@ -27,7 +27,8 @@
#include <smmintrin.h>
static void
conv_s24_to_f32d_1_sse41(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_1s_sse41(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const uint8_t *s = src;
float **d = (float **) dst;
@ -61,23 +62,26 @@ conv_s24_to_f32d_1_sse41(void *data, void * SPA_RESTRICT dst[], const void * SPA
}
}
extern void conv_s24_to_f32d_2_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples);
extern void conv_s24_to_f32d_4_ssse3(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples);
extern void conv_s24_to_f32d_2s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples);
extern void conv_s24_to_f32d_4s_ssse3(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples);
void
conv_s24_to_f32d_sse41(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_sse41(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int8_t *s = src[0];
uint32_t i = 0;
uint32_t i = 0, n_channels = conv->n_channels;
#if defined (HAVE_SSSE3)
for(; i + 3 < n_channels; i += 4)
conv_s24_to_f32d_4_ssse3(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_4s_ssse3(conv, &dst[i], &s[3*i], n_channels, n_samples);
#endif
#if defined (HAVE_SSE2)
for(; i + 1 < n_channels; i += 2)
conv_s24_to_f32d_2_sse2(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_2s_sse2(conv, &dst[i], &s[3*i], n_channels, n_samples);
#endif
for(; i < n_channels; i++)
conv_s24_to_f32d_1_sse41(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_1s_sse41(conv, &dst[i], &s[3*i], n_channels, n_samples);
}

View file

@ -27,7 +27,8 @@
#include <tmmintrin.h>
static void
conv_s24_to_f32d_4_ssse3(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_4s_ssse3(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples)
{
const uint8_t *s = src;
float **d = (float **) dst;
@ -94,16 +95,18 @@ conv_s24_to_f32d_4_ssse3(void *data, void * SPA_RESTRICT dst[], const void * SPA
}
void
conv_s24_to_f32d_1_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src, uint32_t n_channels, uint32_t n_samples);
conv_s24_to_f32d_1s_sse2(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src,
uint32_t n_channels, uint32_t n_samples);
void
conv_s24_to_f32d_ssse3(void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], uint32_t n_channels, uint32_t n_samples)
conv_s24_to_f32d_ssse3(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples)
{
const int8_t *s = src[0];
uint32_t i = 0;
uint32_t i = 0, n_channels = conv->n_channels;
for(; i + 3 < n_channels; i += 4)
conv_s24_to_f32d_4_ssse3(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_4s_ssse3(conv, &dst[i], &s[3*i], n_channels, n_samples);
for(; i < n_channels; i++)
conv_s24_to_f32d_1_sse2(data, &dst[i], &s[3*i], n_channels, n_samples);
conv_s24_to_f32d_1s_sse2(conv, &dst[i], &s[3*i], n_channels, n_samples);
}

View file

@ -32,135 +32,163 @@
#include "fmt-ops.h"
typedef void (*convert_func_t) (struct convert *conv, void * SPA_RESTRICT dst[],
const void * SPA_RESTRICT src[], uint32_t n_samples);
struct conv_info {
uint32_t src_fmt;
uint32_t dst_fmt;
#define FEATURE_SSE2 SPA_CPU_FLAG_SSE2
#define FEATURE_SSE41 SPA_CPU_FLAG_SSE41
#define FEATURE_SSSE3 SPA_CPU_FLAG_SSSE3
uint32_t features;
uint32_t n_channels;
uint32_t cpu_flags;
convert_func_t func;
convert_func_t process;
};
static struct conv_info conv_table[] =
{
/* to f32 */
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_F32, 0, conv_u8_to_f32_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_F32P, 0, conv_u8d_to_f32d_c },
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_F32P, 0, conv_u8_to_f32d_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_F32, 0, conv_u8d_to_f32_c },
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u8_to_f32_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u8d_to_f32d_c },
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_u8_to_f32d_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_u8d_to_f32_c },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32, 0, conv_s16_to_f32_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_F32P, 0, conv_s16d_to_f32d_c },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s16_to_f32_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s16d_to_f32d_c },
#if defined (HAVE_SSE2)
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, FEATURE_SSE2, conv_s16_to_f32d_sse2 },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 2, SPA_CPU_FLAG_SSE2, conv_s16_to_f32d_2_sse2 },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE2, conv_s16_to_f32d_sse2 },
#endif
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 0, conv_s16_to_f32d_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_F32, 0, conv_s16d_to_f32_c },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s16_to_f32d_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s16d_to_f32_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32, 0, conv_copy32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32P, 0, conv_copy32d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, conv_deinterleave_32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, conv_interleave_32_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_copy32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_copy32d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_deinterleave_32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_interleave_32_c },
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32, 0, conv_s32_to_f32_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_F32P, 0, conv_s32d_to_f32d_c },
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32P, 0, conv_s32_to_f32d_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_F32, 0, conv_s32d_to_f32_c },
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s32_to_f32_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s32d_to_f32d_c },
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s32_to_f32d_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s32d_to_f32_c },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32, 0, conv_s24_to_f32_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_F32P, 0, conv_s24d_to_f32d_c },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24_to_f32_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24d_to_f32d_c },
#if defined (HAVE_SSSE3)
// { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, FEATURE_SSSE3, conv_s24_to_f32d_ssse3 },
// { SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSSE3, conv_s24_to_f32d_ssse3 },
#endif
#if defined (HAVE_SSE41)
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, FEATURE_SSE41, conv_s24_to_f32d_sse41 },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE41, conv_s24_to_f32d_sse41 },
#endif
#if defined (HAVE_SSE2)
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, FEATURE_SSE2, conv_s24_to_f32d_sse2 },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, SPA_CPU_FLAG_SSE2, conv_s24_to_f32d_sse2 },
#endif
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, conv_s24_to_f32d_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_F32, 0, conv_s24d_to_f32_c },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_to_f32d_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24d_to_f32_c },
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_F32, 0, conv_s24_32_to_f32_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_F32P, 0, conv_s24_32d_to_f32d_c },
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_F32P, 0, conv_s24_32_to_f32d_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_F32, 0, conv_s24_32d_to_f32_c },
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24_32_to_f32_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_32d_to_f32d_c },
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_F32P, 0, 0, conv_s24_32_to_f32d_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_F32, 0, 0, conv_s24_32d_to_f32_c },
/* from f32 */
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8, 0, conv_f32_to_u8_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8P, 0, conv_f32d_to_u8d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8P, 0, conv_f32_to_u8d_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8, 0, conv_f32d_to_u8_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8, 0, 0, conv_f32_to_u8_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_f32d_to_u8d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_f32_to_u8d_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_U8, 0, 0, conv_f32d_to_u8_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S16, 0, conv_f32_to_s16_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16P, 0, conv_f32d_to_s16d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S16P, 0, conv_f32_to_s16d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S16, 0, 0, conv_f32_to_s16_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_f32d_to_s16d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_f32_to_s16d_c },
#if defined (HAVE_SSE2)
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, FEATURE_SSE2, conv_f32d_to_s16_sse2 },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 0, SPA_CPU_FLAG_SSE2, conv_f32d_to_s16_sse2 },
#endif
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 0, conv_f32d_to_s16_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S16, 0, 0, conv_f32d_to_s16_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S32, 0, conv_f32_to_s32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32P, 0, conv_f32d_to_s32d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S32P, 0, conv_f32_to_s32d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S32, 0, 0, conv_f32_to_s32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_f32d_to_s32d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_f32_to_s32d_c },
#if defined (HAVE_SSE2)
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32, FEATURE_SSE2, conv_f32d_to_s32_sse2 },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32, 0, SPA_CPU_FLAG_SSE2, conv_f32d_to_s32_sse2 },
#endif
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32, 0, conv_f32d_to_s32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_f32d_to_s32_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24, 0, conv_f32_to_s24_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24P, 0, conv_f32d_to_s24d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24P, 0, conv_f32_to_s24d_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24, 0, conv_f32d_to_s24_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24, 0, 0, conv_f32_to_s24_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_f32d_to_s24d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_f32_to_s24d_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24, 0, 0, conv_f32d_to_s24_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24_32, 0, conv_f32_to_s24_32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32P, 0, conv_f32d_to_s24_32d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24_32P, 0, conv_f32_to_s24_32d_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32, 0, conv_f32d_to_s24_32_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_f32_to_s24_32_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_f32d_to_s24_32d_c },
{ SPA_AUDIO_FORMAT_F32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_f32_to_s24_32d_c },
{ SPA_AUDIO_FORMAT_F32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_f32d_to_s24_32_c },
/* u8 */
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8, 0, conv_copy8_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8P, 0, conv_copy8d_c },
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8P, 0, conv_deinterleave_8_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8, 0, conv_interleave_8_c },
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8, 0, 0, conv_copy8_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_copy8d_c },
{ SPA_AUDIO_FORMAT_U8, SPA_AUDIO_FORMAT_U8P, 0, 0, conv_deinterleave_8_c },
{ SPA_AUDIO_FORMAT_U8P, SPA_AUDIO_FORMAT_U8, 0, 0, conv_interleave_8_c },
/* s16 */
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_S16, 0, conv_copy16_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_S16P, 0, conv_copy16d_c },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_S16P, 0, conv_deinterleave_16_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_S16, 0, conv_interleave_16_c },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_S16, 0, 0, conv_copy16_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_copy16d_c },
{ SPA_AUDIO_FORMAT_S16, SPA_AUDIO_FORMAT_S16P, 0, 0, conv_deinterleave_16_c },
{ SPA_AUDIO_FORMAT_S16P, SPA_AUDIO_FORMAT_S16, 0, 0, conv_interleave_16_c },
/* s32 */
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32, 0, conv_copy32_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32P, 0, conv_copy32d_c },
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, conv_deinterleave_32_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, conv_interleave_32_c },
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32, 0, 0, conv_copy32_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_copy32d_c },
{ SPA_AUDIO_FORMAT_S32, SPA_AUDIO_FORMAT_S32P, 0, 0, conv_deinterleave_32_c },
{ SPA_AUDIO_FORMAT_S32P, SPA_AUDIO_FORMAT_S32, 0, 0, conv_interleave_32_c },
/* s24 */
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_S24, 0, conv_copy24_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_S24P, 0, conv_copy24d_c },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_S24P, 0, conv_deinterleave_24_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_S24, 0, conv_interleave_24_c },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_S24, 0, 0, conv_copy24_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_copy24d_c },
{ SPA_AUDIO_FORMAT_S24, SPA_AUDIO_FORMAT_S24P, 0, 0, conv_deinterleave_24_c },
{ SPA_AUDIO_FORMAT_S24P, SPA_AUDIO_FORMAT_S24, 0, 0, conv_interleave_24_c },
/* s24_32 */
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32, 0, conv_copy32_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32P, 0, conv_copy32d_c },
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, conv_deinterleave_32_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, conv_interleave_32_c },
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_copy32_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_copy32d_c },
{ SPA_AUDIO_FORMAT_S24_32, SPA_AUDIO_FORMAT_S24_32P, 0, 0, conv_deinterleave_32_c },
{ SPA_AUDIO_FORMAT_S24_32P, SPA_AUDIO_FORMAT_S24_32, 0, 0, conv_interleave_32_c },
};
static const struct conv_info *find_conv_info(uint32_t src_fmt, uint32_t dst_fmt, uint32_t features)
#define MATCH_CHAN(a,b) ((a) == 0 || (a) == (b))
#define MATCH_CPU_FLAGS(a,b) ((a) == 0 || ((a) & (b)) == a)
static const struct conv_info *find_conv_info(uint32_t src_fmt, uint32_t dst_fmt,
uint32_t n_channels, uint32_t cpu_flags)
{
size_t i;
for (i = 0; i < SPA_N_ELEMENTS(conv_table); i++) {
if (conv_table[i].src_fmt == src_fmt &&
conv_table[i].dst_fmt == dst_fmt &&
(conv_table[i].features == 0 || (conv_table[i].features & features) != 0))
MATCH_CHAN(conv_table[i].n_channels, n_channels) &&
MATCH_CPU_FLAGS(conv_table[i].cpu_flags, cpu_flags))
return &conv_table[i];
}
return NULL;
}
static void impl_convert_free(struct convert *conv)
{
conv->process = NULL;
}
int convert_init(struct convert *conv)
{
const struct conv_info *info;
info = find_conv_info(conv->src_fmt, conv->dst_fmt, conv->n_channels, conv->cpu_flags);
if (info == NULL)
return -ENOTSUP;
conv->is_passthrough = conv->src_fmt == conv->dst_fmt;
conv->cpu_flags = info->cpu_flags;
conv->process = info->process;
conv->free = impl_convert_free;
return 0;
}

View file

@ -77,13 +77,32 @@ static inline void write_s24(void *dst, int32_t val)
#endif
}
typedef void (*convert_func_t) (void *data, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_channels, uint32_t n_samples);
#define MAX_NS 64
struct convert {
uint32_t src_fmt;
uint32_t dst_fmt;
uint32_t n_channels;
uint32_t cpu_flags;
int is_passthrough:1;
float ns_data[MAX_NS];
uint32_t ns_idx;
uint32_t ns_size;
void (*process) (struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
uint32_t n_samples);
void (*free) (struct convert *conv);
};
int convert_init(struct convert *conv);
#define convert_process(conv,...) (conv)->process(conv, __VA_ARGS__)
#define convert_free(conv) (conv)->free(conv)
#define DEFINE_FUNCTION(name,arch) \
void conv_##name##_##arch(void *data, void * SPA_RESTRICT dst[], \
const void * SPA_RESTRICT src[], \
uint32_t n_channels, uint32_t n_samples)
void conv_##name##_##arch(struct convert *conv, void * SPA_RESTRICT dst[], \
const void * SPA_RESTRICT src[], uint32_t n_samples) \
DEFINE_FUNCTION(copy8d, c);
DEFINE_FUNCTION(copy8, c);
@ -143,6 +162,7 @@ DEFINE_FUNCTION(interleave_24, c);
DEFINE_FUNCTION(interleave_32, c);
#if defined(HAVE_SSE2)
DEFINE_FUNCTION(s16_to_f32d_2, sse2);
DEFINE_FUNCTION(s16_to_f32d, sse2);
DEFINE_FUNCTION(s24_to_f32d, sse2);
DEFINE_FUNCTION(f32d_to_s32, sse2);

View file

@ -39,6 +39,8 @@
#include <spa/debug/types.h>
#include <spa/debug/format.h>
#include "fmt-ops.h"
#define NAME "fmtconvert"
#define DEFAULT_RATE 48000
@ -97,8 +99,6 @@ struct port {
struct spa_list queue;
};
#include "fmt-ops.c"
struct impl {
struct spa_handle handle;
struct spa_node node;
@ -120,7 +120,7 @@ struct impl {
bool started;
uint32_t cpu_flags;
convert_func_t convert;
struct convert conv;
int is_passthrough:1;
};
@ -143,8 +143,8 @@ static int setup_convert(struct impl *this)
uint32_t src_fmt, dst_fmt;
struct spa_audio_info informat, outformat;
struct port *inport, *outport;
const struct conv_info *conv;
uint32_t i, j;
int res;
inport = GET_IN_PORT(this, 0);
outport = GET_OUT_PORT(this, 0);
@ -181,16 +181,19 @@ static int setup_convert(struct impl *this)
}
}
/* find fast path */
conv = find_conv_info(src_fmt, dst_fmt, this->cpu_flags);
if (conv == NULL)
return -ENOTSUP;
this->conv.src_fmt = src_fmt;
this->conv.dst_fmt = dst_fmt;
this->conv.n_channels = outformat.info.raw.channels;
this->conv.cpu_flags = this->cpu_flags;
if ((res = convert_init(&this->conv)) < 0)
return res;
spa_log_info(this->log, NAME " %p: got converter features %08x:%08x", this,
this->cpu_flags, conv->features);
this->cpu_flags, this->conv.cpu_flags);
this->is_passthrough = this->conv.is_passthrough;
this->convert = conv->func;
this->is_passthrough = src_fmt == dst_fmt;
return 0;
}
@ -556,7 +559,7 @@ static int port_set_format(struct spa_node *node,
if (port->have_format) {
port->have_format = false;
clear_buffers(this, port);
this->convert = NULL;
convert_free(&this->conv);
}
} else {
struct spa_audio_info info = { 0 };
@ -801,7 +804,7 @@ static int impl_node_process(struct spa_node *node)
struct spa_buffer *inb, *outb;
const void **src_datas;
void **dst_datas;
uint32_t i, n_src_datas, n_dst_datas, n_datas;
uint32_t i, n_src_datas, n_dst_datas;
int res = 0;
uint32_t n_samples, size, maxsize, offs;
@ -863,8 +866,6 @@ static int impl_node_process(struct spa_node *node)
spa_log_trace_fp(this->log, NAME " %p: n_src:%d n_dst:%d size:%d maxsize:%d n_samples:%d",
this, n_src_datas, n_dst_datas, size, maxsize, n_samples);
n_datas = SPA_MAX(n_src_datas, n_dst_datas);
for (i = 0; i < n_dst_datas; i++) {
dst_datas[i] = this->is_passthrough ?
(void*)src_datas[i] :
@ -875,7 +876,7 @@ static int impl_node_process(struct spa_node *node)
}
if (!this->is_passthrough)
this->convert(this, dst_datas, src_datas, n_datas, n_samples);
convert_process(&this->conv, dst_datas, src_datas, n_samples);
inio->status = SPA_STATUS_NEED_BUFFER;
res |= SPA_STATUS_NEED_BUFFER;

View file

@ -27,6 +27,7 @@
#include <stdio.h>
#include <limits.h>
#include <spa/support/cpu.h>
#include <spa/support/log.h>
#include <spa/utils/list.h>
#include <spa/node/node.h>
@ -39,6 +40,8 @@
#include <spa/debug/mem.h>
#include <spa/debug/pod.h>
#include "fmt-ops.h"
#define NAME "merger"
#define DEFAULT_RATE 48000
@ -81,8 +84,6 @@ struct port {
struct spa_list queue;
};
#include "fmt-ops.c"
struct impl {
struct spa_handle handle;
struct spa_node node;
@ -101,7 +102,7 @@ struct impl {
struct port in_ports[MAX_PORTS];
struct port out_ports[MAX_PORTS + 1];
convert_func_t convert;
struct convert conv;
uint32_t cpu_flags;
int is_passthrough:1;
int started:1;
@ -543,9 +544,9 @@ static int clear_buffers(struct impl *this, struct port *port)
static int setup_convert(struct impl *this)
{
const struct conv_info *conv;
struct port *outport;
uint32_t src_fmt, dst_fmt;
int res;
outport = GET_OUT_PORT(this, 0);
@ -561,16 +562,20 @@ static int setup_convert(struct impl *this)
outport->format.info.raw.channels,
outport->format.info.raw.rate);
conv = find_conv_info(src_fmt, dst_fmt, this->cpu_flags);
if (conv != NULL) {
spa_log_info(this->log, NAME " %p: got converter features %08x:%08x", this,
this->cpu_flags, conv->features);
this->conv.src_fmt = src_fmt;
this->conv.dst_fmt = dst_fmt;
this->conv.n_channels = outport->format.info.raw.channels;
this->conv.cpu_flags = this->cpu_flags;
this->convert = conv->func;
this->is_passthrough = src_fmt == dst_fmt;
return 0;
}
return -ENOTSUP;
if ((res = convert_init(&this->conv)) < 0)
return res;
spa_log_info(this->log, NAME " %p: got converter features %08x:%08x", this,
this->cpu_flags, this->conv.cpu_flags);
this->is_passthrough = src_fmt == dst_fmt;
return 0;
}
static int calc_width(struct spa_audio_info *info)
@ -942,7 +947,7 @@ static int impl_node_process(struct spa_node *node)
outport = GET_OUT_PORT(this, 0);
outio = outport->io;
spa_return_val_if_fail(outio != NULL, -EIO);
spa_return_val_if_fail(this->convert != NULL, -EIO);
spa_return_val_if_fail(this->conv.process != NULL, -EIO);
spa_log_trace_fp(this->log, NAME " %p: status %d %d", this, outio->status, outio->buffer_id);
@ -995,7 +1000,7 @@ static int impl_node_process(struct spa_node *node)
n_samples * outport->stride);
}
if (!this->is_passthrough)
this->convert(this, dst_datas, src_datas, SPA_MAX(n_dst_datas, n_src_datas), n_samples);
convert_process(&this->conv, dst_datas, src_datas, n_samples);
return res | SPA_STATUS_HAVE_BUFFER;
}

View file

@ -1,5 +1,7 @@
audioconvert_sources = ['fmtconvert.c',
'fmt-ops.c',
'channelmix.c',
'channelmix-ops.c',
'resample.c',
'splitter.c',
'merger.c',
@ -23,7 +25,7 @@ if have_sse
audioconvert_sse = static_library('audioconvert_sse',
['resample-native-sse.c',
'channelmix-ops-sse.c' ],
c_args : [sse_args, '-O3'],
c_args : [sse_args, '-O3', '-DHAVE_SSE'],
include_directories : [spa_inc],
install : false
)
@ -33,7 +35,7 @@ endif
if have_sse2
audioconvert_sse2 = static_library('audioconvert_sse2',
['fmt-ops-sse2.c' ],
c_args : [sse2_args, '-O3'],
c_args : [sse2_args, '-O3', '-DHAVE_SSE2'],
include_directories : [spa_inc],
install : false
)
@ -44,7 +46,7 @@ if have_ssse3
audioconvert_ssse3 = static_library('audioconvert_ssse3',
['fmt-ops-ssse3.c',
'resample-native-ssse3.c' ],
c_args : [ssse3_args, '-O3'],
c_args : [ssse3_args, '-O3', '-DHAVE_SSSE3'],
include_directories : [spa_inc],
install : false
)
@ -54,7 +56,7 @@ endif
if have_sse41
audioconvert_sse41 = static_library('audioconvert_sse41',
['fmt-ops-sse41.c'],
c_args : [sse41_args, '-O3'],
c_args : [sse41_args, '-O3', '-DHAVE_SSE41'],
include_directories : [spa_inc],
install : false
)
@ -64,7 +66,7 @@ endif
if have_avx and have_fma
audioconvert_avx = static_library('audioconvert_avx',
['resample-native-avx.c'],
c_args : [avx2_args, fma_args, '-O3'],
c_args : [avx2_args, fma_args, '-O3', '-DHAVE_AVX', '-DHAVE_FMA'],
include_directories : [spa_inc],
install : false
)

View file

@ -27,6 +27,7 @@
#include <stdio.h>
#include <limits.h>
#include <spa/support/cpu.h>
#include <spa/support/log.h>
#include <spa/utils/list.h>
#include <spa/node/node.h>
@ -38,6 +39,8 @@
#include <spa/debug/mem.h>
#include <spa/debug/pod.h>
#include "fmt-ops.h"
#define NAME "splitter"
#define DEFAULT_RATE 48000
@ -84,8 +87,6 @@ struct port {
struct spa_list queue;
};
#include "fmt-ops.c"
struct impl {
struct spa_handle handle;
struct spa_node node;
@ -104,7 +105,7 @@ struct impl {
uint32_t port_count;
uint32_t cpu_flags;
convert_func_t convert;
struct convert conv;
int is_passthrough:1;
int started:1;
@ -530,9 +531,9 @@ static int clear_buffers(struct impl *this, struct port *port)
static int setup_convert(struct impl *this)
{
const struct conv_info *conv;
struct port *inport;
uint32_t src_fmt, dst_fmt;
int res;
inport = GET_IN_PORT(this, 0);
@ -548,16 +549,21 @@ static int setup_convert(struct impl *this)
inport->format.info.raw.rate,
this->port_count);
conv = find_conv_info(src_fmt, dst_fmt, this->cpu_flags);
if (conv != NULL) {
spa_log_info(this->log, NAME " %p: got converter features %08x:%08x", this,
this->cpu_flags, conv->features);
this->convert = conv->func;
this->is_passthrough = src_fmt == dst_fmt;
return 0;
}
return -ENOTSUP;
this->conv.src_fmt = src_fmt;
this->conv.dst_fmt = dst_fmt;
this->conv.n_channels = inport->format.info.raw.channels;
this->conv.cpu_flags = this->cpu_flags;
if ((res = convert_init(&this->conv)) < 0)
return res;
spa_log_info(this->log, NAME " %p: got converter features %08x:%08x", this,
this->cpu_flags, this->conv.cpu_flags);
this->is_passthrough = this->conv.is_passthrough;
return 0;
}
static int calc_width(struct spa_audio_info *info)
@ -846,7 +852,7 @@ static int impl_node_process(struct spa_node *node)
inport = GET_IN_PORT(this, 0);
inio = inport->io;
spa_return_val_if_fail(inio != NULL, -EIO);
spa_return_val_if_fail(this->convert != NULL, -EIO);
spa_return_val_if_fail(this->conv.process != NULL, -EIO);
spa_log_trace_fp(this->log, NAME " %p: status %p %d %d", this,
inio, inio->status, inio->buffer_id);
@ -924,7 +930,7 @@ static int impl_node_process(struct spa_node *node)
n_src_datas, n_dst_datas, n_samples, maxsize, inport->stride);
if (!this->is_passthrough)
this->convert(this, dst_datas, src_datas, SPA_MAX(n_dst_datas, n_src_datas), n_samples);
convert_process(&this->conv, dst_datas, src_datas, n_samples);
inio->status = SPA_STATUS_NEED_BUFFER;
res |= SPA_STATUS_NEED_BUFFER;

View file

@ -49,6 +49,9 @@ static void run_test(const char *name,
void *tp[N_CHANNELS];
int i, j;
const uint8_t *in8 = in, *out8 = out;
struct convert conv;
conv.n_channels = N_CHANNELS;
for (j = 0; j < N_SAMPLES; j++) {
memcpy(&samp_in[j * in_size], &in8[(j % n_samples) * in_size], in_size);
@ -62,16 +65,16 @@ static void run_test(const char *name,
tp[0] = temp_in;
switch(in_size) {
case 1:
conv_interleave_8_c(NULL, tp, ip, N_CHANNELS, N_SAMPLES);
conv_interleave_8_c(&conv, tp, ip, N_SAMPLES);
break;
case 2:
conv_interleave_16_c(NULL, tp, ip, N_CHANNELS, N_SAMPLES);
conv_interleave_16_c(&conv, tp, ip, N_SAMPLES);
break;
case 3:
conv_interleave_24_c(NULL, tp, ip, N_CHANNELS, N_SAMPLES);
conv_interleave_24_c(&conv, tp, ip, N_SAMPLES);
break;
case 4:
conv_interleave_32_c(NULL, tp, ip, N_CHANNELS, N_SAMPLES);
conv_interleave_32_c(&conv, tp, ip, N_SAMPLES);
break;
default:
fprintf(stderr, "unknown size %zd\n", in_size);
@ -84,7 +87,7 @@ static void run_test(const char *name,
for (j = 0; j < N_CHANNELS; j++)
tp[j] = &temp_out[j * N_SAMPLES * out_size];
func(NULL, tp, ip, N_CHANNELS, N_SAMPLES);
func(&conv, tp, ip, N_SAMPLES);
fprintf(stderr, "test %s:\n", name);
if (out_packed) {
@ -260,8 +263,6 @@ static void test_s24_32_f32(void)
int main(int argc, char *argv[])
{
find_conv_info(0, 0, 0);
test_f32_u8();
test_u8_f32();
test_f32_s16();