Add speech frontend.

PiperOrigin-RevId: 217171519
This commit is contained in:
Jian Li 2018-10-15 10:59:37 -07:00 committed by TensorFlower Gardener
parent ec16f981be
commit 333c4ff556
59 changed files with 3586 additions and 0 deletions

View File

@ -0,0 +1,188 @@
# Library for generating feature vectors from audio data
package(
default_visibility = ["//visibility:private"],
)
licenses(["notice"]) # Apache 2.0
cc_library(
name = "bits",
hdrs = ["bits.h"],
)
cc_library(
name = "fft",
srcs = [
"fft.c",
"fft_util.c",
],
hdrs = [
"fft.h",
"fft_util.h",
],
deps = ["@kissfft//:kiss_fftr_16"],
)
cc_library(
name = "filterbank",
srcs = [
"filterbank.c",
"filterbank_util.c",
],
hdrs = [
"filterbank.h",
"filterbank_util.h",
],
deps = [
":bits",
":fft",
],
)
cc_library(
name = "frontend",
srcs = [
"frontend.c",
"frontend_util.c",
],
hdrs = [
"frontend.h",
"frontend_util.h",
],
deps = [
":bits",
":fft",
":filterbank",
":log_scale",
":noise_reduction",
":pcan_gain_control",
":window",
],
)
cc_library(
name = "log_scale",
srcs = [
"log_lut.c",
"log_scale.c",
"log_scale_util.c",
],
hdrs = [
"log_lut.h",
"log_scale.h",
"log_scale_util.h",
],
deps = [
":bits",
],
)
cc_library(
name = "noise_reduction",
srcs = [
"noise_reduction.c",
"noise_reduction_util.c",
],
hdrs = [
"noise_reduction.h",
"noise_reduction_util.h",
],
)
cc_library(
name = "pcan_gain_control",
srcs = [
"pcan_gain_control.c",
"pcan_gain_control_util.c",
],
hdrs = [
"pcan_gain_control.h",
"pcan_gain_control_util.h",
],
deps = [
":bits",
],
)
cc_library(
name = "window",
srcs = [
"window.c",
"window_util.c",
],
hdrs = [
"window.h",
"window_util.h",
],
)
cc_test(
name = "fft_test",
size = "small",
srcs = ["fft_test.cc"],
deps = [
":fft",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "filterbank_test",
size = "small",
srcs = ["filterbank_test.cc"],
deps = [
":filterbank",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "frontend_test",
size = "small",
srcs = ["frontend_test.cc"],
deps = [
":frontend",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "log_scale_test",
size = "small",
srcs = ["log_scale_test.cc"],
deps = [
":log_scale",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "noise_reduction_test",
size = "small",
srcs = ["noise_reduction_test.cc"],
deps = [
":noise_reduction",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "pcan_gain_control_test",
size = "small",
srcs = ["pcan_gain_control_test.cc"],
deps = [
":pcan_gain_control",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "window_test",
size = "small",
srcs = ["window_test.cc"],
deps = [
":window",
"@com_google_googletest//:gtest_main",
],
)

View File

@ -0,0 +1,9 @@
The binary frontend_main shows sample usage of the frontend, printing out
coefficients when it has processed enough data.
The binary frontend_memmap_main shows a sample usage of how to avoid all the
init code in your runtime, by first running "frontend_generate_memmap" to
create a header/source file that uses a baked in frontend state. This command
could be automated as part of your build process, or you can just use the output
directly.

View File

@ -0,0 +1,102 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_BITS_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_BITS_H_
#ifdef __cplusplus
#include <cstdint>
extern "C" {
#endif
static inline int CountLeadingZeros32Slow(uint64_t n) {
int zeroes = 28;
if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4;
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
}
static inline int CountLeadingZeros32(uint32_t n) {
#if defined(_MSC_VER)
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse(&result, n)) {
return 31 - result;
}
return 32;
#elif defined(__GNUC__)
// Handle 0 as a special case because __builtin_clz(0) is undefined.
if (n == 0) {
return 32;
}
return __builtin_clz(n);
#else
return CountLeadingZeros32Slow(n);
#endif
}
static inline int MostSignificantBit32(uint32_t n) {
return 32 - CountLeadingZeros32(n);
}
static inline int CountLeadingZeros64Slow(uint64_t n) {
int zeroes = 60;
if (n >> 32) zeroes -= 32, n >>= 32;
if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4;
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
}
static inline int CountLeadingZeros64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64)
// MSVC does not have __buitin_clzll. Use _BitScanReverse64.
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse64(&result, n)) {
return 63 - result;
}
return 64;
#elif defined(_MSC_VER)
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
unsigned long result = 0; // NOLINT(runtime/int)
if ((n >> 32) && _BitScanReverse(&result, n >> 32)) {
return 31 - result;
}
if (_BitScanReverse(&result, n)) {
return 63 - result;
}
return 64;
#elif defined(__GNUC__)
// Handle 0 as a special case because __builtin_clzll(0) is undefined.
if (n == 0) {
return 64;
}
return __builtin_clzll(n);
#else
return CountLeadingZeros64Slow(n);
#endif
}
static inline int MostSignificantBit64(uint64_t n) {
return 64 - CountLeadingZeros64(n);
}
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_BITS_H_

View File

@ -0,0 +1,54 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft.h"
#include <string.h>
#define FIXED_POINT 16
#include "kiss_fft.h"
// Internal test dependency placeholder1
// Internal test dependency placeholder2
#include "tools/kiss_fftr.h"
// Internal test dependency placeholder3
void FftCompute(struct FftState* state, const int16_t* input,
int input_scale_shift) {
const size_t input_size = state->input_size;
const size_t fft_size = state->fft_size;
int16_t* fft_input = state->input;
// First, scale the input by the given shift.
int i;
for (i = 0; i < input_size; ++i) {
*fft_input++ = (*input++) << input_scale_shift;
}
// Zero out whatever else remains in the top part of the input.
for (; i < fft_size; ++i) {
*fft_input++ = 0;
}
// Apply the FFT.
kiss_fftr((const kiss_fftr_cfg)state->scratch, state->input,
(kiss_fft_cpx*)state->output);
}
void FftInit(struct FftState* state) {
// All the initialization is done in FftPopulateState()
}
void FftReset(struct FftState* state) {
memset(state->input, 0, state->fft_size * sizeof(*state->input));
memset(state->output, 0, (state->fft_size / 2 + 1) * sizeof(*state->output));
}

View File

@ -0,0 +1,50 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_H_
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
struct complex_int16_t {
int16_t real;
int16_t imag;
};
struct FftState {
int16_t* input;
struct complex_int16_t* output;
size_t fft_size;
size_t input_size;
void* scratch;
size_t scratch_size;
};
void FftCompute(struct FftState* state, const int16_t* input,
int input_scale_shift);
void FftInit(struct FftState* state);
void FftReset(struct FftState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_H_

View File

@ -0,0 +1,33 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft_io.h"
void FftWriteMemmapPreamble(FILE* fp, const struct FftState* state) {
fprintf(fp, "static int16_t fft_input[%zu];\n", state->fft_size);
fprintf(fp, "static struct complex_int16_t fft_output[%zu];\n",
state->fft_size / 2 + 1);
fprintf(fp, "static char fft_scratch[%zu];\n", state->scratch_size);
fprintf(fp, "\n");
}
void FftWriteMemmap(FILE* fp, const struct FftState* state,
const char* variable) {
fprintf(fp, "%s->input = fft_input;\n", variable);
fprintf(fp, "%s->output = fft_output;\n", variable);
fprintf(fp, "%s->fft_size = %zu;\n", variable, state->fft_size);
fprintf(fp, "%s->input_size = %zu;\n", variable, state->input_size);
fprintf(fp, "%s->scratch = fft_scratch;\n", variable);
fprintf(fp, "%s->scratch_size = %zu;\n", variable, state->scratch_size);
}

View File

@ -0,0 +1,34 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_IO_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_IO_H_
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft.h"
#ifdef __cplusplus
extern "C" {
#endif
void FftWriteMemmapPreamble(FILE* fp, const struct FftState* state);
void FftWriteMemmap(FILE* fp, const struct FftState* state,
const char* variable);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_IO_H_

View File

@ -0,0 +1,49 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
const int16_t kFakeWindow[] = {
0, 1151, 0, -5944, 0, 13311, 0, -21448, 0, 28327, 0, -32256, 0, 32255,
0, -28328, 0, 21447, 0, -13312, 0, 5943, 0, -1152, 0};
const int kScaleShift = 0;
TEST(FftTest, CheckOutputValues) {
struct FftState state;
ASSERT_TRUE(
FftPopulateState(&state, sizeof(kFakeWindow) / sizeof(kFakeWindow[0])));
FftInit(&state);
FftCompute(&state, kFakeWindow, kScaleShift);
const struct complex_int16_t expected[] = {
{0, 0}, {-10, 9}, {-20, 0}, {-9, -10}, {0, 25}, {-119, 119},
{-887, 0}, {3000, 3000}, {0, -6401}, {-3000, 3000}, {886, 0}, {118, 119},
{0, 25}, {9, -10}, {19, 0}, {9, 9}, {0, 0}};
ASSERT_EQ(state.fft_size / 2 + 1, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i <= state.fft_size / 2; ++i) {
EXPECT_EQ(state.output[i].real, expected[i].real);
EXPECT_EQ(state.output[i].imag, expected[i].imag);
}
FftFreeStateContents(&state);
}
} // namespace

View File

@ -0,0 +1,71 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft_util.h"
#include <stdio.h>
#define FIXED_POINT 16
#include "kiss_fft.h"
#include "tools/kiss_fftr.h"
int FftPopulateState(struct FftState* state, size_t input_size) {
state->input_size = input_size;
state->fft_size = 1;
while (state->fft_size < state->input_size) {
state->fft_size <<= 1;
}
state->input = malloc(state->fft_size * sizeof(*state->input));
if (state->input == NULL) {
fprintf(stderr, "Failed to alloc fft input buffer\n");
return 0;
}
state->output =
malloc((state->fft_size / 2 + 1) * sizeof(*state->output) * 2);
if (state->output == NULL) {
fprintf(stderr, "Failed to alloc fft output buffer\n");
return 0;
}
// Ask kissfft how much memory it wants.
size_t scratch_size = 0;
kiss_fftr_cfg kfft_cfg =
kiss_fftr_alloc(state->fft_size, 0, NULL, &scratch_size);
if (kfft_cfg != NULL) {
fprintf(stderr, "Kiss memory sizing failed.\n");
return 0;
}
state->scratch = malloc(scratch_size);
if (state->scratch == NULL) {
fprintf(stderr, "Failed to alloc fft scratch buffer\n");
return 0;
}
state->scratch_size = scratch_size;
// Let kissfft configure the scratch space we just allocated
kfft_cfg = kiss_fftr_alloc(state->fft_size, 0, state->scratch, &scratch_size);
if (kfft_cfg != state->scratch) {
fprintf(stderr, "Kiss memory preallocation strategy failed.\n");
return 0;
}
return 1;
}
void FftFreeStateContents(struct FftState* state) {
free(state->input);
free(state->output);
free(state->scratch);
}

View File

@ -0,0 +1,34 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_UTIL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_UTIL_H_
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft.h"
#ifdef __cplusplus
extern "C" {
#endif
// Prepares and FFT for the given input size.
int FftPopulateState(struct FftState* state, size_t input_size);
// Frees any allocated buffers.
void FftFreeStateContents(struct FftState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FFT_UTIL_H_

View File

@ -0,0 +1,134 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank.h"
#include <string.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/bits.h"
void FilterbankConvertFftComplexToEnergy(struct FilterbankState* state,
struct complex_int16_t* fft_output,
int32_t* energy) {
const int end_index = state->end_index;
int i;
energy += state->start_index;
fft_output += state->start_index;
for (i = state->start_index; i < end_index; ++i) {
const int32_t real = fft_output->real;
const int32_t imag = fft_output->imag;
fft_output++;
const uint32_t mag_squared = (real * real) + (imag * imag);
*energy++ = mag_squared;
}
}
void FilterbankAccumulateChannels(struct FilterbankState* state,
const int32_t* energy) {
uint64_t* work = state->work;
uint64_t weight_accumulator = 0;
uint64_t unweight_accumulator = 0;
const int16_t* channel_frequency_starts = state->channel_frequency_starts;
const int16_t* channel_weight_starts = state->channel_weight_starts;
const int16_t* channel_widths = state->channel_widths;
int num_channels_plus_1 = state->num_channels + 1;
int i;
for (i = 0; i < num_channels_plus_1; ++i) {
const int32_t* magnitudes = energy + *channel_frequency_starts++;
const int16_t* weights = state->weights + *channel_weight_starts;
const int16_t* unweights = state->unweights + *channel_weight_starts++;
const int width = *channel_widths++;
int j;
for (j = 0; j < width; ++j) {
weight_accumulator += *weights++ * ((uint64_t) *magnitudes);
unweight_accumulator += *unweights++ * ((uint64_t) *magnitudes);
++magnitudes;
}
*work++ = weight_accumulator;
weight_accumulator = unweight_accumulator;
unweight_accumulator = 0;
}
}
static uint16_t Sqrt32(uint32_t num) {
if (num == 0) {
return 0;
}
uint32_t res = 0;
int max_bit_number = 32 - MostSignificantBit32(num);
max_bit_number |= 1;
uint32_t bit = 1U << (31 - max_bit_number);
int iterations = (31 - max_bit_number) / 2 + 1;
while (iterations--) {
if (num >= res + bit) {
num -= res + bit;
res = (res >> 1U) + bit;
} else {
res >>= 1U;
}
bit >>= 2U;
}
// Do rounding - if we have the bits.
if (num > res && res != 0xFFFF) {
++res;
}
return res;
}
static uint32_t Sqrt64(uint64_t num) {
// Take a shortcut and just use 32 bit operations if the upper word is all
// clear. This will cause a slight off by one issue for numbers close to 2^32,
// but it probably isn't going to matter (and gives us a big performance win).
if ((num >> 32) == 0) {
return Sqrt32((uint32_t) num);
}
uint64_t res = 0;
int max_bit_number = 64 - MostSignificantBit64(num);
max_bit_number |= 1;
uint64_t bit = 1ULL << (63 - max_bit_number);
int iterations = (63 - max_bit_number) / 2 + 1;
while (iterations--) {
if (num >= res + bit) {
num -= res + bit;
res = (res >> 1U) + bit;
} else {
res >>= 1U;
}
bit >>= 2U;
}
// Do rounding - if we have the bits.
if (num > res && res != 0xFFFFFFFFLL) {
++res;
}
return res;
}
uint32_t* FilterbankSqrt(struct FilterbankState* state, int scale_down_shift) {
const int num_channels = state->num_channels;
const int64_t* work = state->work + 1;
// Reuse the work buffer since we're fine clobbering it at this point to hold
// the output.
uint32_t* output = (uint32_t*) state->work;
int i;
for (i = 0; i < num_channels; ++i) {
*output++ = Sqrt64(*work++) >> scale_down_shift;
}
return (uint32_t*) state->work;
}
void FilterbankReset(struct FilterbankState* state) {
memset(state->work, 0, (state->num_channels + 1) * sizeof(*state->work));
}

View File

@ -0,0 +1,63 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_H_
#include <stdint.h>
#include <stdlib.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft.h"
#define kFilterbankBits 12
#ifdef __cplusplus
extern "C" {
#endif
struct FilterbankState {
int num_channels;
int start_index;
int end_index;
int16_t* channel_frequency_starts;
int16_t* channel_weight_starts;
int16_t* channel_widths;
int16_t* weights;
int16_t* unweights;
uint64_t* work;
};
// Converts the relevant complex values of an FFT output into energy (the
// square magnitude).
void FilterbankConvertFftComplexToEnergy(struct FilterbankState* state,
struct complex_int16_t* fft_output,
int32_t* energy);
// Computes the mel-scale filterbank on the given energy array. Output is cached
// internally - to fetch it, you need to call FilterbankSqrt.
void FilterbankAccumulateChannels(struct FilterbankState* state,
const int32_t* energy);
// Applies an integer square root to the 64 bit intermediate values of the
// filterbank, and returns a pointer to them. Memory will be invalidated the
// next time FilterbankAccumulateChannels is called.
uint32_t* FilterbankSqrt(struct FilterbankState* state, int scale_down_shift);
void FilterbankReset(struct FilterbankState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_H_

View File

@ -0,0 +1,66 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank_io.h"
static void PrintArray(FILE* fp, const char* name, const int16_t* values,
size_t size) {
fprintf(fp, "static int16_t filterbank_%s[] = {", name);
for (int i = 0; i < size; ++i) {
fprintf(fp, "%d", values[i]);
if (i < size - 1) {
fprintf(fp, ", ");
}
}
fprintf(fp, "};\n");
}
void FilterbankWriteMemmapPreamble(FILE* fp,
const struct FilterbankState* state) {
const int num_channels_plus_1 = state->num_channels + 1;
PrintArray(fp, "channel_frequency_starts", state->channel_frequency_starts,
num_channels_plus_1);
PrintArray(fp, "channel_weight_starts", state->channel_weight_starts,
num_channels_plus_1);
PrintArray(fp, "channel_widths", state->channel_widths, num_channels_plus_1);
int num_weights = 0;
int i;
for (i = 0; i < num_channels_plus_1; ++i) {
num_weights += state->channel_widths[i];
}
PrintArray(fp, "weights", state->weights, num_weights);
PrintArray(fp, "unweights", state->unweights, num_weights);
fprintf(fp, "static uint64_t filterbank_work[%d];\n", num_channels_plus_1);
fprintf(fp, "\n");
}
void FilterbankWriteMemmap(FILE* fp, const struct FilterbankState* state,
const char* variable) {
fprintf(fp, "%s->num_channels = %d;\n", variable, state->num_channels);
fprintf(fp, "%s->start_index = %d;\n", variable, state->start_index);
fprintf(fp, "%s->end_index = %d;\n", variable, state->end_index);
fprintf(
fp,
"%s->channel_frequency_starts = filterbank_channel_frequency_starts;\n",
variable);
fprintf(fp, "%s->channel_weight_starts = filterbank_channel_weight_starts;\n",
variable);
fprintf(fp, "%s->channel_widths = filterbank_channel_widths;\n", variable);
fprintf(fp, "%s->weights = filterbank_weights;\n", variable);
fprintf(fp, "%s->unweights = filterbank_unweights;\n", variable);
fprintf(fp, "%s->work = filterbank_work;\n", variable);
}

View File

@ -0,0 +1,35 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_IO_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_IO_H_
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank.h"
#ifdef __cplusplus
extern "C" {
#endif
void FilterbankWriteMemmapPreamble(FILE* fp,
const struct FilterbankState* state);
void FilterbankWriteMemmap(FILE* fp, const struct FilterbankState* state,
const char* variable);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_IO_H_

View File

@ -0,0 +1,194 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank_util.h"
#include <cstring>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
const int kSampleRate = 1000;
const int kSpectrumSize = 17;
const int kStartIndex = 1;
const int kEndIndex = 15;
const int32_t kEnergy[] = {-1, 181, 400, 181, 625, 28322,
786769, 18000000, 40972801, 18000000, 784996, 28085,
625, 181, 361, -1, -1};
const uint64_t kWork[] = {1835887, 61162970173, 258694800000};
const int kScaleShift = 0;
// Test filterbank generation using scaled-down defaults.
class FilterbankTest : public ::testing::Test {
protected:
FilterbankTest() {
config_.num_channels = 2;
config_.lower_band_limit = 8.0;
config_.upper_band_limit = 450.0;
}
struct FilterbankConfig config_;
};
TEST_F(FilterbankTest, CheckStartIndex) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
EXPECT_EQ(state.start_index, kStartIndex);
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckEndIndex) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
EXPECT_EQ(state.end_index, kEndIndex);
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckChannelFrequencyStarts) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
const int16_t expected[] = {0, 4, 8};
ASSERT_EQ(state.num_channels + 1, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i <= state.num_channels; ++i) {
EXPECT_EQ(state.channel_frequency_starts[i], expected[i]);
}
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckChannelWeightStarts) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
const int16_t expected[] = {0, 8, 16};
ASSERT_EQ(state.num_channels + 1, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i <= state.num_channels; ++i) {
EXPECT_EQ(state.channel_weight_starts[i], expected[i]);
}
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckChannelWidths) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
const int16_t expected[] = {8, 8, 8};
ASSERT_EQ(state.num_channels + 1, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i <= state.num_channels; ++i) {
EXPECT_EQ(state.channel_widths[i], expected[i]);
}
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckWeights) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
const int16_t expected[] = {0, 3277, 2217, 1200, 222, 0, 0, 0,
0, 3376, 2468, 1591, 744, 0, 0, 0,
0, 4020, 3226, 2456, 1708, 983, 277, 0};
ASSERT_EQ(state.channel_weight_starts[state.num_channels] +
state.channel_widths[state.num_channels],
sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < sizeof(expected) / sizeof(expected[0]); ++i) {
EXPECT_EQ(state.weights[i], expected[i]);
}
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckUnweights) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
const int16_t expected[] = {0, 819, 1879, 2896, 3874, 0, 0, 0,
0, 720, 1628, 2505, 3352, 0, 0, 0,
0, 76, 870, 1640, 2388, 3113, 3819, 0};
ASSERT_EQ(state.channel_weight_starts[state.num_channels] +
state.channel_widths[state.num_channels],
sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < sizeof(expected) / sizeof(expected[0]); ++i) {
EXPECT_EQ(state.unweights[i], expected[i]);
}
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckConvertFftComplexToEnergy) {
struct FilterbankState state;
state.start_index = kStartIndex;
state.end_index = kEndIndex;
struct complex_int16_t fake_fft[] = {
{0, 0}, {-10, 9}, {-20, 0}, {-9, -10}, {0, 25}, {-119, 119},
{-887, 0}, {3000, 3000}, {0, -6401}, {-3000, 3000}, {886, 0}, {118, 119},
{0, 25}, {9, -10}, {19, 0}, {9, 9}, {0, 0}};
int32_t* energy = reinterpret_cast<int32_t*>(fake_fft);
FilterbankConvertFftComplexToEnergy(&state, fake_fft, energy);
for (int i = state.start_index; i < state.end_index; ++i) {
EXPECT_EQ(energy[i], kEnergy[i]);
}
}
TEST_F(FilterbankTest, CheckAccumulateChannels) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
FilterbankAccumulateChannels(&state, kEnergy);
ASSERT_EQ(state.num_channels + 1, sizeof(kWork) / sizeof(kWork[0]));
for (int i = 0; i <= state.num_channels; ++i) {
EXPECT_EQ(state.work[i], kWork[i]);
}
FilterbankFreeStateContents(&state);
}
TEST_F(FilterbankTest, CheckSqrt) {
struct FilterbankState state;
ASSERT_TRUE(
FilterbankPopulateState(&config_, &state, kSampleRate, kSpectrumSize));
std::memcpy(state.work, kWork, sizeof(kWork));
uint32_t* scaled_filterbank = FilterbankSqrt(&state, kScaleShift);
const uint32_t expected[] = {247311, 508620};
ASSERT_EQ(state.num_channels, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < state.num_channels; ++i) {
EXPECT_EQ(scaled_filterbank[i], expected[i]);
}
FilterbankFreeStateContents(&state);
}
} // namespace

View File

@ -0,0 +1,225 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank_util.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#define kFilterbankIndexAlignment 4
#define kFilterbankChannelBlockSize 4
void FilterbankFillConfigWithDefaults(struct FilterbankConfig* config) {
config->num_channels = 32;
config->lower_band_limit = 125.0f;
config->upper_band_limit = 7500.0f;
config->output_scale_shift = 7;
}
static float FreqToMel(float freq) {
return 1127.0 * log(1.0 + (freq / 700.0));
}
static void CalculateCenterFrequencies(const int num_channels,
const float lower_frequency_limit,
const float upper_frequency_limit,
float* center_frequencies) {
assert(lower_frequency_limit >= 0.0f);
assert(upper_frequency_limit > lower_frequency_limit);
const float mel_low = FreqToMel(lower_frequency_limit);
const float mel_hi = FreqToMel(upper_frequency_limit);
const float mel_span = mel_hi - mel_low;
const float mel_spacing = mel_span / ((float) num_channels);
int i;
for (i = 0; i < num_channels; ++i) {
center_frequencies[i] = mel_low + (mel_spacing * (i + 1));
}
}
static void QuantizeFilterbankWeights(const float float_weight,
int16_t* weight, int16_t* unweight) {
*weight = floor(float_weight * (1 << kFilterbankBits) + 0.5);
*unweight = floor((1.0 - float_weight) * (1 << kFilterbankBits) + 0.5);
}
int FilterbankPopulateState(const struct FilterbankConfig* config,
struct FilterbankState* state,
int sample_rate, int spectrum_size) {
state->num_channels = config->num_channels;
const int num_channels_plus_1 = config->num_channels + 1;
// How should we align things to index counts given the byte alignment?
const int index_alignment =
(kFilterbankIndexAlignment < sizeof(int16_t)
? 1
: kFilterbankIndexAlignment / sizeof(int16_t));
state->channel_frequency_starts =
malloc(num_channels_plus_1 * sizeof(*state->channel_frequency_starts));
state->channel_weight_starts =
malloc(num_channels_plus_1 * sizeof(*state->channel_weight_starts));
state->channel_widths =
malloc(num_channels_plus_1 * sizeof(*state->channel_widths));
state->work = malloc(num_channels_plus_1 * sizeof(*state->work));
float* center_mel_freqs =
malloc(num_channels_plus_1 * sizeof(*center_mel_freqs));
int16_t* actual_channel_starts =
malloc(num_channels_plus_1 * sizeof(*actual_channel_starts));
int16_t* actual_channel_widths =
malloc(num_channels_plus_1 * sizeof(*actual_channel_widths));
if (state->channel_frequency_starts == NULL ||
state->channel_weight_starts == NULL ||
state->channel_widths == NULL ||
center_mel_freqs == NULL ||
actual_channel_starts == NULL ||
actual_channel_widths == NULL) {
free(center_mel_freqs);
free(actual_channel_starts);
free(actual_channel_widths);
fprintf(stderr, "Failed to allocate channel buffers\n");
return 0;
}
CalculateCenterFrequencies(num_channels_plus_1, config->lower_band_limit,
config->upper_band_limit, center_mel_freqs);
// Always exclude DC.
const float hz_per_sbin = 0.5 * sample_rate / ((float) spectrum_size - 1);
state->start_index = 1.5 + config->lower_band_limit / hz_per_sbin;
state->end_index = 0; // Initialized to zero here, but actually set below.
// For each channel, we need to figure out what frequencies belong to it, and
// how much padding we need to add so that we can efficiently multiply the
// weights and unweights for accumulation. To simplify the multiplication
// logic, all channels will have some multiplication to do (even if there are
// no frequencies that accumulate to that channel) - they will be directed to
// a set of zero weights.
int chan_freq_index_start = state->start_index;
int weight_index_start = 0;
int needs_zeros = 0;
int chan;
for (chan = 0; chan < num_channels_plus_1; ++chan) {
// Keep jumping frequencies until we overshoot the bound on this channel.
int freq_index = chan_freq_index_start;
while (FreqToMel((freq_index) * hz_per_sbin) <= center_mel_freqs[chan]) {
++freq_index;
}
const int width = freq_index - chan_freq_index_start;
actual_channel_starts[chan] = chan_freq_index_start;
actual_channel_widths[chan] = width;
if (width == 0) {
// This channel doesn't actually get anything from the frequencies, it's
// always zero. We need then to insert some 'zero' weights into the
// output, and just redirect this channel to do a single multiplication at
// this point. For simplicity, the zeros are placed at the beginning of
// the weights arrays, so we have to go and update all the other
// weight_starts to reflect this shift (but only once).
state->channel_frequency_starts[chan] = 0;
state->channel_weight_starts[chan] = 0;
state->channel_widths[chan] = kFilterbankChannelBlockSize;
if (!needs_zeros) {
needs_zeros = 1;
int j;
for (j = 0; j < chan; ++j) {
state->channel_weight_starts[j] += kFilterbankChannelBlockSize;
}
weight_index_start += kFilterbankChannelBlockSize;
}
} else {
// How far back do we need to go to ensure that we have the proper
// alignment?
const int aligned_start =
(chan_freq_index_start / index_alignment) * index_alignment;
const int aligned_width =
(chan_freq_index_start - aligned_start + width);
const int padded_width =
(((aligned_width - 1) / kFilterbankChannelBlockSize) + 1) *
kFilterbankChannelBlockSize;
state->channel_frequency_starts[chan] = aligned_start;
state->channel_weight_starts[chan] = weight_index_start;
state->channel_widths[chan] = padded_width;
weight_index_start += padded_width;
}
chan_freq_index_start = freq_index;
}
// Allocate the two arrays to store the weights - weight_index_start contains
// the index of what would be the next set of weights that we would need to
// add, so that's how many weights we need to allocate.
state->weights = calloc(weight_index_start, sizeof(*state->weights));
state->unweights = calloc(weight_index_start, sizeof(*state->unweights));
// If the alloc failed, we also need to nuke the arrays.
if (state->weights == NULL || state->unweights == NULL) {
free(center_mel_freqs);
free(actual_channel_starts);
free(actual_channel_widths);
fprintf(stderr, "Failed to allocate weights or unweights\n");
return 0;
}
// Next pass, compute all the weights. Since everything has been memset to
// zero, we only need to fill in the weights that correspond to some frequency
// for a channel.
const float mel_low = FreqToMel(config->lower_band_limit);
for (chan = 0; chan < num_channels_plus_1; ++chan) {
int frequency = actual_channel_starts[chan];
const int num_frequencies = actual_channel_widths[chan];
const int frequency_offset =
frequency - state->channel_frequency_starts[chan];
const int weight_start = state->channel_weight_starts[chan];
const float denom_val = (chan == 0) ? mel_low : center_mel_freqs[chan - 1];
int j;
for (j = 0; j < num_frequencies; ++j, ++frequency) {
const float weight =
(center_mel_freqs[chan] - FreqToMel(frequency * hz_per_sbin)) /
(center_mel_freqs[chan] - denom_val);
// Make the float into an integer for the weights (and unweights).
const int weight_index = weight_start + frequency_offset + j;
QuantizeFilterbankWeights(weight, state->weights + weight_index,
state->unweights + weight_index);
}
if (frequency > state->end_index) {
state->end_index = frequency;
}
}
free(center_mel_freqs);
free(actual_channel_starts);
free(actual_channel_widths);
if (state->end_index >= spectrum_size) {
fprintf(stderr, "Filterbank end_index is above spectrum size.\n");
return 0;
}
return 1;
}
void FilterbankFreeStateContents(struct FilterbankState* state) {
free(state->channel_frequency_starts);
free(state->channel_weight_starts);
free(state->channel_widths);
free(state->weights);
free(state->unweights);
free(state->work);
}

View File

@ -0,0 +1,50 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_UTIL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_UTIL_H_
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank.h"
#ifdef __cplusplus
extern "C" {
#endif
struct FilterbankConfig {
// number of frequency channel buckets for filterbank
int num_channels;
// maximum frequency to include
float upper_band_limit;
// minimum frequency to include
float lower_band_limit;
// unused
int output_scale_shift;
};
// Fills the frontendConfig with "sane" defaults.
void FilterbankFillConfigWithDefaults(struct FilterbankConfig* config);
// Allocates any buffers.
int FilterbankPopulateState(const struct FilterbankConfig* config,
struct FilterbankState* state, int sample_rate,
int spectrum_size);
// Frees any allocated buffers.
void FilterbankFreeStateContents(struct FilterbankState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FILTERBANK_UTIL_H_

View File

@ -0,0 +1,72 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/bits.h"
struct FrontendOutput FrontendProcessSamples(struct FrontendState* state,
const int16_t* samples,
size_t num_samples,
size_t* num_samples_read) {
struct FrontendOutput output;
output.values = NULL;
output.size = 0;
// Try to apply the window - if it fails, return and wait for more data.
if (!WindowProcessSamples(&state->window, samples, num_samples,
num_samples_read)) {
return output;
}
// Apply the FFT to the window's output (and scale it so that the fixed point
// FFT can have as much resolution as possible).
int input_shift =
15 - MostSignificantBit32(state->window.max_abs_output_value);
FftCompute(&state->fft, state->window.output, input_shift);
// We can re-ruse the fft's output buffer to hold the energy.
int32_t* energy = (int32_t*) state->fft.output;
FilterbankConvertFftComplexToEnergy(&state->filterbank, state->fft.output,
energy);
FilterbankAccumulateChannels(&state->filterbank, energy);
uint32_t* scaled_filterbank = FilterbankSqrt(&state->filterbank, input_shift);
// Apply noise reduction.
NoiseReductionApply(&state->noise_reduction, scaled_filterbank);
if (state->pcan_gain_control.enable_pcan) {
PcanGainControlApply(&state->pcan_gain_control, scaled_filterbank);
}
// Apply the log and scale.
int correction_bits =
MostSignificantBit32(state->fft.fft_size) - 1 - (kFilterbankBits / 2);
uint16_t* logged_filterbank =
LogScaleApply(&state->log_scale, scaled_filterbank,
state->filterbank.num_channels, correction_bits);
output.size = state->filterbank.num_channels;
output.values = logged_filterbank;
return output;
}
void FrontendReset(struct FrontendState* state) {
WindowReset(&state->window);
FftReset(&state->fft);
FilterbankReset(&state->filterbank);
NoiseReductionReset(&state->noise_reduction);
}

View File

@ -0,0 +1,64 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_H_
#include <stdint.h>
#include <stdlib.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/pcan_gain_control.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window.h"
#ifdef __cplusplus
extern "C" {
#endif
struct FrontendState {
struct WindowState window;
struct FftState fft;
struct FilterbankState filterbank;
struct NoiseReductionState noise_reduction;
struct PcanGainControlState pcan_gain_control;
struct LogScaleState log_scale;
};
struct FrontendOutput {
const uint16_t* values;
size_t size;
};
// Main entry point to processing frontend samples. Updates num_samples_read to
// contain the number of samples that have been consumed from the input array.
// Returns a struct containing the generated output. If not enough samples were
// added to generate a feature vector, the returned size will be 0 and the
// values pointer will be NULL. Note that the output pointer will be invalidated
// as soon as FrontendProcessSamples is called again, so copy the contents
// elsewhere if you need to use them later.
struct FrontendOutput FrontendProcessSamples(struct FrontendState* state,
const int16_t* samples,
size_t num_samples,
size_t* num_samples_read);
void FrontendReset(struct FrontendState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_H_

View File

@ -0,0 +1,69 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend_io.h"
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft_io.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank_io.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale_io.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction_io.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window_io.h"
int WriteFrontendStateMemmap(const char* header, const char* source,
const struct FrontendState* state) {
// Write a header that just has our init function.
FILE* fp = fopen(header, "w");
if (!fp) {
fprintf(stderr, "Failed to open header '%s' for write\n", header);
return 0;
}
fprintf(fp, "#ifndef FRONTEND_STATE_MEMMAP_H_\n");
fprintf(fp, "#define FRONTEND_STATE_MEMMAP_H_\n");
fprintf(fp, "\n");
fprintf(fp, "#include \"frontend.h\"\n");
fprintf(fp, "\n");
fprintf(fp, "struct FrontendState* GetFrontendStateMemmap();\n");
fprintf(fp, "\n");
fprintf(fp, "#endif // FRONTEND_STATE_MEMMAP_H_\n");
fclose(fp);
// Write out the source file that actually has everything in it.
fp = fopen(source, "w");
if (!fp) {
fprintf(stderr, "Failed to open source '%s' for write\n", source);
return 0;
}
fprintf(fp, "#include \"%s\"\n", header);
fprintf(fp, "\n");
WindowWriteMemmapPreamble(fp, &state->window);
FftWriteMemmapPreamble(fp, &state->fft);
FilterbankWriteMemmapPreamble(fp, &state->filterbank);
NoiseReductionWriteMemmapPreamble(fp, &state->noise_reduction);
fprintf(fp, "static struct FrontendState state;\n");
fprintf(fp, "struct FrontendState* GetFrontendStateMemmap() {\n");
WindowWriteMemmap(fp, &state->window, " (&state.window)");
FftWriteMemmap(fp, &state->fft, " (&state.fft)");
FilterbankWriteMemmap(fp, &state->filterbank, " (&state.filterbank)");
NoiseReductionWriteMemmap(fp, &state->noise_reduction,
" (&state.noise_reduction)");
LogScaleWriteMemmap(fp, &state->log_scale, " (&state.log_scale)");
fprintf(fp, " FftInit(&state.fft);\n");
fprintf(fp, " FrontendReset(&state);\n");
fprintf(fp, " return &state;\n");
fprintf(fp, "}\n");
fclose(fp);
return 1;
}

View File

@ -0,0 +1,31 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_IO_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_IO_H_
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend.h"
#ifdef __cplusplus
extern "C" {
#endif
int WriteFrontendStateMemmap(const char* header, const char* source,
const struct FrontendState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_IO_H_

View File

@ -0,0 +1,70 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend_util.h"
int main(int argc, char** argv) {
struct FrontendConfig frontend_config;
FrontendFillConfigWithDefaults(&frontend_config);
char* filename = argv[1];
int sample_rate = 16000;
struct FrontendState frontend_state;
if (!FrontendPopulateState(&frontend_config, &frontend_state, sample_rate)) {
fprintf(stderr, "Failed to populate frontend state\n");
FrontendFreeStateContents(&frontend_state);
return 1;
}
FILE* fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s for read\n", filename);
return 1;
}
fseek(fp, 0L, SEEK_END);
size_t audio_file_size = ftell(fp) / sizeof(int16_t);
fseek(fp, 0L, SEEK_SET);
int16_t* audio_data = malloc(audio_file_size * sizeof(int16_t));
int16_t* original_audio_data = audio_data;
if (audio_file_size !=
fread(audio_data, sizeof(int16_t), audio_file_size, fp)) {
fprintf(stderr, "Failed to read in all audio data\n");
return 1;
}
while (audio_file_size > 0) {
size_t num_samples_read;
struct FrontendOutput output = FrontendProcessSamples(
&frontend_state, audio_data, audio_file_size, &num_samples_read);
audio_data += num_samples_read;
audio_file_size -= num_samples_read;
if (output.values != NULL) {
int i;
for (i = 0; i < output.size; ++i) {
printf("%d ", output.values[i]);
}
printf("\n");
}
}
FrontendFreeStateContents(&frontend_state);
free(original_audio_data);
return 0;
}

View File

@ -0,0 +1,47 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend_util.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend_io.h"
int main(int argc, char** argv) {
if (argc != 3) {
fprintf(stderr,
"%s requires exactly two parameters - the names of the header and "
"source files to save\n");
return 1;
}
struct FrontendConfig frontend_config;
FrontendFillConfigWithDefaults(&frontend_config);
int sample_rate = 16000;
struct FrontendState frontend_state;
if (!FrontendPopulateState(&frontend_config, &frontend_state, sample_rate)) {
fprintf(stderr, "Failed to populate frontend state\n");
FrontendFreeStateContents(&frontend_state);
return 1;
}
if (!WriteFrontendStateMemmap(argv[1], argv[2], &frontend_state)) {
fprintf(stderr, "Failed to write memmap\n");
FrontendFreeStateContents(&frontend_state);
return 1;
}
FrontendFreeStateContents(&frontend_state);
return 0;
}

View File

@ -0,0 +1,58 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend.h"
#include "memmap.h"
int main(int argc, char** argv) {
struct FrontendState* frontend_state = GetFrontendStateMemmap();
char* filename = argv[1];
FILE* fp = fopen(filename, "r");
if (fp == NULL) {
fprintf(stderr, "Failed to open %s for read\n", filename);
return 1;
}
fseek(fp, 0L, SEEK_END);
size_t audio_file_size = ftell(fp) / sizeof(int16_t);
fseek(fp, 0L, SEEK_SET);
int16_t* audio_data = malloc(audio_file_size * sizeof(int16_t));
int16_t* original_audio_data = audio_data;
if (audio_file_size !=
fread(audio_data, sizeof(int16_t), audio_file_size, fp)) {
fprintf(stderr, "Failed to read in all audio data\n");
return 1;
}
while (audio_file_size > 0) {
size_t num_samples_read;
struct FrontendOutput output = FrontendProcessSamples(
frontend_state, audio_data, audio_file_size, &num_samples_read);
audio_data += num_samples_read;
audio_file_size -= num_samples_read;
if (output.values != NULL) {
int i;
for (i = 0; i < output.size; ++i) {
printf("%d ", output.values[i]);
}
printf("\n");
}
}
free(original_audio_data);
return 0;
}

View File

@ -0,0 +1,120 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
const int kSampleRate = 1000;
const int kWindowSamples = 25;
const int kStepSamples = 10;
const int16_t kFakeAudioData[] = {
0, 32767, 0, -32768, 0, 32767, 0, -32768, 0, 32767, 0, -32768,
0, 32767, 0, -32768, 0, 32767, 0, -32768, 0, 32767, 0, -32768,
0, 32767, 0, -32768, 0, 32767, 0, -32768, 0, 32767, 0, -32768};
// Test end-to-end frontend behaviors.
class FrontendTest : public ::testing::Test {
protected:
FrontendTest() {
config_.window.size_ms = 25;
config_.window.step_size_ms = 10;
config_.noise_reduction.smoothing_bits = 10;
config_.filterbank.num_channels = 2;
config_.filterbank.lower_band_limit = 8.0;
config_.filterbank.upper_band_limit = 450.0;
config_.noise_reduction.smoothing_bits = 10;
config_.noise_reduction.even_smoothing = 0.025;
config_.noise_reduction.odd_smoothing = 0.06;
config_.noise_reduction.min_signal_remaining = 0.05;
config_.pcan_gain_control.enable_pcan = true;
config_.pcan_gain_control.strength = 0.95;
config_.pcan_gain_control.offset = 80.0;
config_.pcan_gain_control.gain_bits = 21;
config_.log_scale.enable_log = true;
config_.log_scale.scale_shift = 6;
}
struct FrontendConfig config_;
};
TEST_F(FrontendTest, CheckOutputValues) {
struct FrontendState state;
ASSERT_TRUE(FrontendPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
struct FrontendOutput output = FrontendProcessSamples(
&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]), &num_samples_read);
const uint16_t expected[] = {479, 425};
ASSERT_EQ(output.size, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < output.size; ++i) {
EXPECT_EQ(output.values[i], expected[i]);
}
FrontendFreeStateContents(&state);
}
TEST_F(FrontendTest, CheckConsecutiveWindow) {
struct FrontendState state;
ASSERT_TRUE(FrontendPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
FrontendProcessSamples(&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]),
&num_samples_read);
struct FrontendOutput output = FrontendProcessSamples(
&state, kFakeAudioData + kWindowSamples,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]) - kWindowSamples,
&num_samples_read);
const int16_t expected[] = {436, 378};
ASSERT_EQ(output.size, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < output.size; ++i) {
EXPECT_EQ(output.values[i], expected[i]);
}
FrontendFreeStateContents(&state);
}
TEST_F(FrontendTest, CheckNotEnoughSamples) {
struct FrontendState state;
ASSERT_TRUE(FrontendPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
FrontendProcessSamples(&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]),
&num_samples_read);
FrontendProcessSamples(
&state, kFakeAudioData + kWindowSamples,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]) - kWindowSamples,
&num_samples_read);
struct FrontendOutput output = FrontendProcessSamples(
&state, kFakeAudioData + kWindowSamples + kStepSamples,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]) - kWindowSamples -
kStepSamples,
&num_samples_read);
EXPECT_EQ(output.size, 0);
EXPECT_EQ(output.values, nullptr);
FrontendFreeStateContents(&state);
}
} // namespace

View File

@ -0,0 +1,87 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend_util.h"
#include <stdio.h>
#include <string.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/bits.h"
void FrontendFillConfigWithDefaults(struct FrontendConfig* config) {
WindowFillConfigWithDefaults(&config->window);
FilterbankFillConfigWithDefaults(&config->filterbank);
NoiseReductionFillConfigWithDefaults(&config->noise_reduction);
PcanGainControlFillConfigWithDefaults(&config->pcan_gain_control);
LogScaleFillConfigWithDefaults(&config->log_scale);
}
int FrontendPopulateState(const struct FrontendConfig* config,
struct FrontendState* state, int sample_rate) {
memset(state, 0, sizeof(*state));
if (!WindowPopulateState(&config->window, &state->window, sample_rate)) {
fprintf(stderr, "Failed to populate window state\n");
return 0;
}
if (!FftPopulateState(&state->fft, state->window.size)) {
fprintf(stderr, "Failed to populate fft state\n");
return 0;
}
FftInit(&state->fft);
if (!FilterbankPopulateState(&config->filterbank, &state->filterbank,
sample_rate, state->fft.fft_size / 2 + 1)) {
fprintf(stderr, "Failed to populate filterbank state\n");
return 0;
}
if (!NoiseReductionPopulateState(&config->noise_reduction,
&state->noise_reduction,
state->filterbank.num_channels)) {
fprintf(stderr, "Failed to populate noise reduction state\n");
return 0;
}
int input_correction_bits =
MostSignificantBit32(state->fft.fft_size) - 1 - (kFilterbankBits / 2);
if (!PcanGainControlPopulateState(&config->pcan_gain_control,
&state->pcan_gain_control,
state->noise_reduction.estimate,
state->filterbank.num_channels,
state->noise_reduction.smoothing_bits,
input_correction_bits)) {
fprintf(stderr, "Failed to populate pcan gain control state\n");
return 0;
}
if (!LogScalePopulateState(&config->log_scale, &state->log_scale)) {
fprintf(stderr, "Failed to populate log scale state\n");
return 0;
}
FrontendReset(state);
// All good, return a true value.
return 1;
}
void FrontendFreeStateContents(struct FrontendState* state) {
WindowFreeStateContents(&state->window);
FftFreeStateContents(&state->fft);
FilterbankFreeStateContents(&state->filterbank);
NoiseReductionFreeStateContents(&state->noise_reduction);
PcanGainControlFreeStateContents(&state->pcan_gain_control);
}

View File

@ -0,0 +1,52 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_UTIL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_UTIL_H_
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/fft_util.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/filterbank_util.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/frontend.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale_util.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction_util.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/pcan_gain_control_util.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window_util.h"
#ifdef __cplusplus
extern "C" {
#endif
struct FrontendConfig {
struct WindowConfig window;
struct FilterbankConfig filterbank;
struct NoiseReductionConfig noise_reduction;
struct PcanGainControlConfig pcan_gain_control;
struct LogScaleConfig log_scale;
};
// Fills the frontendConfig with "sane" defaults.
void FrontendFillConfigWithDefaults(struct FrontendConfig* config);
// Allocates any buffers.
int FrontendPopulateState(const struct FrontendConfig* config,
struct FrontendState* state, int sample_rate);
// Frees any allocated buffers.
void FrontendFreeStateContents(struct FrontendState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_FRONTEND_UTIL_H_

View File

@ -0,0 +1,30 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_lut.h"
const uint16_t kLogLut[]
#ifndef _MSC_VER
__attribute__((aligned(4)))
#endif // _MSV_VER
= {0, 224, 442, 654, 861, 1063, 1259, 1450, 1636, 1817, 1992, 2163,
2329, 2490, 2646, 2797, 2944, 3087, 3224, 3358, 3487, 3611, 3732, 3848,
3960, 4068, 4172, 4272, 4368, 4460, 4549, 4633, 4714, 4791, 4864, 4934,
5001, 5063, 5123, 5178, 5231, 5280, 5326, 5368, 5408, 5444, 5477, 5507,
5533, 5557, 5578, 5595, 5610, 5622, 5631, 5637, 5640, 5641, 5638, 5633,
5626, 5615, 5602, 5586, 5568, 5547, 5524, 5498, 5470, 5439, 5406, 5370,
5332, 5291, 5249, 5203, 5156, 5106, 5054, 5000, 4944, 4885, 4825, 4762,
4697, 4630, 4561, 4490, 4416, 4341, 4264, 4184, 4103, 4020, 3935, 3848,
3759, 3668, 3575, 3481, 3384, 3286, 3186, 3084, 2981, 2875, 2768, 2659,
2549, 2437, 2323, 2207, 2090, 1971, 1851, 1729, 1605, 1480, 1353, 1224,
1094, 963, 830, 695, 559, 421, 282, 142, 0, 0};

View File

@ -0,0 +1,40 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_LUT_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_LUT_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// Number of segments in the log lookup table. The table will be kLogSegments+1
// in length (with some padding).
#define kLogSegments 128
#define kLogSegmentsLog2 7
// Scale used by lookup table.
#define kLogScale 65536
#define kLogScaleLog2 16
#define kLogCoeff 45426
extern const uint16_t kLogLut[];
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_LUT_H_

View File

@ -0,0 +1,83 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/bits.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_lut.h"
#define kuint16max 0x0000FFFF
// The following functions implement integer logarithms of various sizes. The
// approximation is calculated according to method described in
// www.inti.gob.ar/electronicaeinformatica/instrumentacion/utic/
// publicaciones/SPL2007/Log10-spl07.pdf
// It first calculates log2 of the input and then converts it to natural
// logarithm.
static uint32_t Log2FractionPart(const uint32_t x, const uint32_t log2x) {
// Part 1
int32_t frac = x - (1LL << log2x);
if (log2x < kLogScaleLog2) {
frac <<= kLogScaleLog2 - log2x;
} else {
frac >>= log2x - kLogScaleLog2;
}
// Part 2
const uint32_t base_seg = frac >> (kLogScaleLog2 - kLogSegmentsLog2);
const uint32_t seg_unit =
(((uint32_t) 1) << kLogScaleLog2) >> kLogSegmentsLog2;
const int32_t c0 = kLogLut[base_seg];
const int32_t c1 = kLogLut[base_seg + 1];
const int32_t seg_base = seg_unit * base_seg;
const int32_t rel_pos = ((c1 - c0) * (frac - seg_base)) >> kLogScaleLog2;
return frac + c0 + rel_pos;
}
static uint32_t Log(const uint32_t x, const uint32_t scale_shift) {
const uint32_t integer = MostSignificantBit32(x) - 1;
const uint32_t fraction = Log2FractionPart(x, integer);
const uint32_t log2 = (integer << kLogScaleLog2) + fraction;
const uint32_t round = kLogScale / 2;
const uint32_t loge =
(((uint64_t) kLogCoeff) * log2 + round) >> kLogScaleLog2;
// Finally scale to our output scale
const uint32_t loge_scaled = ((loge << scale_shift) + round) >> kLogScaleLog2;
return loge_scaled;
}
uint16_t* LogScaleApply(struct LogScaleState* state, uint32_t* signal,
int signal_size, int correction_bits) {
const int scale_shift = state->scale_shift;
uint16_t* output = (uint16_t*) signal;
uint16_t* ret = output;
for (int i = 0; i < signal_size; ++i) {
uint32_t value = *signal++;
if (state->enable_log) {
if (correction_bits < 0) {
value >>= -correction_bits;
} else {
value <<= correction_bits;
}
if (value > 1) {
value = Log(value, scale_shift);
} else {
value = 0;
}
}
*output++ = (value < kuint16max) ? value : kuint16max;
}
return ret;
}

View File

@ -0,0 +1,39 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_H_
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
struct LogScaleState {
int enable_log;
int scale_shift;
};
// Applies a fixed point logarithm to the signal and converts it to 16 bit. Note
// that the signal array will be modified.
uint16_t* LogScaleApply(struct LogScaleState* state, uint32_t* signal,
int signal_size, int correction_bits);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_H_

View File

@ -0,0 +1,21 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale_io.h"
void LogScaleWriteMemmap(FILE* fp, const struct LogScaleState* state,
const char* variable) {
fprintf(fp, "%s->enable_log = %d;\n", variable, state->enable_log);
fprintf(fp, "%s->scale_shift = %d;\n", variable, state->scale_shift);
}

View File

@ -0,0 +1,33 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_IO_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_IO_H_
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale.h"
#ifdef __cplusplus
extern "C" {
#endif
void LogScaleWriteMemmap(FILE* fp, const struct LogScaleState* state,
const char* variable);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_IO_H_

View File

@ -0,0 +1,58 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
const int kScaleShift = 6;
const int kCorrectionBits = -1;
TEST(LogScaleTest, CheckOutputValues) {
struct LogScaleState state;
state.enable_log = true;
state.scale_shift = kScaleShift;
uint32_t fake_signal[] = {3578, 1533};
uint16_t* output = LogScaleApply(&state, fake_signal,
sizeof(fake_signal) / sizeof(fake_signal[0]),
kCorrectionBits);
const uint16_t expected[] = {479, 425};
for (int i = 0; i < sizeof(expected) / sizeof(expected[0]); ++i) {
EXPECT_EQ(output[i], expected[i]);
}
}
TEST(LogScaleTest, CheckOutputValuesNoLog) {
struct LogScaleState state;
state.enable_log = false;
state.scale_shift = kScaleShift;
uint32_t fake_signal[] = {85964, 45998};
uint16_t* output = LogScaleApply(&state, fake_signal,
sizeof(fake_signal) / sizeof(fake_signal[0]),
kCorrectionBits);
const uint16_t expected[] = {65535, 45998};
for (int i = 0; i < sizeof(expected) / sizeof(expected[0]); ++i) {
EXPECT_EQ(output[i], expected[i]);
}
}
} // namespace

View File

@ -0,0 +1,27 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale_util.h"
void LogScaleFillConfigWithDefaults(struct LogScaleConfig* config) {
config->enable_log = 1;
config->scale_shift = 6;
}
int LogScalePopulateState(const struct LogScaleConfig* config,
struct LogScaleState* state) {
state->enable_log = config->enable_log;
state->scale_shift = config->scale_shift;
return 1;
}

View File

@ -0,0 +1,45 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_UTIL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_UTIL_H_
#include <stdint.h>
#include <stdlib.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/log_scale.h"
#ifdef __cplusplus
extern "C" {
#endif
struct LogScaleConfig {
// set to false (0) to disable this module
int enable_log;
// scale results by 2^(scale_shift)
int scale_shift;
};
// Populates the LogScaleConfig with "sane" default values.
void LogScaleFillConfigWithDefaults(struct LogScaleConfig* config);
// Allocates any buffers.
int LogScalePopulateState(const struct LogScaleConfig* config,
struct LogScaleState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_LOG_SCALE_UTIL_H_

View File

@ -0,0 +1,51 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction.h"
#include <string.h>
void NoiseReductionApply(struct NoiseReductionState* state, uint32_t* signal) {
int i;
for (i = 0; i < state->num_channels; ++i) {
const uint32_t smoothing =
((i & 1) == 0) ? state->even_smoothing : state->odd_smoothing;
const uint32_t one_minus_smoothing = (1 << kNoiseReductionBits) - smoothing;
// Update the estimate of the noise.
const uint32_t signal_scaled_up = signal[i] << state->smoothing_bits;
uint32_t estimate =
(((uint64_t) signal_scaled_up * smoothing) +
((uint64_t) state->estimate[i] * one_minus_smoothing)) >>
kNoiseReductionBits;
state->estimate[i] = estimate;
// Make sure that we can't get a negative value for the signal - estimate.
if (estimate > signal_scaled_up) {
estimate = signal_scaled_up;
}
const uint32_t floor =
((uint64_t) signal[i] * state->min_signal_remaining) >>
kNoiseReductionBits;
const uint32_t subtracted = (signal_scaled_up - estimate) >>
state->smoothing_bits;
const uint32_t output = subtracted > floor ? subtracted : floor;
signal[i] = output;
}
}
void NoiseReductionReset(struct NoiseReductionState* state) {
memset(state->estimate, 0, sizeof(*state->estimate) * state->num_channels);
}

View File

@ -0,0 +1,46 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_H_
#define kNoiseReductionBits 14
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
struct NoiseReductionState {
int smoothing_bits;
uint16_t even_smoothing;
uint16_t odd_smoothing;
uint16_t min_signal_remaining;
int num_channels;
uint32_t* estimate;
};
// Removes stationary noise from each channel of the signal using a low pass
// filter.
void NoiseReductionApply(struct NoiseReductionState* state, uint32_t* signal);
void NoiseReductionReset(struct NoiseReductionState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_H_

View File

@ -0,0 +1,34 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction_io.h"
void NoiseReductionWriteMemmapPreamble(
FILE* fp, const struct NoiseReductionState* state) {
fprintf(fp, "static uint32_t noise_reduction_estimate[%zu];\n",
state->num_channels);
fprintf(fp, "\n");
}
void NoiseReductionWriteMemmap(FILE* fp,
const struct NoiseReductionState* state,
const char* variable) {
fprintf(fp, "%s->even_smoothing = %d;\n", variable, state->even_smoothing);
fprintf(fp, "%s->odd_smoothing = %d;\n", variable, state->odd_smoothing);
fprintf(fp, "%s->min_signal_remaining = %d;\n", variable,
state->min_signal_remaining);
fprintf(fp, "%s->num_channels = %d;\n", variable, state->num_channels);
fprintf(fp, "%s->estimate = noise_reduction_estimate;\n", variable);
}

View File

@ -0,0 +1,36 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_IO_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_IO_H_
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction.h"
#ifdef __cplusplus
extern "C" {
#endif
void NoiseReductionWriteMemmapPreamble(FILE* fp,
const struct NoiseReductionState* state);
void NoiseReductionWriteMemmap(FILE* fp,
const struct NoiseReductionState* state,
const char* variable);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_IO_H_

View File

@ -0,0 +1,70 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
const int kNumChannels = 2;
// Test noise reduction using default config values.
class NoiseReductionTest : public ::testing::Test {
protected:
NoiseReductionTest() {
config_.smoothing_bits = 10;
config_.even_smoothing = 0.025;
config_.odd_smoothing = 0.06;
config_.min_signal_remaining = 0.05;
}
struct NoiseReductionConfig config_;
};
TEST_F(NoiseReductionTest, TestNoiseReductionEstimate) {
struct NoiseReductionState state;
ASSERT_TRUE(NoiseReductionPopulateState(&config_, &state, kNumChannels));
uint32_t signal[] = {247311, 508620};
NoiseReductionApply(&state, signal);
const uint32_t expected[] = {6321887, 31248341};
ASSERT_EQ(state.num_channels, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < state.num_channels; ++i) {
EXPECT_EQ(state.estimate[i], expected[i]);
}
NoiseReductionFreeStateContents(&state);
}
TEST_F(NoiseReductionTest, TestNoiseReduction) {
struct NoiseReductionState state;
ASSERT_TRUE(NoiseReductionPopulateState(&config_, &state, kNumChannels));
uint32_t signal[] = {247311, 508620};
NoiseReductionApply(&state, signal);
const uint32_t expected[] = {241137, 478104};
ASSERT_EQ(state.num_channels, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < state.num_channels; ++i) {
EXPECT_EQ(signal[i], expected[i]);
}
NoiseReductionFreeStateContents(&state);
}
} // namespace

View File

@ -0,0 +1,45 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction_util.h"
#include <stdio.h>
void NoiseReductionFillConfigWithDefaults(struct NoiseReductionConfig* config) {
config->smoothing_bits = 10;
config->even_smoothing = 0.025;
config->odd_smoothing = 0.06;
config->min_signal_remaining = 0.05;
}
int NoiseReductionPopulateState(const struct NoiseReductionConfig* config,
struct NoiseReductionState* state,
int num_channels) {
state->smoothing_bits = config->smoothing_bits;
state->odd_smoothing = config->odd_smoothing * (1 << kNoiseReductionBits);
state->even_smoothing = config->even_smoothing * (1 << kNoiseReductionBits);
state->min_signal_remaining =
config->min_signal_remaining * (1 << kNoiseReductionBits);
state->num_channels = num_channels;
state->estimate = calloc(state->num_channels, sizeof(*state->estimate));
if (state->estimate == NULL) {
fprintf(stderr, "Failed to alloc estimate buffer\n");
return 0;
}
return 1;
}
void NoiseReductionFreeStateContents(struct NoiseReductionState* state) {
free(state->estimate);
}

View File

@ -0,0 +1,50 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_UTIL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_UTIL_H_
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/noise_reduction.h"
#ifdef __cplusplus
extern "C" {
#endif
struct NoiseReductionConfig {
// scale the signal up by 2^(smoothing_bits) before reduction
int smoothing_bits;
// smoothing coefficient for even-numbered channels
float even_smoothing;
// smoothing coefficient for odd-numbered channels
float odd_smoothing;
// fraction of signal to preserve (1.0 disables this module)
float min_signal_remaining;
};
// Populates the NoiseReductionConfig with "sane" default values.
void NoiseReductionFillConfigWithDefaults(struct NoiseReductionConfig* config);
// Allocates any buffers.
int NoiseReductionPopulateState(const struct NoiseReductionConfig* config,
struct NoiseReductionState* state,
int num_channels);
// Frees any allocated buffers.
void NoiseReductionFreeStateContents(struct NoiseReductionState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_NOISE_REDUCTION_UTIL_H_

View File

@ -0,0 +1,56 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/pcan_gain_control.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/bits.h"
int16_t WideDynamicFunction(const uint32_t x, const int16_t* lut) {
if (x <= 2) {
return lut[x];
}
const int16_t interval = MostSignificantBit32(x);
lut += 4 * interval - 6;
const int16_t frac = ((interval < 11)
? (x << (11 - interval))
: (x >> (interval - 11))
) & 0x3FF;
int32_t result = ((int32_t) lut[2] * frac) >> 5;
result += ((int32_t) lut[1]) << 5;
result *= frac;
result = (result + (1 << 14)) >> 15;
result += lut[0];
return (int16_t) result;
}
uint32_t PcanShrink(const uint32_t x) {
if (x < (2 << kPcanSnrBits)) {
return (x * x) >> (2 + 2 * kPcanSnrBits - kPcanOutputBits);
} else {
return (x >> (kPcanSnrBits - kPcanOutputBits)) - (1 << kPcanOutputBits);
}
}
void PcanGainControlApply(struct PcanGainControlState* state,
uint32_t* signal) {
for (int i = 0; i < state->num_channels; ++i) {
const uint32_t gain = WideDynamicFunction(state->noise_estimate[i],
state->gain_lut);
const uint32_t snr = ((uint64_t) signal[i] * gain) >> state->snr_shift;
signal[i] = PcanShrink(snr);
}
}

View File

@ -0,0 +1,46 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_H_
#include <stdint.h>
#include <stdlib.h>
#define kPcanSnrBits 12
#define kPcanOutputBits 6
#ifdef __cplusplus
extern "C" {
#endif
struct PcanGainControlState {
int enable_pcan;
uint32_t* noise_estimate;
int num_channels;
int16_t* gain_lut;
int32_t snr_shift;
};
int16_t WideDynamicFunction(const uint32_t x, const int16_t* lut);
uint32_t PcanShrink(const uint32_t x);
void PcanGainControlApply(struct PcanGainControlState* state, uint32_t* signal);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_H_

View File

@ -0,0 +1,59 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/pcan_gain_control.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/pcan_gain_control_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
const int kNumChannels = 2;
const int kSmoothingBits = 10;
const int kCorrectionBits = -1;
// Test pcan auto gain control using default config values.
class PcanGainControlTest : public ::testing::Test {
protected:
PcanGainControlTest() {
config_.enable_pcan = 1;
config_.strength = 0.95;
config_.offset = 80.0;
config_.gain_bits = 21;
}
struct PcanGainControlConfig config_;
};
TEST_F(PcanGainControlTest, TestPcanGainControl) {
uint32_t estimate[] = {6321887, 31248341};
struct PcanGainControlState state;
ASSERT_TRUE(PcanGainControlPopulateState(&config_, &state, estimate,
kNumChannels, kSmoothingBits,
kCorrectionBits));
uint32_t signal[] = {241137, 478104};
PcanGainControlApply(&state, signal);
const uint32_t expected[] = {3578, 1533};
ASSERT_EQ(state.num_channels, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < state.num_channels; ++i) {
EXPECT_EQ(signal[i], expected[i]);
}
PcanGainControlFreeStateContents(&state);
}
} // namespace

View File

@ -0,0 +1,90 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/pcan_gain_control_util.h"
#include <math.h>
#include <stdio.h>
#define kint16max 0x00007FFF
void PcanGainControlFillConfigWithDefaults(
struct PcanGainControlConfig* config) {
config->enable_pcan = 0;
config->strength = 0.95;
config->offset = 80.0;
config->gain_bits = 21;
}
int16_t PcanGainLookupFunction(const struct PcanGainControlConfig* config,
int32_t input_bits, uint32_t x) {
const float x_as_float = ((float) x) / ((uint32_t) 1 << input_bits);
const float gain_as_float = ((uint32_t) 1 << config->gain_bits) *
powf(x_as_float + config->offset, -config->strength);
if (gain_as_float > kint16max) {
return kint16max;
}
return (int16_t) (gain_as_float + 0.5f);
}
int PcanGainControlPopulateState(const struct PcanGainControlConfig* config,
struct PcanGainControlState* state,
uint32_t* noise_estimate,
const int num_channels,
const uint16_t smoothing_bits,
const int32_t input_correction_bits) {
state->enable_pcan = config->enable_pcan;
if (!state->enable_pcan) {
return 1;
}
state->noise_estimate = noise_estimate;
state->num_channels = num_channels;
state->gain_lut = malloc(kWideDynamicFunctionLUTSize * sizeof(int16_t));
if (state->gain_lut == NULL) {
fprintf(stderr, "Failed to allocate gain LUT\n");
return 0;
}
state->snr_shift = config->gain_bits - input_correction_bits - kPcanSnrBits;
const int32_t input_bits = smoothing_bits - input_correction_bits;
state->gain_lut[0] = PcanGainLookupFunction(config, input_bits, 0);
state->gain_lut[1] = PcanGainLookupFunction(config, input_bits, 1);
state->gain_lut -= 6;
for (int interval = 2; interval <= kWideDynamicFunctionBits; ++interval) {
const uint32_t x0 = (uint32_t) 1 << (interval - 1);
const uint32_t x1 = x0 + (x0 >> 1);
const uint32_t x2 = (interval == kWideDynamicFunctionBits)
? x0 + (x0 - 1) : 2 * x0;
const int16_t y0 = PcanGainLookupFunction(config, input_bits, x0);
const int16_t y1 = PcanGainLookupFunction(config, input_bits, x1);
const int16_t y2 = PcanGainLookupFunction(config, input_bits, x2);
const int32_t diff1 = (int32_t) y1 - y0;
const int32_t diff2 = (int32_t) y2 - y0;
const int32_t a1 = 4 * diff1 - diff2;
const int32_t a2 = diff2 - a1;
state->gain_lut[4 * interval] = y0;
state->gain_lut[4 * interval + 1] = (int16_t) a1;
state->gain_lut[4 * interval + 2] = (int16_t) a2;
}
state->gain_lut += 6;
return 1;
}
void PcanGainControlFreeStateContents(struct PcanGainControlState* state) {
free(state->gain_lut);
}

View File

@ -0,0 +1,57 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_UTIL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_UTIL_H_
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/pcan_gain_control.h"
#define kWideDynamicFunctionBits 32
#define kWideDynamicFunctionLUTSize (4 * kWideDynamicFunctionBits - 3)
#ifdef __cplusplus
extern "C" {
#endif
struct PcanGainControlConfig {
// set to false (0) to disable this module
int enable_pcan;
// gain normalization exponent (0.0 disables, 1.0 full strength)
float strength;
// positive value added in the normalization denominator
float offset;
// number of fractional bits in the gain
int gain_bits;
};
void PcanGainControlFillConfigWithDefaults(
struct PcanGainControlConfig* config);
int16_t PcanGainLookupFunction(const struct PcanGainControlConfig* config,
int32_t input_bits, uint32_t x);
int PcanGainControlPopulateState(const struct PcanGainControlConfig* config,
struct PcanGainControlState* state,
uint32_t* noise_estimate,
const int num_channels,
const uint16_t smoothing_bits,
const int32_t input_correction_bits);
void PcanGainControlFreeStateContents(struct PcanGainControlState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_PCAN_GAIN_CONTROL_UTIL_H_

View File

@ -0,0 +1,70 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window.h"
#include <string.h>
int WindowProcessSamples(struct WindowState* state, const int16_t* samples,
size_t num_samples, size_t* num_samples_read) {
const int size = state->size;
// Copy samples from the samples buffer over to our local input.
size_t max_samples_to_copy = state->size - state->input_used;
if (max_samples_to_copy > num_samples) {
max_samples_to_copy = num_samples;
}
memcpy(state->input + state->input_used, samples,
max_samples_to_copy * sizeof(*samples));
*num_samples_read = max_samples_to_copy;
state->input_used += max_samples_to_copy;
if (state->input_used < state->size) {
// We don't have enough samples to compute a window.
return 0;
}
// Apply the window to the input.
const int16_t* coefficients = state->coefficients;
const int16_t* input = state->input;
int16_t* output = state->output;
int i;
int16_t max_abs_output_value = 0;
for (i = 0; i < size; ++i) {
int16_t new_value =
(((int32_t) *input++) * *coefficients++) >> kFrontendWindowBits;
*output++ = new_value;
if (new_value < 0) {
new_value = -new_value;
}
if (new_value > max_abs_output_value) {
max_abs_output_value = new_value;
}
}
// Shuffle the input down by the step size, and update how much we have used.
memmove(state->input, state->input + state->step,
sizeof(*state->input) * (state->size - state->step));
state->input_used -= state->step;
state->max_abs_output_value = max_abs_output_value;
// Indicate that the output buffer is valid for the next stage.
return 1;
}
void WindowReset(struct WindowState* state) {
memset(state->input, 0, state->size * sizeof(*state->input));
memset(state->output, 0, state->size * sizeof(*state->output));
state->input_used = 0;
state->max_abs_output_value = 0;
}

View File

@ -0,0 +1,49 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_H_
#include <stdint.h>
#include <stdlib.h>
#define kFrontendWindowBits 12
#ifdef __cplusplus
extern "C" {
#endif
struct WindowState {
size_t size;
int16_t* coefficients;
size_t step;
int16_t* input;
size_t input_used;
int16_t* output;
int16_t max_abs_output_value;
};
// Applies a window to the samples coming in, stepping forward at the given
// rate.
int WindowProcessSamples(struct WindowState* state, const int16_t* samples,
size_t num_samples, size_t* num_samples_read);
void WindowReset(struct WindowState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_H_

View File

@ -0,0 +1,42 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window_io.h"
void WindowWriteMemmapPreamble(FILE* fp, const struct WindowState* state) {
fprintf(fp, "static int16_t window_coefficients[] = {\n");
for (int i = 0; i < state->size; ++i) {
fprintf(fp, "%d", state->coefficients[i]);
if (i < state->size - 1) {
fprintf(fp, ", ");
}
}
fprintf(fp, "};\n");
fprintf(fp, "static int16_t window_input[%zu];\n", state->size);
fprintf(fp, "static int16_t window_output[%zu];\n", state->size);
fprintf(fp, "\n");
}
void WindowWriteMemmap(FILE* fp, const struct WindowState* state,
const char* variable) {
fprintf(fp, "%s->size = %zu;\n", variable, state->size);
fprintf(fp, "%s->coefficients = window_coefficients;\n", variable);
fprintf(fp, "%s->step = %zu;\n", variable, state->step);
fprintf(fp, "%s->input = window_input;\n", variable);
fprintf(fp, "%s->input_used = %zu;\n", variable, state->input_used);
fprintf(fp, "%s->output = window_output;\n", variable);
fprintf(fp, "%s->max_abs_output_value = %d;\n", variable,
state->max_abs_output_value);
}

View File

@ -0,0 +1,34 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_IO_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_IO_H_
#include <stdio.h>
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window.h"
#ifdef __cplusplus
extern "C" {
#endif
void WindowWriteMemmapPreamble(FILE* fp, const struct WindowState* state);
void WindowWriteMemmap(FILE* fp, const struct WindowState* state,
const char* variable);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_IO_H_

View File

@ -0,0 +1,157 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window.h"
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window_util.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace {
const int kSampleRate = 1000;
const int kWindowSamples = 25;
const int kStepSamples = 10;
const int16_t kFakeAudioData[] = {
0, 32767, 0, -32768, 0, 32767, 0, -32768, 0, 32767, 0, -32768,
0, 32767, 0, -32768, 0, 32767, 0, -32768, 0, 32767, 0, -32768,
0, 32767, 0, -32768, 0, 32767, 0, -32768, 0, 32767, 0, -32768};
// Test window function behaviors using default config values.
class WindowTest : public ::testing::Test {
protected:
WindowTest() {
config_.size_ms = 25;
config_.step_size_ms = 10;
}
struct WindowConfig config_;
};
TEST_F(WindowTest, CheckCoefficients) {
struct WindowState state;
ASSERT_TRUE(WindowPopulateState(&config_, &state, kSampleRate));
const int16_t expected[] = {16, 144, 391, 743, 1176, 1664, 2177,
2681, 3145, 3541, 3843, 4032, 4096, 4032,
3843, 3541, 3145, 2681, 2177, 1664, 1176,
743, 391, 144, 16};
ASSERT_EQ(state.size, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < state.size; ++i) {
EXPECT_EQ(state.coefficients[i], expected[i]);
}
WindowFreeStateContents(&state);
}
TEST_F(WindowTest, CheckResidualInput) {
struct WindowState state;
ASSERT_TRUE(WindowPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
ASSERT_TRUE(WindowProcessSamples(
&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]), &num_samples_read));
for (int i = kStepSamples; i < kWindowSamples; ++i) {
EXPECT_EQ(state.input[i - kStepSamples], kFakeAudioData[i]);
}
WindowFreeStateContents(&state);
}
TEST_F(WindowTest, CheckOutputValues) {
struct WindowState state;
ASSERT_TRUE(WindowPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
ASSERT_TRUE(WindowProcessSamples(
&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]), &num_samples_read));
const int16_t expected[] = {
0, 1151, 0, -5944, 0, 13311, 0, -21448, 0, 28327, 0, -32256, 0, 32255,
0, -28328, 0, 21447, 0, -13312, 0, 5943, 0, -1152, 0};
ASSERT_EQ(state.size, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < state.size; ++i) {
EXPECT_EQ(state.output[i], expected[i]);
}
WindowFreeStateContents(&state);
}
TEST_F(WindowTest, CheckMaxAbsValue) {
struct WindowState state;
ASSERT_TRUE(WindowPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
ASSERT_TRUE(WindowProcessSamples(
&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]), &num_samples_read));
EXPECT_EQ(state.max_abs_output_value, 32256);
WindowFreeStateContents(&state);
}
TEST_F(WindowTest, CheckConsecutiveWindow) {
struct WindowState state;
ASSERT_TRUE(WindowPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
ASSERT_TRUE(WindowProcessSamples(
&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]), &num_samples_read));
ASSERT_TRUE(WindowProcessSamples(
&state, kFakeAudioData + kWindowSamples,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]) - kWindowSamples,
&num_samples_read));
const int16_t expected[] = {
0, -1152, 0, 5943, 0, -13312, 0, 21447, 0, -28328, 0, 32255, 0, -32256,
0, 28327, 0, -21448, 0, 13311, 0, -5944, 0, 1151, 0};
ASSERT_EQ(state.size, sizeof(expected) / sizeof(expected[0]));
for (int i = 0; i < state.size; ++i) {
EXPECT_EQ(state.output[i], expected[i]);
}
WindowFreeStateContents(&state);
}
TEST_F(WindowTest, CheckNotEnoughSamples) {
struct WindowState state;
ASSERT_TRUE(WindowPopulateState(&config_, &state, kSampleRate));
size_t num_samples_read;
ASSERT_TRUE(WindowProcessSamples(
&state, kFakeAudioData,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]), &num_samples_read));
ASSERT_TRUE(WindowProcessSamples(
&state, kFakeAudioData + kWindowSamples,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]) - kWindowSamples,
&num_samples_read));
ASSERT_FALSE(WindowProcessSamples(
&state, kFakeAudioData + kWindowSamples + kStepSamples,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]) - kWindowSamples -
kStepSamples,
&num_samples_read));
EXPECT_EQ(
state.input_used,
sizeof(kFakeAudioData) / sizeof(kFakeAudioData[0]) - 2 * kStepSamples);
WindowFreeStateContents(&state);
}
} // namespace

View File

@ -0,0 +1,71 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window_util.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void WindowFillConfigWithDefaults(struct WindowConfig* config) {
config->size_ms = 25;
config->step_size_ms = 10;
}
int WindowPopulateState(const struct WindowConfig* config,
struct WindowState* state, int sample_rate) {
state->size = config->size_ms * sample_rate / 1000;
state->step = config->step_size_ms * sample_rate / 1000;
state->coefficients = malloc(
state->size * sizeof(*state->coefficients));
if (state->coefficients == NULL) {
fprintf(stderr, "Failed to allocate window coefficients\n");
return 0;
}
// Populate the window values.
const float arg = M_PI * 2.0 / ((float) state->size);
int i;
for (i = 0; i < state->size; ++i) {
float float_value = 0.5 - (0.5 * cos(arg * (i + 0.5)));
// Scale it to fixed point and round it.
state->coefficients[i] =
floor(float_value * (1 << kFrontendWindowBits) + 0.5);
}
state->input_used = 0;
state->input = malloc(
state->size * sizeof(*state->input));
if (state->input == NULL) {
fprintf(stderr, "Failed to allocate window input\n");
return 0;
}
state->output = malloc(
state->size * sizeof(*state->output));
if (state->output == NULL) {
fprintf(stderr, "Failed to allocate window output\n");
return 0;
}
return 1;
}
void WindowFreeStateContents(struct WindowState* state) {
free(state->coefficients);
free(state->input);
free(state->output);
}

View File

@ -0,0 +1,45 @@
/* Copyright 2018 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#ifndef TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_UTIL_H_
#define TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_UTIL_H_
#include "tensorflow/contrib/lite/experimental/microfrontend/lib/window.h"
#ifdef __cplusplus
extern "C" {
#endif
struct WindowConfig {
// length of window frame in milliseconds
size_t size_ms;
// length of step for next frame in milliseconds
size_t step_size_ms;
};
// Populates the WindowConfig with "sane" default values.
void WindowFillConfigWithDefaults(struct WindowConfig* config);
// Allocates any buffers.
int WindowPopulateState(const struct WindowConfig* config,
struct WindowState* state, int sample_rate);
// Frees any allocated buffers.
void WindowFreeStateContents(struct WindowState* state);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // TENSORFLOW_CONTRIB_LITE_EXPERIMENTAL_MICROFRONTEND_LIB_WINDOW_UTIL_H_

View File

@ -26,6 +26,7 @@ load("//third_party/highwayhash:workspace.bzl", highwayhash = "repo")
load("//third_party/icu:workspace.bzl", icu = "repo")
load("//third_party/jpeg:workspace.bzl", jpeg = "repo")
load("//third_party/nasm:workspace.bzl", nasm = "repo")
load("//third_party/kissfft:workspace.bzl", kissfft = "repo")
def initialize_third_party():
""" Load third party repositories. See above load() statements. """
@ -33,6 +34,7 @@ def initialize_third_party():
flatbuffers()
highwayhash()
icu()
kissfft()
jpeg()
nasm()

1
third_party/kissfft/BUILD vendored Normal file
View File

@ -0,0 +1 @@
# This empty BUILD file is required to make Bazel treat this directory as a package.

23
third_party/kissfft/BUILD.bazel vendored Normal file
View File

@ -0,0 +1,23 @@
package(
default_visibility = ["//visibility:public"],
)
licenses(["notice"]) # Apache 2.0
exports_files(["LICENSE"])
cc_library(
name = "kiss_fftr_16",
srcs = [
"kiss_fft.c",
"tools/kiss_fftr.c",
],
hdrs = [
"_kiss_fft_guts.h",
"kiss_fft.h",
"tools/kiss_fftr.h",
],
copts = [
"-DFIXED_POINT=16",
],
)

15
third_party/kissfft/workspace.bzl vendored Normal file
View File

@ -0,0 +1,15 @@
"""Loads the kissfft library, used by TF Lite."""
load("//third_party:repo.bzl", "third_party_http_archive")
def repo():
third_party_http_archive(
name = "kissfft",
strip_prefix = "kissfft-cddf3833fdf24fa84b79be37efdcd348cae0e39c",
sha256 = "7ba83a3da1636350472e501e3e6c3418df72466990530ea273c05fa7e3dd8635",
urls = [
"https://mirror.bazel.build/github.com/mborgerding/kissfft/archive/cddf3833fdf24fa84b79be37efdcd348cae0e39c.tar.gz",
"https://github.com/mborgerding/kissfft/archive/cddf3833fdf24fa84b79be37efdcd348cae0e39c.tar.gz",
],
build_file = "//third_party/kissfft:BUILD.bazel",
)