mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-02 09:01:50 -05:00
audioconvert: move dither and noise to fmt-ops
We need to do dithering and noise when converting f32 to the target format. This is more natural because we can work in 32 bits integers instead of floats. This will also make it possible to actually calculate the error between source and target values and implement some sort of feedback and noise shaping later.
This commit is contained in:
parent
51f4f1fb69
commit
6b49bded3a
9 changed files with 555 additions and 571 deletions
|
|
@ -736,6 +736,26 @@ conv_f64d_to_f32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void *
|
|||
}
|
||||
}
|
||||
|
||||
/* 32 bit xorshift PRNG, see https://en.wikipedia.org/wiki/Xorshift */
|
||||
static inline uint32_t
|
||||
xorshift(uint32_t *state)
|
||||
{
|
||||
uint32_t x = *state;
|
||||
x ^= x << 13;
|
||||
x ^= x >> 17;
|
||||
x ^= x << 5;
|
||||
return (*state = x);
|
||||
}
|
||||
|
||||
static inline void update_dither_c(struct convert *conv, uint32_t n_samples)
|
||||
{
|
||||
uint32_t n, mask = conv->mask;
|
||||
int32_t offset = conv->offset + conv->bias;
|
||||
|
||||
for (n = 0; n < n_samples; n++)
|
||||
conv->dither[n] = offset + (int32_t)(xorshift(&conv->random[0]) & mask);
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_u8d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -920,6 +940,29 @@ conv_f32d_to_s16d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s16d_dither_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
{
|
||||
uint32_t i, j, k, chunk, n_channels = conv->n_channels;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
const float *s = src[i];
|
||||
int16_t *d = dst[i];
|
||||
int32_t v;
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
v = F32_TO_S32(s[j]) + conv->dither[k];
|
||||
d[j] = v >> 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32_to_s16_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -962,6 +1005,28 @@ conv_f32d_to_s16_c(struct convert *conv, void * SPA_RESTRICT dst[], const void *
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s16_dither_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, k, chunk, n_channels = conv->n_channels;
|
||||
int32_t v;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
v = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
*d++ = v >> 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s16s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -976,6 +1041,28 @@ conv_f32d_to_s16s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s16s_dither_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, k, chunk, n_channels = conv->n_channels;
|
||||
int32_t v;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
v = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
*d++ = bswap_16(v >> 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32_to_u32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1019,6 +1106,26 @@ conv_f32d_to_s32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s32d_dither_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
{
|
||||
uint32_t i, j, k, chunk, n_channels = conv->n_channels;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
const float *s = src[i];
|
||||
int32_t *d = dst[i];
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++)
|
||||
d[j] = F32_TO_S32(s[j]) + conv->dither[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32_to_s32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1061,6 +1168,25 @@ conv_f32d_to_s32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void *
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s32_dither_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, k, chunk, n_channels = conv->n_channels;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++)
|
||||
*d++ = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s32s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1075,6 +1201,27 @@ conv_f32d_to_s32s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s32s_dither_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], v;
|
||||
uint32_t i, j, k, chunk, n_channels = conv->n_channels;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
v = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
*d++ = bswap_32(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_f64d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1195,6 +1342,30 @@ conv_f32d_to_s24d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24d_dither_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
{
|
||||
uint32_t i, j, k, chunk, n_channels = conv->n_channels;
|
||||
int32_t v;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
const float *s = src[i];
|
||||
uint8_t *d = dst[i];
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
v = F32_TO_S32(s[j]) + conv->dither[k];
|
||||
write_s24(d, v >> 8);
|
||||
d += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32_to_s24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1242,6 +1413,30 @@ conv_f32d_to_s24_c(struct convert *conv, void * SPA_RESTRICT dst[], const void *
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24_dither_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, k, chunk, n_channels = conv->n_channels;
|
||||
int32_t v;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
v = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
write_s24(d, v >> 8);
|
||||
d += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
conv_f32d_to_s24s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1258,6 +1453,28 @@ conv_f32d_to_s24s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24s_dither_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, k, chunk, n_channels = conv->n_channels;
|
||||
int32_t v;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
v = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
write_s24s(d, v >> 8);
|
||||
d += 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24_32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
|
|
@ -1274,6 +1491,29 @@ conv_f32d_to_s24_32d_c(struct convert *conv, void * SPA_RESTRICT dst[], const vo
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24_32d_dither_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
{
|
||||
uint32_t i, j, k, chunk, n_channels = conv->n_channels;
|
||||
int32_t v;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
const float *s = src[i];
|
||||
int32_t *d = dst[i];
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
v = F32_TO_S32(s[j]) + conv->dither[k];
|
||||
d[j] = v >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32_to_u24_32_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1344,6 +1584,27 @@ conv_f32d_to_s24_32_c(struct convert *conv, void * SPA_RESTRICT dst[], const voi
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24_32_dither_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], v;
|
||||
uint32_t i, j, k, chunk, n_channels = conv->n_channels;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
v = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
*d++ = v >> 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24_32s_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
@ -1358,6 +1619,27 @@ conv_f32d_to_s24_32s_c(struct convert *conv, void * SPA_RESTRICT dst[], const vo
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_f32d_to_s24_32s_dither_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], v;
|
||||
uint32_t i, j, k, chunk, n_channels = conv->n_channels;
|
||||
|
||||
update_dither_c(conv, SPA_MIN(n_samples, conv->dither_size));
|
||||
|
||||
for (j = 0; j < n_samples;) {
|
||||
chunk = SPA_MIN(n_samples - j, conv->dither_size);
|
||||
for (k = 0; k < chunk; k++, j++) {
|
||||
for (i = 0; i < n_channels; i++) {
|
||||
v = F32_TO_S32(s[i][j]) + conv->dither[k];
|
||||
*d++ = bswap_32(v >> 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
conv_deinterleave_8_c(struct convert *conv, void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[],
|
||||
uint32_t n_samples)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue