Add partial_tukey and punchout_tukey apodization functions

Adds two new apodization functions that seem to perform better than
the apodization functions currently in the codebase and fixes three
existing windows as well.

Its important to note that this patch only affects the encoder stage
that evaluates various possible predictors. Audio encoded with these
new windows will still decode with existing legacy decoders.

= Theory =
These functions are used to window the  audio data at the predictor
stage. These news functions enable the use of only part of the signal
to generate a predictor. This helps  because short transients can
introduce noise into the predictor. The  predictor becomes very good
at prediciting one part of the  signal, instead of mediocre for the
whole block.

Signed-off-by: Erik de Castro Lopo <erikd@mega-nerd.com>
This commit is contained in:
Martijn van Beurden
2014-08-10 10:59:29 +02:00
committed by Erik de Castro Lopo
parent ffa55423e0
commit 29a28338c3
8 changed files with 152 additions and 12 deletions

View File

@@ -65,6 +65,8 @@ void FLAC__window_nuttall(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_rectangle(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L);
void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p);
void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end);
void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L);
#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */

View File

@@ -59,6 +59,8 @@ typedef enum {
FLAC__APODIZATION_RECTANGLE,
FLAC__APODIZATION_TRIANGLE,
FLAC__APODIZATION_TUKEY,
FLAC__APODIZATION_PARTIAL_TUKEY,
FLAC__APODIZATION_PUNCHOUT_TUKEY,
FLAC__APODIZATION_WELCH
} FLAC__ApodizationFunction;
@@ -71,6 +73,11 @@ typedef struct {
struct {
FLAC__real p;
} tukey;
struct {
FLAC__real p;
FLAC__real start;
FLAC__real end;
} multiple_tukey;
} parameters;
} FLAC__ApodizationSpecification;

View File

@@ -1664,6 +1664,48 @@ FLAC_API FLAC__bool FLAC__stream_encoder_set_apodization(FLAC__StreamEncoder *en
encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
}
}
else if(n>15 && 0 == strncmp("partial_tukey(" , specification, 14)) {
FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+14, 0);
const char *si_1 = strchr(specification, '/');
FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.1f;
FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f;
const char *si_2 = strchr((si_1?(si_1+1):specification), '/');
FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f;
if (tukey_parts <= 1) {
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p;
encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
}else if (encoder->protected_->num_apodizations + tukey_parts < 32){
FLAC__int32 m;
for(m = 0; m < tukey_parts; m++){
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p;
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units);
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units);
encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PARTIAL_TUKEY;
}
}
}
else if(n>16 && 0 == strncmp("punchout_tukey(" , specification, 15)) {
FLAC__int32 tukey_parts = (FLAC__int32)strtod(specification+15, 0);
const char *si_1 = strchr(specification, '/');
FLAC__real overlap = si_1?flac_min((FLAC__real)strtod(si_1+1, 0),0.99f):0.2f;
FLAC__real overlap_units = 1.0f/(1.0f - overlap) - 1.0f;
const char *si_2 = strchr((si_1?(si_1+1):specification), '/');
FLAC__real tukey_p = si_2?(FLAC__real)strtod(si_2+1, 0):0.2f;
if (tukey_parts <= 1) {
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.tukey.p = tukey_p;
encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_TUKEY;
}else if (encoder->protected_->num_apodizations + tukey_parts < 32){
FLAC__int32 m;
for(m = 0; m < tukey_parts; m++){
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.p = tukey_p;
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.start = m/(tukey_parts+overlap_units);
encoder->protected_->apodizations[encoder->protected_->num_apodizations].parameters.multiple_tukey.end = (m+1+overlap_units)/(tukey_parts+overlap_units);
encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_PUNCHOUT_TUKEY;
}
}
}
else if(n==5 && 0 == strncmp("welch" , specification, n))
encoder->protected_->apodizations[encoder->protected_->num_apodizations++].type = FLAC__APODIZATION_WELCH;
if (encoder->protected_->num_apodizations == 32)
@@ -2443,6 +2485,12 @@ FLAC__bool resize_buffers_(FLAC__StreamEncoder *encoder, unsigned new_blocksize)
case FLAC__APODIZATION_TUKEY:
FLAC__window_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.tukey.p);
break;
case FLAC__APODIZATION_PARTIAL_TUKEY:
FLAC__window_partial_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end);
break;
case FLAC__APODIZATION_PUNCHOUT_TUKEY:
FLAC__window_punchout_tukey(encoder->private_->window[i], new_blocksize, encoder->protected_->apodizations[i].parameters.multiple_tukey.p, encoder->protected_->apodizations[i].parameters.multiple_tukey.start, encoder->protected_->apodizations[i].parameters.multiple_tukey.end);
break;
case FLAC__APODIZATION_WELCH:
FLAC__window_welch(encoder->private_->window[i], new_blocksize);
break;

View File

@@ -58,7 +58,7 @@ void FLAC__window_bartlett(FLAC__real *window, const FLAC__int32 L)
for (n = 0; n <= L/2-1; n++)
window[n] = 2.0f * n / (float)N;
for (; n <= N; n++)
window[n] = 2.0f - 2.0f * (N-n) / (float)N;
window[n] = 2.0f - 2.0f * n / (float)N;
}
}
@@ -68,7 +68,7 @@ void FLAC__window_bartlett_hann(FLAC__real *window, const FLAC__int32 L)
FLAC__int32 n;
for (n = 0; n < L; n++)
window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N+0.5f) + 0.38f * cos(2.0f * M_PI * ((float)n/(float)N+0.5f)));
window[n] = (FLAC__real)(0.62f - 0.48f * fabs((float)n/(float)N-0.5f) - 0.38f * cos(2.0f * M_PI * ((float)n/(float)N)));
}
void FLAC__window_blackman(FLAC__real *window, const FLAC__int32 L)
@@ -173,16 +173,16 @@ void FLAC__window_triangle(FLAC__real *window, const FLAC__int32 L)
FLAC__int32 n;
if (L & 1) {
for (n = 1; n <= L+1/2; n++)
for (n = 1; n <= (L+1)/2; n++)
window[n-1] = 2.0f * n / ((float)L + 1.0f);
for (; n <= L; n++)
window[n-1] = - (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
}
else {
for (n = 1; n <= L/2; n++)
window[n-1] = 2.0f * n / (float)L;
window[n-1] = 2.0f * n / ((float)L + 1.0f);
for (; n <= L; n++)
window[n-1] = ((float)(2 * (L - n)) + 1.0f) / (float)L;
window[n-1] = (float)(2 * (L - n + 1)) / ((float)L + 1.0f);
}
}
@@ -207,6 +207,61 @@ void FLAC__window_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__rea
}
}
void FLAC__window_partial_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
{
const FLAC__int32 start_n = (FLAC__int32)(start * L);
const FLAC__int32 end_n = (FLAC__int32)(end * L);
const FLAC__int32 N = end_n - start_n;
FLAC__int32 Np, n, i;
if (p <= 0.0)
FLAC__window_partial_tukey(window, L, 0.01, start, end);
else if (p >= 1.0)
FLAC__window_partial_tukey(window, L, 1, start, end);
Np = (FLAC__int32)(p / 2.0f * N) - 1;
for (n = 0; n < start_n; n++)
window[n] = 0.0f;
for (i = 1; n < (start_n+Np); n++, i++)
window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
for (; n < (end_n-Np); n++)
window[n] = 1.0f;
for (i = Np; n < end_n; n++, i--)
window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Np));
for (; n < L; n++)
window[n] = 0.0f;
}
void FLAC__window_punchout_tukey(FLAC__real *window, const FLAC__int32 L, const FLAC__real p, const FLAC__real start, const FLAC__real end)
{
const FLAC__int32 start_n = (FLAC__int32)(start * L);
const FLAC__int32 end_n = (FLAC__int32)(end * L);
FLAC__int32 Ns, Ne, n, i;
if (p <= 0.0)
FLAC__window_partial_tukey(window, L, 0.01, start, end);
else if (p >= 1.0)
FLAC__window_partial_tukey(window, L, 1, start, end);
Ns = (FLAC__int32)(p / 2.0f * start_n);
Ne = (FLAC__int32)(p / 2.0f * (L - end_n));
for (n = 0, i = 1; n < Ns; n++, i++)
window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
for (; n < start_n-Ns; n++)
window[n] = 1.0f;
for (i = Ns; n < start_n; n++, i--)
window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ns));
for (; n < end_n; n++)
window[n] = 0.0f;
for (i = 1; n < end_n+Ne; n++, i++)
window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
for (; n < L - (Ne); n++)
window[n] = 1.0f;
for (i = Ne; n < L; n++, i--)
window[n] = (FLAC__real)(0.5f - 0.5f * cos(M_PI * i / Ne));
}
void FLAC__window_welch(FLAC__real *window, const FLAC__int32 L)
{
const FLAC__int32 N = L - 1;