aboutsummaryrefslogtreecommitdiff
path: root/src/vector.c
diff options
context:
space:
mode:
authorJamie Bullock <jamie@jamiebullock.com>2013-01-07 16:27:15 +0000
committerJamie Bullock <jamie@jamiebullock.com>2013-01-07 16:39:29 +0000
commit144e7f8668166ee1779ad304cc5ac94d8e525529 (patch)
tree089b2bbbcf15ee8bdde390a4d270e4812e7e2228 /src/vector.c
parent0f46938156dedf13032bdb1fc914a63d46bae558 (diff)
downloadLibXtract-144e7f8668166ee1779ad304cc5ac94d8e525529.tar.gz
LibXtract-144e7f8668166ee1779ad304cc5ac94d8e525529.tar.bz2
LibXtract-144e7f8668166ee1779ad304cc5ac94d8e525529.zip
added Ooura implementation to repository
Diffstat (limited to 'src/vector.c')
-rw-r--r--src/vector.c467
1 files changed, 249 insertions, 218 deletions
diff --git a/src/vector.c b/src/vector.c
index 9c29762..73e437f 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -1,5 +1,5 @@
/* libxtract feature extraction library
- *
+ *
* Copyright (C) 2006 Jamie Bullock
*
* This program is free software; you can redistribute it and/or modify
@@ -14,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
@@ -25,16 +25,19 @@
#include <string.h>
#include <stdlib.h>
+#include "fftsg.h"
+
#include "xtract/libxtract.h"
#include "xtract_macros_private.h"
#ifndef roundf
- float roundf(float f){
- if (f - (int)f >= 0.5)
- return (float)((int)f + 1);
- else
- return (float)((int)f);
- }
+float roundf(float f)
+{
+ if (f - (int)f >= 0.5)
+ return (float)((int)f + 1);
+ else
+ return (float)((int)f);
+}
#endif
#ifndef powf
@@ -53,185 +56,208 @@
#define fabsf fabs
#endif
-#ifdef XTRACT_FFT
-
-#include <fftw3.h>
#include "xtract_globals_private.h"
#include "xtract_macros_private.h"
-int xtract_spectrum(const float *data, const int N, const void *argv, float *result){
-
- float *input, *rfft, q, temp, max, NxN;
- size_t bytes;
- int n,
- m,
- M,
- vector,
- withDC,
- argc,
- normalise;
-
- vector = argc = withDC = normalise = 0;
-
- M = N >> 1;
- NxN = XTRACT_SQ(N);
-
- rfft = (float *)fftwf_malloc(N * sizeof(float));
- input = (float *)malloc(bytes = N * sizeof(float));
- input = memcpy(input, data, bytes);
+int xtract_spectrum(const float *data, const int N, const void *argv, float *result)
+{
+
+ int vector = 0;
+ int withDC = 0;
+ int normalise = 0;
+ float q = 0.f;
+ float temp = 0.f;
+ float max = 0.f;
+ float NxN = XTRACT_SQ(N);
+ float *marker = NULL;
+ size_t bytes = N * sizeof(double);
+ double *rfft = NULL;
+ unsigned int n = 0;
+ unsigned int m = 0;
+ unsigned int nx2 = 0;
+ unsigned int M = N >> 1;
+
+ rfft = (double *)malloc(bytes);
+ //memcpy(rfft, data, bytes);
+
+ for(n = 0; n < N; ++n){
+ rfft[n] = (double)data[n];
+ }
q = *(float *)argv;
vector = (int)*((float *)argv+1);
withDC = (int)*((float *)argv+2);
normalise = (int)*((float *)argv+3);
- temp = 0.f;
- max = 0.f;
-
XTRACT_CHECK_q;
- if(fft_plans.spectrum_plan == NULL){
- fprintf(stderr,
- "libxtract: Error: xtract_spectrum() has uninitialised plan\n");
+ if(!ooura_data_spectrum.initialised)
+ {
+ fprintf(stderr,
+ "libxtract: error: xtract_spectrum() failed, "
+ "fft data unitialised.\n");
return XTRACT_NO_RESULT;
}
- fftwf_execute_r2r(fft_plans.spectrum_plan, input, rfft);
+ /* ooura is in-place
+ * the output format seems to be
+ * a[0] - DC, a[1] - nyquist, a[2...N-1] - remaining bins
+ */
+ rdft(N, 1, rfft, ooura_data_spectrum.ooura_ip,
+ ooura_data_spectrum.ooura_w);
- switch(vector){
+ switch(vector)
+ {
case XTRACT_LOG_MAGNITUDE_SPECTRUM:
- for(n = 0, m = 0; m < M; ++n, ++m){
- if(!withDC && n == 0){
- ++n;
- }
- if ((temp = XTRACT_SQ(rfft[n]) +
- XTRACT_SQ(rfft[N - n])) > XTRACT_LOG_LIMIT)
- temp = logf(sqrtf(temp) / (float)N);
- else
- temp = XTRACT_LOG_LIMIT_DB;
-
- result[m] =
- /* Scaling */
- (temp + XTRACT_DB_SCALE_OFFSET) /
- XTRACT_DB_SCALE_OFFSET;
-
- XTRACT_SET_FREQUENCY;
- XTRACT_GET_MAX;
+ for(n = 0, m = 0; m < M; ++n, ++m)
+ {
+ if(!withDC && n == 0)
+ {
+ continue;
}
- break;
-
- case XTRACT_POWER_SPECTRUM:
- for(n = 0, m = 0; m < M; ++n, ++m){
- if(!withDC && n == 0){
- ++n;
- }
- result[m] = (XTRACT_SQ(rfft[n]) + XTRACT_SQ(rfft[N - n])) / NxN;
- XTRACT_SET_FREQUENCY;
- XTRACT_GET_MAX;
+ nx2 = n * 2;
+ temp = XTRACT_SQ(rfft[nx2]) + XTRACT_SQ(rfft[nx2+1]);
+ if (temp > XTRACT_LOG_LIMIT)
+ {
+ temp = logf(sqrtf(temp) / (float)N);
}
- break;
-
- case XTRACT_LOG_POWER_SPECTRUM:
- for(n = 0, m = 0; m < M; ++n, ++m){
- if(!withDC && n == 0){
- ++n;
- }
- if ((temp = XTRACT_SQ(rfft[n]) + XTRACT_SQ(rfft[N - n])) >
- XTRACT_LOG_LIMIT)
- temp = logf(temp / NxN);
- else
- temp = XTRACT_LOG_LIMIT_DB;
-
- result[m] = (temp + XTRACT_DB_SCALE_OFFSET) /
- XTRACT_DB_SCALE_OFFSET;
- XTRACT_SET_FREQUENCY;
- XTRACT_GET_MAX;
+ else
+ {
+ temp = XTRACT_LOG_LIMIT_DB;
}
- break;
+ result[m] =
+ /* Scaling */
+ (temp + XTRACT_DB_SCALE_OFFSET) /
+ XTRACT_DB_SCALE_OFFSET;
- default:
- /* MAGNITUDE_SPECTRUM */
- for(n = 0, m = 0; m < M; ++n, ++m){
- if(!withDC && n == 0){
- ++n;
- }
- result[m] = sqrtf(XTRACT_SQ(rfft[n]) +
- XTRACT_SQ(rfft[N - n])) / (float)N;
- XTRACT_SET_FREQUENCY;
- XTRACT_GET_MAX;
+ XTRACT_SET_FREQUENCY;
+ XTRACT_GET_MAX;
+ }
+ break;
+
+ case XTRACT_POWER_SPECTRUM:
+ for(n = 0, m = 0; m < M; ++n, ++m)
+ {
+ if(!withDC && n == 0)
+ {
+ ++n;
}
- break;
+ result[m] = (XTRACT_SQ(rfft[n]) + XTRACT_SQ(rfft[N - n])) / NxN;
+ XTRACT_SET_FREQUENCY;
+ XTRACT_GET_MAX;
+ }
+ break;
+
+ case XTRACT_LOG_POWER_SPECTRUM:
+ for(n = 0, m = 0; m < M; ++n, ++m)
+ {
+ if(!withDC && n == 0)
+ {
+ ++n;
+ }
+ if ((temp = XTRACT_SQ(rfft[n]) + XTRACT_SQ(rfft[N - n])) >
+ XTRACT_LOG_LIMIT)
+ temp = logf(temp / NxN);
+ else
+ temp = XTRACT_LOG_LIMIT_DB;
+
+ result[m] = (temp + XTRACT_DB_SCALE_OFFSET) /
+ XTRACT_DB_SCALE_OFFSET;
+ XTRACT_SET_FREQUENCY;
+ XTRACT_GET_MAX;
+ }
+ break;
+
+ default:
+ /* MAGNITUDE_SPECTRUM */
+ for(n = 0, m = 0; m < M; ++n, ++m)
+ {
+ marker = &result[m];
+
+ if(n==0 && !withDC) /* discard DC and keep Nyquist */
+ {
+ ++n;
+ marker = &result[M-1];
+ }
+ if(n==1 && withDC) /* discard Nyquist */
+ {
+ ++n;
+ }
+
+ *marker = (float)(sqrt(XTRACT_SQ(rfft[n*2]) +
+ XTRACT_SQ(rfft[n*2+1])) / (double)N);
+ XTRACT_SET_FREQUENCY;
+ XTRACT_GET_MAX;
+
+ }
+ break;
}
- if(normalise){
+ if(normalise)
+ {
for(n = 0; n < M; n++)
result[n] /= max;
}
- fftwf_free(rfft);
- free(input);
+ free(rfft);
return XTRACT_SUCCESS;
}
-int xtract_autocorrelation_fft(const float *data, const int N, const void *argv, float *result){
+int xtract_autocorrelation_fft(const float *data, const int N, const void *argv, float *result)
+{
- float *freq, *time;
- int n, M;
- //fftwf_plan plan;
+ double *rfft = NULL;
+ int n = 0;
+ int M = 0;
M = N << 1;
- freq = (float *)fftwf_malloc(M * sizeof(float));
/* Zero pad the input vector */
- time = (float *)calloc(M, sizeof(float));
- time = memcpy(time, data, N * sizeof(float));
-
- fftwf_execute_r2r(fft_plans.autocorrelation_fft_plan_1, time, freq);
- //plan = fftwf_plan_r2r_1d(M, time, freq, FFTW_R2HC, FFTW_ESTIMATE);
+ rfft = (double *)calloc(M, sizeof(double));
+ memcpy(rfft, data, N * sizeof(float));
- //fftwf_execute(plan);
+ rdft(M, 1, rfft, ooura_data_autocorrelation_fft.ooura_ip,
+ ooura_data_autocorrelation_fft.ooura_w);
- for(n = 1; n < N; n++){
- freq[n] = XTRACT_SQ(freq[n]) + XTRACT_SQ(freq[M - n]);
- freq[M - n] = 0.f;
+ for(n = 2; n < M; n++)
+ {
+ rfft[n*2] = XTRACT_SQ(rfft[n*2]) + XTRACT_SQ(rfft[n*2+1]);
+ rfft[n*2+1] = 0.f;
}
- freq[0] = XTRACT_SQ(freq[0]);
- freq[N] = XTRACT_SQ(freq[N]);
-
- //plan = fftwf_plan_r2r_1d(M, freq, time, FFTW_HC2R, FFTW_ESTIMATE);
-
- //fftwf_execute(plan);
+ rfft[0] = XTRACT_SQ(rfft[0]);
+ rfft[1] = XTRACT_SQ(rfft[1]);
- fftwf_execute_r2r(fft_plans.autocorrelation_fft_plan_2, freq, time);
+ rdft(M, -1, rfft, ooura_data_autocorrelation_fft.ooura_ip,
+ ooura_data_autocorrelation_fft.ooura_w);
/* Normalisation factor */
M = M * N;
for(n = 0; n < N; n++)
- result[n] = time[n] / (float)M;
- /* result[n] = time[n+1] / (float)M; */
+ result[n] = rfft[n] / (float)M;
- //fftwf_destroy_plan(plan);
- fftwf_free(freq);
- free(time);
+ free(rfft);
return XTRACT_SUCCESS;
}
-int xtract_mfcc(const float *data, const int N, const void *argv, float *result){
+int xtract_mfcc(const float *data, const int N, const void *argv, float *result)
+{
xtract_mel_filter *f;
int n, filter;
f = (xtract_mel_filter *)argv;
- for(filter = 0; filter < f->n_filters; filter++){
+ for(filter = 0; filter < f->n_filters; filter++)
+ {
result[filter] = 0.f;
- for(n = 0; n < N; n++){
+ for(n = 0; n < N; n++)
+ {
result[filter] += data[n] * f->filters[filter][n];
}
result[filter] = logf(result[filter] < XTRACT_LOG_LIMIT ? XTRACT_LOG_LIMIT : result[filter]);
@@ -242,53 +268,25 @@ int xtract_mfcc(const float *data, const int N, const void *argv, float *result)
return XTRACT_SUCCESS;
}
-int xtract_dct(const float *data, const int N, const void *argv, float *result){
+int xtract_dct(const float *data, const int N, const void *argv, float *result)
+{
- //fftwf_plan plan;
+ int n;
+ int m;
+ float *temp = calloc(N, sizeof(float));
- //plan =
- // fftwf_plan_r2r_1d(N, (float *) data, result, FFTW_REDFT00, FFTW_ESTIMATE);
-
- fftwf_execute_r2r(fft_plans.dct_plan, (float *)data, result);
- //fftwf_execute(plan);
- //fftwf_destroy_plan(plan);
-
- return XTRACT_SUCCESS;
-}
-
-#else
-
-int xtract_spectrum(const float *data, const int N, const void *argv, float *result){
-
- XTRACT_NEEDS_FFTW;
- return XTRACT_NO_RESULT;
-
-}
-
-int xtract_autocorrelation_fft(const float *data, const int N, const void *argv, float *result){
-
- XTRACT_NEEDS_FFTW;
- return XTRACT_NO_RESULT;
-
-}
-
-int xtract_mfcc(const float *data, const int N, const void *argv, float *result){
-
- XTRACT_NEEDS_FFTW;
- return XTRACT_NO_RESULT;
-
-}
-
-int xtract_dct(const float *data, const int N, const void *argv, float *result){
-
- XTRACT_NEEDS_FFTW;
- return XTRACT_NO_RESULT;
+ for (n = 0; n < N; ++n)
+ {
+ for(m = 1; m <= N; ++m) {
+ temp[n] += data[m - 1] * cos(M_PI * (n / (float)N) * (m - 0.5));
+ }
+ }
+ return XTRACT_SUCCESS;
}
-#endif
-
-int xtract_autocorrelation(const float *data, const int N, const void *argv, float *result){
+int xtract_autocorrelation(const float *data, const int N, const void *argv, float *result)
+{
/* Naive time domain implementation */
@@ -296,9 +294,11 @@ int xtract_autocorrelation(const float *data, const int N, const void *argv, flo
float corr;
- while(n--){
+ while(n--)
+ {
corr = 0;
- for(i = 0; i < N - n; i++){
+ for(i = 0; i < N - n; i++)
+ {
corr += data[i] * data[i + n];
}
result[n] = corr / N;
@@ -307,15 +307,18 @@ int xtract_autocorrelation(const float *data, const int N, const void *argv, flo
return XTRACT_SUCCESS;
}
-int xtract_amdf(const float *data, const int N, const void *argv, float *result){
+int xtract_amdf(const float *data, const int N, const void *argv, float *result)
+{
int n = N, i;
float md, temp;
- while(n--){
+ while(n--)
+ {
md = 0.f;
- for(i = 0; i < N - n; i++){
+ for(i = 0; i < N - n; i++)
+ {
temp = data[i] - data[i + n];
temp = (temp < 0 ? -temp : temp);
md += temp;
@@ -326,15 +329,18 @@ int xtract_amdf(const float *data, const int N, const void *argv, float *result)
return XTRACT_SUCCESS;
}
-int xtract_asdf(const float *data, const int N, const void *argv, float *result){
+int xtract_asdf(const float *data, const int N, const void *argv, float *result)
+{
int n = N, i;
float sd;
- while(n--){
+ while(n--)
+ {
sd = 0.f;
- for(i = 0; i < N - n; i++){
+ for(i = 0; i < N - n; i++)
+ {
/*sd = 1;*/
sd += XTRACT_SQ(data[i] - data[i + n]);
}
@@ -344,13 +350,15 @@ int xtract_asdf(const float *data, const int N, const void *argv, float *result)
return XTRACT_SUCCESS;
}
-int xtract_bark_coefficients(const float *data, const int N, const void *argv, float *result){
+int xtract_bark_coefficients(const float *data, const int N, const void *argv, float *result)
+{
int *limits, band, n;
limits = (int *)argv;
- for(band = 0; band < XTRACT_BARK_BANDS - 1; band++){
+ for(band = 0; band < XTRACT_BARK_BANDS - 1; band++)
+ {
result[band] = 0.f;
for(n = limits[band]; n < limits[band + 1]; n++)
result[band] += data[n];
@@ -359,7 +367,8 @@ int xtract_bark_coefficients(const float *data, const int N, const void *argv, f
return XTRACT_SUCCESS;
}
-int xtract_peak_spectrum(const float *data, const int N, const void *argv, float *result){
+int xtract_peak_spectrum(const float *data, const int N, const void *argv, float *result)
+{
float threshold, max, y, y2, y3, p, q, *input = NULL;
size_t bytes;
@@ -367,14 +376,16 @@ int xtract_peak_spectrum(const float *data, const int N, const void *argv, float
threshold = max = y = y2 = y3 = p = q = 0.f;
- if(argv != NULL){
+ if(argv != NULL)
+ {
q = ((float *)argv)[0];
threshold = ((float *)argv)[1];
}
else
rv = XTRACT_BAD_ARGV;
- if(threshold < 0 || threshold > 100){
+ if(threshold < 0 || threshold > 100)
+ {
threshold = 0;
rv = XTRACT_BAD_ARGV;
}
@@ -398,32 +409,38 @@ int xtract_peak_spectrum(const float *data, const int N, const void *argv, float
result[0] = 0;
result[N] = 0;
- for(n = 1; n < N; n++){
- if(input[n] >= threshold){
- if(input[n] > input[n - 1] && n + 1 < N && input[n] > input[n + 1]){
- result[N + n] = q * (n + (p = .5 * ((y = input[n-1]) -
- (y3 = input[n+1])) / (input[n - 1] - 2 *
- (y2 = input[n]) + input[n + 1])));
+ for(n = 1; n < N; n++)
+ {
+ if(input[n] >= threshold)
+ {
+ if(input[n] > input[n - 1] && n + 1 < N && input[n] > input[n + 1])
+ {
+ result[N + n] = q * (n + (p = .5 * ((y = input[n-1]) -
+ (y3 = input[n+1])) / (input[n - 1] - 2 *
+ (y2 = input[n]) + input[n + 1])));
result[n] = y2 - .25 * (y - y3) * p;
}
- else{
+ else
+ {
result[n] = 0;
result[N + n] = 0;
}
}
- else{
+ else
+ {
result[n] = 0;
result[N + n] = 0;
}
- }
+ }
free(input);
return (rv ? rv : XTRACT_SUCCESS);
}
-int xtract_harmonic_spectrum(const float *data, const int N, const void *argv, float *result){
+int xtract_harmonic_spectrum(const float *data, const int N, const void *argv, float *result)
+{
- int n = (N >> 1), M = n;
+ int n = (N >> 1), M = n;
const float *freqs, *amps;
float f0, threshold, ratio, nearest, distance;
@@ -435,14 +452,17 @@ int xtract_harmonic_spectrum(const float *data, const int N, const void *argv, f
ratio = nearest = distance = 0.f;
- while(n--){
- if(freqs[n]){
+ while(n--)
+ {
+ if(freqs[n])
+ {
ratio = freqs[n] / f0;
nearest = roundf(ratio);
distance = fabs(nearest - ratio);
if(distance > threshold)
result[n] = result[M + n] = 0.f;
- else {
+ else
+ {
result[n] = amps[n];
result[M + n] = freqs[n];
}
@@ -453,14 +473,15 @@ int xtract_harmonic_spectrum(const float *data, const int N, const void *argv, f
return XTRACT_SUCCESS;
}
-int xtract_lpc(const float *data, const int N, const void *argv, float *result){
+int xtract_lpc(const float *data, const int N, const void *argv, float *result)
+{
int i, j, k, M, L;
- float r = 0.f,
+ float r = 0.f,
error = 0.f;
float *ref = NULL,
- *lpc = NULL ;
+ *lpc = NULL ;
error = data[0];
k = N; /* The length of *data */
@@ -469,24 +490,27 @@ int xtract_lpc(const float *data, const int N, const void *argv, float *result){
ref = result;
lpc = result+L;
- if(error == 0.0){
+ if(error == 0.0)
+ {
memset(result, 0, M * sizeof(float));
return XTRACT_NO_RESULT;
}
memset(result, 0, M * sizeof(float));
- for (i = 0; i < L; i++) {
+ for (i = 0; i < L; i++)
+ {
/* Sum up this iteration's reflection coefficient. */
r = -data[i + 1];
- for (j = 0; j < i; j++)
+ for (j = 0; j < i; j++)
r -= lpc[j] * data[i - j];
ref[i] = r /= error;
/* Update LPC coefficients and total error. */
lpc[i] = r;
- for (j = 0; j < i / 2; j++) {
+ for (j = 0; j < i / 2; j++)
+ {
float tmp = lpc[j];
lpc[j] = r * lpc[i - 1 - j];
lpc[i - 1 - j] += r * tmp;
@@ -499,7 +523,8 @@ int xtract_lpc(const float *data, const int N, const void *argv, float *result){
return XTRACT_SUCCESS;
}
-int xtract_lpcc(const float *data, const int N, const void *argv, float *result){
+int xtract_lpcc(const float *data, const int N, const void *argv, float *result)
+{
/* Given N lpc coefficients extract an LPC cepstrum of size argv[0] */
/* Based on an an algorithm by rabiner and Juang */
@@ -507,7 +532,7 @@ int xtract_lpcc(const float *data, const int N, const void *argv, float *result)
int n, k;
float sum;
int order = N - 1; /* Eventually change this to Q = 3/2 p as suggested in Rabiner */
- int cep_length;
+ int cep_length;
if(argv == NULL)
cep_length = N - 1; /* FIX: if we're going to have default values, they should come from the descriptor */
@@ -517,7 +542,8 @@ int xtract_lpcc(const float *data, const int N, const void *argv, float *result)
memset(result, 0, cep_length * sizeof(float));
- for (n = 1; n <= order && n <= cep_length; n++){
+ for (n = 1; n <= order && n <= cep_length; n++)
+ {
sum = 0.f;
for (k = 1; k < n; k++)
sum += k * result[k-1] * data[n - k];
@@ -525,7 +551,8 @@ int xtract_lpcc(const float *data, const int N, const void *argv, float *result)
}
/* be wary of these interpolated values */
- for(n = order + 1; n <= cep_length; n++){
+ for(n = order + 1; n <= cep_length; n++)
+ {
sum = 0.f;
for (k = n - (order - 1); k < n; k++)
sum += k * result[k-1] * data[n - k];
@@ -539,7 +566,8 @@ int xtract_lpcc(const float *data, const int N, const void *argv, float *result)
// return XTRACT_SUCCESS;
//}
-int xtract_subbands(const float *data, const int N, const void *argv, float *result){
+int xtract_subbands(const float *data, const int N, const void *argv, float *result)
+{
int n, bw, xtract_func, nbands, scale, start, lower, *argi, rv;
@@ -558,10 +586,12 @@ int xtract_subbands(const float *data, const int N, const void *argv, float *res
lower = start;
rv = XTRACT_SUCCESS;
- for(n = 0; n < nbands; n++){
+ for(n = 0; n < nbands; n++)
+ {
/* Bounds sanity check */
- if(lower >= N || lower + bw >= N){
+ if(lower >= N || lower + bw >= N)
+ {
// printf("n: %d\n", n);
result[n] = 0.f;
continue;
@@ -572,14 +602,15 @@ int xtract_subbands(const float *data, const int N, const void *argv, float *res
if(rv != XTRACT_SUCCESS)
return rv;
- switch(scale){
- case XTRACT_OCTAVE_SUBBANDS:
- lower += bw;
- bw = lower;
- break;
- case XTRACT_LINEAR_SUBBANDS:
- lower += bw;
- break;
+ switch(scale)
+ {
+ case XTRACT_OCTAVE_SUBBANDS:
+ lower += bw;
+ bw = lower;
+ break;
+ case XTRACT_LINEAR_SUBBANDS:
+ lower += bw;
+ break;
}
}