mirror of
https://github.com/esphome/esphome.git
synced 2024-11-28 12:46:22 +01:00
[micro_wake_word] Version 2 (#7032)
This commit is contained in:
parent
2da939c81c
commit
2873c6bbaf
@ -9,7 +9,7 @@ import requests
|
|||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
|
|
||||||
from esphome.core import CORE, HexInt, EsphomeError
|
from esphome.core import CORE, HexInt
|
||||||
|
|
||||||
from esphome.components import esp32, microphone
|
from esphome.components import esp32, microphone
|
||||||
from esphome import automation, git, external_files
|
from esphome import automation, git, external_files
|
||||||
@ -41,9 +41,15 @@ CODEOWNERS = ["@kahrendt", "@jesserockz"]
|
|||||||
DEPENDENCIES = ["microphone"]
|
DEPENDENCIES = ["microphone"]
|
||||||
DOMAIN = "micro_wake_word"
|
DOMAIN = "micro_wake_word"
|
||||||
|
|
||||||
|
|
||||||
|
CONF_FEATURE_STEP_SIZE = "feature_step_size"
|
||||||
|
CONF_MODELS = "models"
|
||||||
|
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
|
||||||
CONF_PROBABILITY_CUTOFF = "probability_cutoff"
|
CONF_PROBABILITY_CUTOFF = "probability_cutoff"
|
||||||
CONF_SLIDING_WINDOW_AVERAGE_SIZE = "sliding_window_average_size"
|
CONF_SLIDING_WINDOW_AVERAGE_SIZE = "sliding_window_average_size"
|
||||||
CONF_ON_WAKE_WORD_DETECTED = "on_wake_word_detected"
|
CONF_SLIDING_WINDOW_SIZE = "sliding_window_size"
|
||||||
|
CONF_TENSOR_ARENA_SIZE = "tensor_arena_size"
|
||||||
|
CONF_VAD = "vad"
|
||||||
|
|
||||||
TYPE_HTTP = "http"
|
TYPE_HTTP = "http"
|
||||||
|
|
||||||
@ -98,12 +104,14 @@ GIT_SCHEMA = cv.All(
|
|||||||
_process_git_source,
|
_process_git_source,
|
||||||
)
|
)
|
||||||
|
|
||||||
KEY_WAKE_WORD = "wake_word"
|
|
||||||
KEY_AUTHOR = "author"
|
KEY_AUTHOR = "author"
|
||||||
KEY_WEBSITE = "website"
|
|
||||||
KEY_VERSION = "version"
|
|
||||||
KEY_MICRO = "micro"
|
KEY_MICRO = "micro"
|
||||||
KEY_MINIMUM_ESPHOME_VERSION = "minimum_esphome_version"
|
KEY_MINIMUM_ESPHOME_VERSION = "minimum_esphome_version"
|
||||||
|
KEY_TRAINED_LANGUAGES = "trained_languages"
|
||||||
|
KEY_VERSION = "version"
|
||||||
|
KEY_WAKE_WORD = "wake_word"
|
||||||
|
KEY_WEBSITE = "website"
|
||||||
|
|
||||||
MANIFEST_SCHEMA_V1 = cv.Schema(
|
MANIFEST_SCHEMA_V1 = cv.Schema(
|
||||||
{
|
{
|
||||||
@ -125,6 +133,29 @@ MANIFEST_SCHEMA_V1 = cv.Schema(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MANIFEST_SCHEMA_V2 = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_TYPE): "micro",
|
||||||
|
cv.Required(CONF_MODEL): cv.string,
|
||||||
|
cv.Required(KEY_AUTHOR): cv.string,
|
||||||
|
cv.Required(KEY_VERSION): cv.All(cv.int_, 2),
|
||||||
|
cv.Required(KEY_WAKE_WORD): cv.string,
|
||||||
|
cv.Required(KEY_TRAINED_LANGUAGES): cv.ensure_list(cv.string),
|
||||||
|
cv.Optional(KEY_WEBSITE): cv.url,
|
||||||
|
cv.Required(KEY_MICRO): cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_FEATURE_STEP_SIZE): cv.int_range(min=0, max=30),
|
||||||
|
cv.Required(CONF_TENSOR_ARENA_SIZE): cv.int_,
|
||||||
|
cv.Required(CONF_PROBABILITY_CUTOFF): cv.float_,
|
||||||
|
cv.Required(CONF_SLIDING_WINDOW_SIZE): cv.positive_int,
|
||||||
|
cv.Required(KEY_MINIMUM_ESPHOME_VERSION): cv.All(
|
||||||
|
cv.version_number, cv.validate_esphome_version
|
||||||
|
),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _compute_local_file_path(config: dict) -> Path:
|
def _compute_local_file_path(config: dict) -> Path:
|
||||||
url = config[CONF_URL]
|
url = config[CONF_URL]
|
||||||
@ -135,6 +166,24 @@ def _compute_local_file_path(config: dict) -> Path:
|
|||||||
return base_dir / key
|
return base_dir / key
|
||||||
|
|
||||||
|
|
||||||
|
def _convert_manifest_v1_to_v2(v1_manifest):
|
||||||
|
v2_manifest = v1_manifest.copy()
|
||||||
|
|
||||||
|
v2_manifest[KEY_VERSION] = 2
|
||||||
|
v2_manifest[KEY_MICRO][CONF_SLIDING_WINDOW_SIZE] = v1_manifest[KEY_MICRO][
|
||||||
|
CONF_SLIDING_WINDOW_AVERAGE_SIZE
|
||||||
|
]
|
||||||
|
del v2_manifest[KEY_MICRO][CONF_SLIDING_WINDOW_AVERAGE_SIZE]
|
||||||
|
v2_manifest[KEY_MICRO][
|
||||||
|
CONF_TENSOR_ARENA_SIZE
|
||||||
|
] = 45672 # Original Inception-based V1 manifest models require a minimum of 45672 bytes
|
||||||
|
v2_manifest[KEY_MICRO][
|
||||||
|
CONF_FEATURE_STEP_SIZE
|
||||||
|
] = 20 # Original Inception-based V1 manifest models use a 20 ms feature step size
|
||||||
|
|
||||||
|
return v2_manifest
|
||||||
|
|
||||||
|
|
||||||
def _download_file(url: str, path: Path) -> bytes:
|
def _download_file(url: str, path: Path) -> bytes:
|
||||||
if not external_files.has_remote_file_changed(url, path):
|
if not external_files.has_remote_file_changed(url, path):
|
||||||
_LOGGER.debug("Remote file has not changed, skipping download")
|
_LOGGER.debug("Remote file has not changed, skipping download")
|
||||||
@ -155,6 +204,24 @@ def _download_file(url: str, path: Path) -> bytes:
|
|||||||
return req.content
|
return req.content
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_manifest_version(manifest_data):
|
||||||
|
if manifest_version := manifest_data.get(KEY_VERSION):
|
||||||
|
if manifest_version == 1:
|
||||||
|
try:
|
||||||
|
MANIFEST_SCHEMA_V1(manifest_data)
|
||||||
|
except cv.Invalid as e:
|
||||||
|
raise cv.Invalid(f"Invalid manifest file: {e}") from e
|
||||||
|
elif manifest_version == 2:
|
||||||
|
try:
|
||||||
|
MANIFEST_SCHEMA_V2(manifest_data)
|
||||||
|
except cv.Invalid as e:
|
||||||
|
raise cv.Invalid(f"Invalid manifest file: {e}") from e
|
||||||
|
else:
|
||||||
|
raise cv.Invalid("Invalid manifest version")
|
||||||
|
else:
|
||||||
|
raise cv.Invalid("Invalid manifest file, missing 'version' key.")
|
||||||
|
|
||||||
|
|
||||||
def _process_http_source(config):
|
def _process_http_source(config):
|
||||||
url = config[CONF_URL]
|
url = config[CONF_URL]
|
||||||
path = _compute_local_file_path(config)
|
path = _compute_local_file_path(config)
|
||||||
@ -167,11 +234,6 @@ def _process_http_source(config):
|
|||||||
if not isinstance(manifest_data, dict):
|
if not isinstance(manifest_data, dict):
|
||||||
raise cv.Invalid("Manifest file must contain a JSON object")
|
raise cv.Invalid("Manifest file must contain a JSON object")
|
||||||
|
|
||||||
try:
|
|
||||||
MANIFEST_SCHEMA_V1(manifest_data)
|
|
||||||
except cv.Invalid as e:
|
|
||||||
raise cv.Invalid(f"Invalid manifest file: {e}") from e
|
|
||||||
|
|
||||||
model = manifest_data[CONF_MODEL]
|
model = manifest_data[CONF_MODEL]
|
||||||
model_url = urljoin(url, model)
|
model_url = urljoin(url, model)
|
||||||
|
|
||||||
@ -206,7 +268,7 @@ def _validate_source_model_name(value):
|
|||||||
return MODEL_SOURCE_SCHEMA(
|
return MODEL_SOURCE_SCHEMA(
|
||||||
{
|
{
|
||||||
CONF_TYPE: TYPE_HTTP,
|
CONF_TYPE: TYPE_HTTP,
|
||||||
CONF_URL: f"https://github.com/esphome/micro-wake-word-models/raw/main/models/{value}.json",
|
CONF_URL: f"https://github.com/esphome/micro-wake-word-models/raw/main/models/v2/{value}.json",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -260,18 +322,55 @@ MODEL_SOURCE_SCHEMA = cv.Any(
|
|||||||
msg="Not a valid model name, local path, http(s) url, or github shorthand",
|
msg="Not a valid model name, local path, http(s) url, or github shorthand",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
MODEL_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(CONF_MODEL): MODEL_SOURCE_SCHEMA,
|
||||||
|
cv.Optional(CONF_PROBABILITY_CUTOFF): cv.percentage,
|
||||||
|
cv.Optional(CONF_SLIDING_WINDOW_SIZE): cv.positive_int,
|
||||||
|
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Provide a default VAD model that could be overridden
|
||||||
|
VAD_MODEL_SCHEMA = MODEL_SCHEMA.extend(
|
||||||
|
cv.Schema(
|
||||||
|
{
|
||||||
|
cv.Optional(
|
||||||
|
CONF_MODEL,
|
||||||
|
default="vad",
|
||||||
|
): MODEL_SOURCE_SCHEMA,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _maybe_empty_vad_schema(value):
|
||||||
|
# Idea borrowed from uart/__init__.py's ``maybe_empty_debug`` function. Accessed 2 July 2024.
|
||||||
|
# Loads a default VAD model without any parameters overridden.
|
||||||
|
if value is None:
|
||||||
|
value = {}
|
||||||
|
return VAD_MODEL_SCHEMA(value)
|
||||||
|
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.All(
|
CONFIG_SCHEMA = cv.All(
|
||||||
cv.Schema(
|
cv.Schema(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(MicroWakeWord),
|
cv.GenerateID(): cv.declare_id(MicroWakeWord),
|
||||||
cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone),
|
cv.GenerateID(CONF_MICROPHONE): cv.use_id(microphone.Microphone),
|
||||||
cv.Optional(CONF_PROBABILITY_CUTOFF): cv.percentage,
|
cv.Required(CONF_MODELS): cv.ensure_list(MODEL_SCHEMA),
|
||||||
cv.Optional(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.positive_int,
|
|
||||||
cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation(
|
cv.Optional(CONF_ON_WAKE_WORD_DETECTED): automation.validate_automation(
|
||||||
single=True
|
single=True
|
||||||
),
|
),
|
||||||
cv.Required(CONF_MODEL): MODEL_SOURCE_SCHEMA,
|
cv.Optional(CONF_VAD): _maybe_empty_vad_schema,
|
||||||
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
|
cv.Optional(CONF_MODEL): cv.invalid(
|
||||||
|
f"The {CONF_MODEL} parameter has moved to be a list element under the {CONF_MODELS} parameter."
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_PROBABILITY_CUTOFF): cv.invalid(
|
||||||
|
f"The {CONF_PROBABILITY_CUTOFF} parameter has moved to be a list element under the {CONF_MODELS} parameter."
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_SLIDING_WINDOW_AVERAGE_SIZE): cv.invalid(
|
||||||
|
f"The {CONF_SLIDING_WINDOW_AVERAGE_SIZE} parameter has been renamed to {CONF_SLIDING_WINDOW_SIZE} and moved to be a list element under the {CONF_MODELS} parameter."
|
||||||
|
),
|
||||||
}
|
}
|
||||||
).extend(cv.COMPONENT_SCHEMA),
|
).extend(cv.COMPONENT_SCHEMA),
|
||||||
cv.only_with_esp_idf,
|
cv.only_with_esp_idf,
|
||||||
@ -282,45 +381,20 @@ def _load_model_data(manifest_path: Path):
|
|||||||
with open(manifest_path, encoding="utf-8") as f:
|
with open(manifest_path, encoding="utf-8") as f:
|
||||||
manifest = json.load(f)
|
manifest = json.load(f)
|
||||||
|
|
||||||
try:
|
_validate_manifest_version(manifest)
|
||||||
MANIFEST_SCHEMA_V1(manifest)
|
|
||||||
except cv.Invalid as e:
|
|
||||||
raise EsphomeError(f"Invalid manifest file: {e}") from e
|
|
||||||
|
|
||||||
model_path = manifest_path.parent / manifest[CONF_MODEL]
|
model_path = manifest_path.parent / manifest[CONF_MODEL]
|
||||||
|
|
||||||
with open(model_path, "rb") as f:
|
with open(model_path, "rb") as f:
|
||||||
model = f.read()
|
model = f.read()
|
||||||
|
|
||||||
|
if manifest.get(KEY_VERSION) == 1:
|
||||||
|
manifest = _convert_manifest_v1_to_v2(manifest)
|
||||||
|
|
||||||
return manifest, model
|
return manifest, model
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
def _model_config_to_manifest_data(model_config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
|
||||||
await cg.register_component(var, config)
|
|
||||||
|
|
||||||
mic = await cg.get_variable(config[CONF_MICROPHONE])
|
|
||||||
cg.add(var.set_microphone(mic))
|
|
||||||
|
|
||||||
if on_wake_word_detection_config := config.get(CONF_ON_WAKE_WORD_DETECTED):
|
|
||||||
await automation.build_automation(
|
|
||||||
var.get_wake_word_detected_trigger(),
|
|
||||||
[(cg.std_string, "wake_word")],
|
|
||||||
on_wake_word_detection_config,
|
|
||||||
)
|
|
||||||
|
|
||||||
esp32.add_idf_component(
|
|
||||||
name="esp-tflite-micro",
|
|
||||||
repo="https://github.com/espressif/esp-tflite-micro",
|
|
||||||
ref="v1.3.1",
|
|
||||||
)
|
|
||||||
|
|
||||||
cg.add_build_flag("-DTF_LITE_STATIC_MEMORY")
|
|
||||||
cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON")
|
|
||||||
cg.add_build_flag("-DESP_NN")
|
|
||||||
|
|
||||||
model_config = config.get(CONF_MODEL)
|
|
||||||
data = []
|
|
||||||
if model_config[CONF_TYPE] == TYPE_GIT:
|
if model_config[CONF_TYPE] == TYPE_GIT:
|
||||||
# compute path to model file
|
# compute path to model file
|
||||||
key = f"{model_config[CONF_URL]}@{model_config.get(CONF_REF)}"
|
key = f"{model_config[CONF_URL]}@{model_config.get(CONF_REF)}"
|
||||||
@ -338,23 +412,95 @@ async def to_code(config):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("Unsupported config type: {model_config[CONF_TYPE]}")
|
raise ValueError("Unsupported config type: {model_config[CONF_TYPE]}")
|
||||||
|
|
||||||
manifest, data = _load_model_data(file)
|
return _load_model_data(file)
|
||||||
|
|
||||||
|
|
||||||
|
def _feature_step_size_validate(config):
|
||||||
|
features_step_size = None
|
||||||
|
|
||||||
|
for model_parameters in config[CONF_MODELS]:
|
||||||
|
model_config = model_parameters.get(CONF_MODEL)
|
||||||
|
manifest, _ = _model_config_to_manifest_data(model_config)
|
||||||
|
|
||||||
|
model_step_size = manifest[KEY_MICRO][CONF_FEATURE_STEP_SIZE]
|
||||||
|
|
||||||
|
if features_step_size is None:
|
||||||
|
features_step_size = model_step_size
|
||||||
|
elif features_step_size != model_step_size:
|
||||||
|
raise cv.Invalid("Cannot load models with different features step sizes.")
|
||||||
|
|
||||||
|
|
||||||
|
FINAL_VALIDATE_SCHEMA = _feature_step_size_validate
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
mic = await cg.get_variable(config[CONF_MICROPHONE])
|
||||||
|
cg.add(var.set_microphone(mic))
|
||||||
|
|
||||||
|
esp32.add_idf_component(
|
||||||
|
name="esp-tflite-micro",
|
||||||
|
repo="https://github.com/espressif/esp-tflite-micro",
|
||||||
|
ref="v1.3.1",
|
||||||
|
)
|
||||||
|
|
||||||
|
cg.add_build_flag("-DTF_LITE_STATIC_MEMORY")
|
||||||
|
cg.add_build_flag("-DTF_LITE_DISABLE_X86_NEON")
|
||||||
|
cg.add_build_flag("-DESP_NN")
|
||||||
|
|
||||||
|
if on_wake_word_detection_config := config.get(CONF_ON_WAKE_WORD_DETECTED):
|
||||||
|
await automation.build_automation(
|
||||||
|
var.get_wake_word_detected_trigger(),
|
||||||
|
[(cg.std_string, "wake_word")],
|
||||||
|
on_wake_word_detection_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
if vad_model := config.get(CONF_VAD):
|
||||||
|
cg.add_define("USE_MICRO_WAKE_WORD_VAD")
|
||||||
|
|
||||||
|
# Use the general model loading code for the VAD codegen
|
||||||
|
config[CONF_MODELS].append(vad_model)
|
||||||
|
|
||||||
|
for model_parameters in config[CONF_MODELS]:
|
||||||
|
model_config = model_parameters.get(CONF_MODEL)
|
||||||
|
data = []
|
||||||
|
manifest, data = _model_config_to_manifest_data(model_config)
|
||||||
|
|
||||||
rhs = [HexInt(x) for x in data]
|
rhs = [HexInt(x) for x in data]
|
||||||
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
|
prog_arr = cg.progmem_array(model_parameters[CONF_RAW_DATA_ID], rhs)
|
||||||
cg.add(var.set_model_start(prog_arr))
|
|
||||||
|
|
||||||
probability_cutoff = config.get(
|
probability_cutoff = model_parameters.get(
|
||||||
CONF_PROBABILITY_CUTOFF, manifest[KEY_MICRO][CONF_PROBABILITY_CUTOFF]
|
CONF_PROBABILITY_CUTOFF, manifest[KEY_MICRO][CONF_PROBABILITY_CUTOFF]
|
||||||
)
|
)
|
||||||
cg.add(var.set_probability_cutoff(probability_cutoff))
|
sliding_window_size = model_parameters.get(
|
||||||
sliding_window_average_size = config.get(
|
CONF_SLIDING_WINDOW_SIZE,
|
||||||
CONF_SLIDING_WINDOW_AVERAGE_SIZE,
|
manifest[KEY_MICRO][CONF_SLIDING_WINDOW_SIZE],
|
||||||
manifest[KEY_MICRO][CONF_SLIDING_WINDOW_AVERAGE_SIZE],
|
|
||||||
)
|
)
|
||||||
cg.add(var.set_sliding_window_average_size(sliding_window_average_size))
|
|
||||||
|
|
||||||
cg.add(var.set_wake_word(manifest[KEY_WAKE_WORD]))
|
if manifest[KEY_WAKE_WORD] == "vad":
|
||||||
|
cg.add(
|
||||||
|
var.add_vad_model(
|
||||||
|
prog_arr,
|
||||||
|
probability_cutoff,
|
||||||
|
sliding_window_size,
|
||||||
|
manifest[KEY_MICRO][CONF_TENSOR_ARENA_SIZE],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
cg.add(
|
||||||
|
var.add_wake_word_model(
|
||||||
|
prog_arr,
|
||||||
|
probability_cutoff,
|
||||||
|
sliding_window_size,
|
||||||
|
manifest[KEY_WAKE_WORD],
|
||||||
|
manifest[KEY_MICRO][CONF_TENSOR_ARENA_SIZE],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
cg.add(var.set_features_step_size(manifest[KEY_MICRO][CONF_FEATURE_STEP_SIZE]))
|
||||||
|
cg.add_library("kahrendt/ESPMicroSpeechFeatures", "1.0.0")
|
||||||
|
|
||||||
|
|
||||||
MICRO_WAKE_WORD_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(MicroWakeWord)})
|
MICRO_WAKE_WORD_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(MicroWakeWord)})
|
||||||
|
@ -1,493 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef USE_ESP_IDF
|
|
||||||
|
|
||||||
// Converted audio_preprocessor_int8.tflite
|
|
||||||
// From https://github.com/tensorflow/tflite-micro/tree/main/tensorflow/lite/micro/examples/micro_speech/models accessed
|
|
||||||
// January 2024
|
|
||||||
//
|
|
||||||
// Copyright 2023 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.
|
|
||||||
|
|
||||||
namespace esphome {
|
|
||||||
namespace micro_wake_word {
|
|
||||||
|
|
||||||
const unsigned char G_AUDIO_PREPROCESSOR_INT8_TFLITE[] = {
|
|
||||||
0x1c, 0x00, 0x00, 0x00, 0x54, 0x46, 0x4c, 0x33, 0x14, 0x00, 0x20, 0x00, 0x1c, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10,
|
|
||||||
0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x88, 0x00,
|
|
||||||
0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x90, 0x0e, 0x00, 0x00, 0xcc, 0x1f, 0x00, 0x00, 0x03,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe2, 0xeb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00,
|
|
||||||
0x1c, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72, 0x76, 0x69, 0x6e, 0x67,
|
|
||||||
0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x94, 0xff,
|
|
||||||
0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75,
|
|
||||||
0x74, 0x5f, 0x30, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc2, 0xf5, 0xff, 0xff,
|
|
||||||
0x04, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f, 0x66, 0x72, 0x61, 0x6d, 0x65,
|
|
||||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xdc, 0xff, 0xff, 0xff, 0x2d, 0x00,
|
|
||||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x43, 0x4f, 0x4e, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f,
|
|
||||||
0x4e, 0x5f, 0x4d, 0x45, 0x54, 0x41, 0x44, 0x41, 0x54, 0x41, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00,
|
|
||||||
0x08, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x6d, 0x69, 0x6e,
|
|
||||||
0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x00, 0x2e, 0x00,
|
|
||||||
0x00, 0x00, 0x9c, 0x0d, 0x00, 0x00, 0x94, 0x0d, 0x00, 0x00, 0xc4, 0x09, 0x00, 0x00, 0x6c, 0x09, 0x00, 0x00, 0x48,
|
|
||||||
0x09, 0x00, 0x00, 0x34, 0x09, 0x00, 0x00, 0x20, 0x09, 0x00, 0x00, 0x0c, 0x09, 0x00, 0x00, 0xf8, 0x08, 0x00, 0x00,
|
|
||||||
0xec, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x24, 0x07, 0x00, 0x00, 0xc0, 0x06, 0x00, 0x00, 0x38, 0x04, 0x00,
|
|
||||||
0x00, 0xb0, 0x01, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x74, 0x01, 0x00, 0x00, 0x60, 0x01,
|
|
||||||
0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, 0x2c,
|
|
||||||
0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00,
|
|
||||||
0x04, 0x01, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00,
|
|
||||||
0x00, 0xdc, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, 0xcc, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0xbc, 0x00,
|
|
||||||
0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x94,
|
|
||||||
0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff,
|
|
||||||
0x04, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04,
|
|
||||||
0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x08, 0x00,
|
|
||||||
0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
|
||||||
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x31, 0x32, 0x2e, 0x30, 0x00,
|
|
||||||
0x00, 0x56, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x32, 0x2e, 0x38, 0x2e, 0x30, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0xe1, 0xff, 0xff, 0xd8, 0xe1, 0xff, 0xff, 0xdc,
|
|
||||||
0xe1, 0xff, 0xff, 0xe0, 0xe1, 0xff, 0xff, 0xe4, 0xe1, 0xff, 0xff, 0xe8, 0xe1, 0xff, 0xff, 0xec, 0xe1, 0xff, 0xff,
|
|
||||||
0xf0, 0xe1, 0xff, 0xff, 0xf4, 0xe1, 0xff, 0xff, 0xf8, 0xe1, 0xff, 0xff, 0xfc, 0xe1, 0xff, 0xff, 0x00, 0xe2, 0xff,
|
|
||||||
0xff, 0x04, 0xe2, 0xff, 0xff, 0x08, 0xe2, 0xff, 0xff, 0x0c, 0xe2, 0xff, 0xff, 0x10, 0xe2, 0xff, 0xff, 0x14, 0xe2,
|
|
||||||
0xff, 0xff, 0x18, 0xe2, 0xff, 0xff, 0x1c, 0xe2, 0xff, 0xff, 0x20, 0xe2, 0xff, 0xff, 0x24, 0xe2, 0xff, 0xff, 0x28,
|
|
||||||
0xe2, 0xff, 0xff, 0x2c, 0xe2, 0xff, 0xff, 0x30, 0xe2, 0xff, 0xff, 0xd2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
|
|
||||||
0x04, 0x00, 0x00, 0x00, 0x9a, 0x02, 0x00, 0x00, 0xe2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x01, 0x00, 0x00, 0xf2, 0xf7, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0xff,
|
|
||||||
0xff, 0xff, 0x02, 0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x12,
|
|
||||||
0xf8, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x22, 0xf8, 0xff, 0xff,
|
|
||||||
0x04, 0x00, 0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x61, 0x05, 0x00, 0x00, 0x00, 0x00, 0x23, 0x0b, 0x41,
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0e, 0x80, 0x05,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0xd1, 0x0c, 0x63, 0x04, 0x00, 0x00, 0x00, 0x00, 0x34, 0x0c, 0x3f, 0x04, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x81, 0x0c, 0xf7, 0x04, 0x00, 0x00, 0x00, 0x00, 0x9f, 0x0d, 0x77, 0x06, 0x00, 0x00, 0x00, 0x00, 0x7b, 0x0f,
|
|
||||||
0xa9, 0x08, 0x01, 0x02, 0x7f, 0x0b, 0x22, 0x05, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0e, 0xd1, 0x08, 0xdb, 0x02, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x03, 0x0d, 0x4a, 0x07, 0xad, 0x01, 0x2c, 0x0c, 0xc6, 0x06, 0x79, 0x01, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x45, 0x0c, 0x29, 0x07, 0x23, 0x02, 0x34, 0x0d, 0x5b, 0x08, 0x96, 0x03, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x0e, 0x48,
|
|
||||||
0x0a, 0xbd, 0x05, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x0c, 0x88, 0x08, 0x43, 0x04,
|
|
||||||
0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x0b, 0xd3, 0x07, 0xcb, 0x03, 0xd2, 0x0f, 0xe7,
|
|
||||||
0x0b, 0x09, 0x08, 0x39, 0x04, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x0c, 0x14, 0x09,
|
|
||||||
0x75, 0x05, 0xe2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x0e, 0xdd, 0x0a, 0x6b, 0x07, 0x03,
|
|
||||||
0x04, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x0d, 0x09, 0x0a, 0xc9, 0x06, 0x93, 0x03, 0x65, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x0d, 0x25, 0x0a, 0x12, 0x07, 0x07, 0x04, 0x05, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x0a, 0x0e, 0x17, 0x0b, 0x2c, 0x08, 0x49, 0x05, 0x6d, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x98, 0x0f, 0xcb, 0x0c, 0x04, 0x0a, 0x44, 0x07, 0x8b, 0x04, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x0f, 0x87,
|
|
||||||
0x0c, 0xe7, 0x09, 0x4e, 0x07, 0xba, 0x04, 0x2d, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x0f, 0x23, 0x0d, 0xa7, 0x0a,
|
|
||||||
0x30, 0x08, 0xbe, 0x05, 0x52, 0x03, 0xeb, 0x00, 0x89, 0x0e, 0x2c, 0x0c, 0xd4, 0x09, 0x81, 0x07, 0x33, 0x05, 0xe9,
|
|
||||||
0x02, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x0e, 0x29, 0x0c, 0xf1, 0x09, 0xbe, 0x07, 0x90, 0x05, 0x65, 0x03,
|
|
||||||
0x3f, 0x01, 0x1d, 0x0f, 0xff, 0x0c, 0xe5, 0x0a, 0xcf, 0x08, 0xbc, 0x06, 0xae, 0x04, 0xa3, 0x02, 0x9c, 0x00, 0x99,
|
|
||||||
0x0e, 0x99, 0x0c, 0x9d, 0x0a, 0xa4, 0x08, 0xaf, 0x06, 0xbd, 0x04, 0xcf, 0x02, 0xe4, 0x00, 0xfc, 0x0e, 0x17, 0x0d,
|
|
||||||
0x36, 0x0b, 0x57, 0x09, 0x7c, 0x07, 0xa4, 0x05, 0xcf, 0x03, 0xfd, 0x01, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x62, 0x0e, 0x98, 0x0c, 0xd2, 0x0a, 0x0e, 0x09, 0x4d, 0x07, 0x8f, 0x05, 0xd4, 0x03, 0x1b, 0x02,
|
|
||||||
0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb1, 0x0e, 0x00, 0x0d, 0x52, 0x0b, 0xa6, 0x09, 0xfd, 0x07, 0x56, 0x06, 0xb1,
|
|
||||||
0x04, 0x0f, 0x03, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd2, 0x0f, 0x37, 0x0e, 0x9e, 0x0c,
|
|
||||||
0x08, 0x0b, 0x73, 0x09, 0xe1, 0x07, 0x52, 0x06, 0xc4, 0x04, 0x38, 0x03, 0xaf, 0x01, 0x28, 0x00, 0xa3, 0x0e, 0x1f,
|
|
||||||
0x0d, 0x9e, 0x0b, 0x1f, 0x0a, 0xa2, 0x08, 0x27, 0x07, 0xae, 0x05, 0x37, 0x04, 0xc2, 0x02, 0x4e, 0x01, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0xdd, 0x0f, 0x6d, 0x0e, 0xff, 0x0c, 0x93, 0x0b, 0x29, 0x0a, 0xc1, 0x08, 0x5a, 0x07, 0xf5, 0x05, 0x92,
|
|
||||||
0x04, 0x30, 0x03, 0xd1, 0x01, 0x73, 0x00, 0x16, 0x0f, 0xbc, 0x0d, 0x62, 0x0c, 0x0b, 0x0b, 0xb5, 0x09, 0x61, 0x08,
|
|
||||||
0x0e, 0x07, 0xbd, 0x05, 0x6d, 0x04, 0x1f, 0x03, 0xd3, 0x01, 0x88, 0x00, 0x3e, 0x0f, 0xf6, 0x0d, 0xaf, 0x0c, 0x6a,
|
|
||||||
0x0b, 0x27, 0x0a, 0xe4, 0x08, 0xa3, 0x07, 0x64, 0x06, 0x26, 0x05, 0xe9, 0x03, 0xae, 0x02, 0x74, 0x01, 0x3b, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x0f, 0xce, 0x0d, 0x99, 0x0c, 0x66, 0x0b, 0x34, 0x0a, 0x03,
|
|
||||||
0x09, 0xd3, 0x07, 0xa5, 0x06, 0x78, 0x05, 0x4c, 0x04, 0x22, 0x03, 0xf8, 0x01, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0xa9, 0x0f, 0x83, 0x0e, 0x5f, 0x0d, 0x3b, 0x0c, 0x19, 0x0b, 0xf8, 0x09, 0xd8, 0x08, 0xb9, 0x07, 0x9b, 0x06, 0x7e,
|
|
||||||
0x05, 0x63, 0x04, 0x48, 0x03, 0x2f, 0x02, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xfa, 0xff, 0xff, 0x04, 0x00,
|
|
||||||
0x00, 0x00, 0x78, 0x02, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x0a, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x04, 0xbe, 0x0e, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x7f, 0x0a, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x2e, 0x03, 0x9c, 0x0b, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x03, 0xc0, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x7e,
|
|
||||||
0x03, 0x08, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x88, 0x09, 0x00, 0x00, 0x00, 0x00, 0x84, 0x00, 0x56, 0x07,
|
|
||||||
0xfe, 0x0d, 0x80, 0x04, 0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x16, 0x01, 0x2e, 0x07, 0x24, 0x0d, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0xfc, 0x02, 0xb5, 0x08, 0x52, 0x0e, 0xd3, 0x03, 0x39, 0x09, 0x86, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xba, 0x03,
|
|
||||||
0xd6, 0x08, 0xdc, 0x0d, 0xcb, 0x02, 0xa4, 0x07, 0x69, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x01, 0xb7, 0x05, 0x42,
|
|
||||||
0x0a, 0xba, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x03, 0x77, 0x07, 0xbc, 0x0b, 0xf1, 0x0f,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x04, 0x2c, 0x08, 0x34, 0x0c, 0x2d, 0x00, 0x18, 0x04, 0xf6,
|
|
||||||
0x07, 0xc6, 0x0b, 0x89, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0xeb, 0x06, 0x8a, 0x0a,
|
|
||||||
0x1d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa5, 0x01, 0x22, 0x05, 0x94, 0x08, 0xfc, 0x0b, 0x59,
|
|
||||||
0x0f, 0x00, 0x00, 0x00, 0x00, 0xac, 0x02, 0xf6, 0x05, 0x36, 0x09, 0x6c, 0x0c, 0x9a, 0x0f, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0xbe, 0x02, 0xda, 0x05, 0xed, 0x08, 0xf8, 0x0b, 0xfa, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xf5,
|
|
||||||
0x01, 0xe8, 0x04, 0xd3, 0x07, 0xb6, 0x0a, 0x92, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00,
|
|
||||||
0x34, 0x03, 0xfb, 0x05, 0xbb, 0x08, 0x74, 0x0b, 0x27, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x78, 0x03, 0x18,
|
|
||||||
0x06, 0xb1, 0x08, 0x45, 0x0b, 0xd2, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x5a, 0x00, 0xdc, 0x02, 0x58, 0x05, 0xcf, 0x07,
|
|
||||||
0x41, 0x0a, 0xad, 0x0c, 0x14, 0x0f, 0x76, 0x01, 0xd3, 0x03, 0x2b, 0x06, 0x7e, 0x08, 0xcc, 0x0a, 0x16, 0x0d, 0x5a,
|
|
||||||
0x0f, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x01, 0xd6, 0x03, 0x0e, 0x06, 0x41, 0x08, 0x6f, 0x0a, 0x9a, 0x0c, 0xc0, 0x0e,
|
|
||||||
0xe2, 0x00, 0x00, 0x03, 0x1a, 0x05, 0x30, 0x07, 0x43, 0x09, 0x51, 0x0b, 0x5c, 0x0d, 0x63, 0x0f, 0x66, 0x01, 0x66,
|
|
||||||
0x03, 0x62, 0x05, 0x5b, 0x07, 0x50, 0x09, 0x42, 0x0b, 0x30, 0x0d, 0x1b, 0x0f, 0x03, 0x01, 0xe8, 0x02, 0xc9, 0x04,
|
|
||||||
0xa8, 0x06, 0x83, 0x08, 0x5b, 0x0a, 0x30, 0x0c, 0x02, 0x0e, 0xd1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x9d, 0x01, 0x67, 0x03, 0x2d, 0x05, 0xf1, 0x06, 0xb2, 0x08, 0x70, 0x0a, 0x2b, 0x0c, 0xe4, 0x0d, 0x9a, 0x0f,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0xff, 0x02, 0xad, 0x04, 0x59, 0x06, 0x02, 0x08, 0xa9, 0x09, 0x4e, 0x0b, 0xf0,
|
|
||||||
0x0c, 0x90, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x00, 0xc8, 0x01, 0x61, 0x03, 0xf7, 0x04,
|
|
||||||
0x8c, 0x06, 0x1e, 0x08, 0xad, 0x09, 0x3b, 0x0b, 0xc7, 0x0c, 0x50, 0x0e, 0xd7, 0x0f, 0x5c, 0x01, 0xe0, 0x02, 0x61,
|
|
||||||
0x04, 0xe0, 0x05, 0x5d, 0x07, 0xd8, 0x08, 0x51, 0x0a, 0xc8, 0x0b, 0x3d, 0x0d, 0xb1, 0x0e, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x22, 0x00, 0x92, 0x01, 0x00, 0x03, 0x6c, 0x04, 0xd6, 0x05, 0x3e, 0x07, 0xa5, 0x08, 0x0a, 0x0a, 0x6d, 0x0b, 0xcf,
|
|
||||||
0x0c, 0x2e, 0x0e, 0x8c, 0x0f, 0xe9, 0x00, 0x43, 0x02, 0x9d, 0x03, 0xf4, 0x04, 0x4a, 0x06, 0x9e, 0x07, 0xf1, 0x08,
|
|
||||||
0x42, 0x0a, 0x92, 0x0b, 0xe0, 0x0c, 0x2c, 0x0e, 0x77, 0x0f, 0xc1, 0x00, 0x09, 0x02, 0x50, 0x03, 0x95, 0x04, 0xd8,
|
|
||||||
0x05, 0x1b, 0x07, 0x5c, 0x08, 0x9b, 0x09, 0xd9, 0x0a, 0x16, 0x0c, 0x51, 0x0d, 0x8b, 0x0e, 0xc4, 0x0f, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x31, 0x02, 0x66, 0x03, 0x99, 0x04, 0xcb, 0x05, 0xfc, 0x06, 0x2c,
|
|
||||||
0x08, 0x5a, 0x09, 0x87, 0x0a, 0xb3, 0x0b, 0xdd, 0x0c, 0x07, 0x0e, 0x2f, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00,
|
|
||||||
0x7c, 0x01, 0xa0, 0x02, 0xc4, 0x03, 0xe6, 0x04, 0x07, 0x06, 0x27, 0x07, 0x46, 0x08, 0x64, 0x09, 0x81, 0x0a, 0x9c,
|
|
||||||
0x0b, 0xb7, 0x0c, 0xd0, 0x0d, 0xe8, 0x0e, 0x00, 0x10, 0x00, 0x00, 0x2a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
|
|
||||||
0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x06, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0a, 0x00, 0x0c, 0x00, 0x0e, 0x00, 0x10,
|
|
||||||
0x00, 0x12, 0x00, 0x16, 0x00, 0x18, 0x00, 0x1a, 0x00, 0x1e, 0x00, 0x20, 0x00, 0x24, 0x00, 0x26, 0x00, 0x2a, 0x00,
|
|
||||||
0x2e, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3a, 0x00, 0x40, 0x00, 0x44, 0x00, 0x4a, 0x00, 0x4e, 0x00, 0x54, 0x00, 0x5a,
|
|
||||||
0x00, 0x62, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00, 0x92, 0x00, 0x9a, 0x00, 0xa6, 0x00,
|
|
||||||
0xb0, 0x00, 0xbc, 0x00, 0xc8, 0x00, 0xd4, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x8a, 0xfd, 0xff, 0xff, 0x04, 0x00, 0x00,
|
|
||||||
0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x14, 0x00, 0x18, 0x00,
|
|
||||||
0x1c, 0x00, 0x20, 0x00, 0x24, 0x00, 0x28, 0x00, 0x2c, 0x00, 0x30, 0x00, 0x34, 0x00, 0x38, 0x00, 0x3c, 0x00, 0x44,
|
|
||||||
0x00, 0x4c, 0x00, 0x50, 0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x70, 0x00, 0x78, 0x00, 0x80, 0x00, 0x88, 0x00,
|
|
||||||
0x90, 0x00, 0x98, 0x00, 0xa0, 0x00, 0xa8, 0x00, 0xb0, 0x00, 0xb8, 0x00, 0xc4, 0x00, 0xd0, 0x00, 0xdc, 0x00, 0xe8,
|
|
||||||
0x00, 0xf4, 0x00, 0x00, 0x01, 0x0c, 0x01, 0x1c, 0x01, 0x2c, 0x01, 0x00, 0x00, 0xea, 0xfd, 0xff, 0xff, 0x04, 0x00,
|
|
||||||
0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04,
|
|
||||||
0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00,
|
|
||||||
0x08, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08,
|
|
||||||
0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00,
|
|
||||||
0x0c, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0x10, 0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x4a, 0xfe, 0xff, 0xff, 0x04,
|
|
||||||
0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x7c, 0x7f, 0x79, 0x7f, 0x76, 0x7f, 0xfa, 0xff, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x70, 0x7f, 0xf4, 0xff, 0x00, 0x00, 0x00, 0x00, 0x64, 0x7f, 0xe9, 0xff, 0xfe, 0xff, 0x00, 0x00, 0x4b, 0x7f, 0xd0,
|
|
||||||
0xff, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x7f, 0xa0, 0xff, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x7e, 0x42, 0xff, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0xfd, 0x7d, 0x86, 0xfe, 0x04, 0x00, 0x00, 0x00, 0x87, 0x7c, 0x1d, 0xfd, 0x12, 0x00, 0x00, 0x00, 0xb6,
|
|
||||||
0x79, 0x7f, 0xfa, 0x3e, 0x00, 0x00, 0x00, 0x73, 0x74, 0xf9, 0xf5, 0xca, 0x00, 0x00, 0x00, 0x36, 0x6b, 0x33, 0xef,
|
|
||||||
0x32, 0x02, 0x00, 0x00, 0x9b, 0x5c, 0x87, 0xe7, 0xce, 0x04, 0x00, 0x00, 0xf0, 0x48, 0xde, 0xe2, 0xa0, 0x07, 0x00,
|
|
||||||
0x00, 0x6e, 0x33, 0x8a, 0xe4, 0xa4, 0x08, 0x00, 0x00, 0x9c, 0x20, 0x22, 0xeb, 0x4c, 0x07, 0x00, 0x00, 0x0a, 0x13,
|
|
||||||
0x7d, 0xf2, 0x02, 0x05, 0x00, 0x00, 0x89, 0x0a, 0x17, 0xf8, 0x06, 0x03, 0x00, 0x00, 0xa6, 0x05, 0xa0, 0xfb, 0xb4,
|
|
||||||
0x01, 0x00, 0x00, 0xfa, 0x02, 0xac, 0xfd, 0xe8, 0x00, 0x00, 0x00, 0x8e, 0x01, 0xc7, 0xfe, 0x7a, 0x00, 0x00, 0x00,
|
|
||||||
0xcf, 0x00, 0x5c, 0xff, 0x40, 0x00, 0x00, 0x00, 0x6b, 0x00, 0xab, 0xff, 0x22, 0x00, 0x00, 0x00, 0x38, 0x00, 0xd3,
|
|
||||||
0xff, 0x12, 0x00, 0x00, 0x00, 0x1d, 0x00, 0xea, 0xff, 0x08, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xf3, 0xff, 0x06, 0x00,
|
|
||||||
0x00, 0x00, 0x08, 0x00, 0xf8, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02,
|
|
||||||
0x00, 0xfd, 0xff, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfd, 0xff,
|
|
||||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00,
|
|
||||||
0x00, 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00,
|
|
||||||
0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x72, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x82, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4d, 0x01, 0x00, 0x00,
|
|
||||||
0x92, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0xff, 0xff, 0xff, 0x04, 0x00,
|
|
||||||
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x08, 0x00,
|
|
||||||
0x04, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
|
|
||||||
0x00, 0x02, 0x00, 0x04, 0x00, 0x05, 0x00, 0x07, 0x00, 0x0a, 0x00, 0x0d, 0x00, 0x10, 0x00, 0x13, 0x00, 0x17, 0x00,
|
|
||||||
0x1b, 0x00, 0x20, 0x00, 0x25, 0x00, 0x2a, 0x00, 0x30, 0x00, 0x35, 0x00, 0x3c, 0x00, 0x42, 0x00, 0x49, 0x00, 0x51,
|
|
||||||
0x00, 0x58, 0x00, 0x60, 0x00, 0x68, 0x00, 0x71, 0x00, 0x7a, 0x00, 0x83, 0x00, 0x8d, 0x00, 0x97, 0x00, 0xa1, 0x00,
|
|
||||||
0xac, 0x00, 0xb7, 0x00, 0xc2, 0x00, 0xcd, 0x00, 0xd9, 0x00, 0xe5, 0x00, 0xf2, 0x00, 0xff, 0x00, 0x0c, 0x01, 0x19,
|
|
||||||
0x01, 0x27, 0x01, 0x35, 0x01, 0x43, 0x01, 0x52, 0x01, 0x61, 0x01, 0x70, 0x01, 0x7f, 0x01, 0x8f, 0x01, 0x9f, 0x01,
|
|
||||||
0xaf, 0x01, 0xc0, 0x01, 0xd1, 0x01, 0xe2, 0x01, 0xf3, 0x01, 0x05, 0x02, 0x17, 0x02, 0x29, 0x02, 0x3c, 0x02, 0x4e,
|
|
||||||
0x02, 0x61, 0x02, 0x75, 0x02, 0x88, 0x02, 0x9c, 0x02, 0xb0, 0x02, 0xc4, 0x02, 0xd8, 0x02, 0xed, 0x02, 0x02, 0x03,
|
|
||||||
0x17, 0x03, 0x2c, 0x03, 0x41, 0x03, 0x57, 0x03, 0x6d, 0x03, 0x83, 0x03, 0x99, 0x03, 0xb0, 0x03, 0xc7, 0x03, 0xdd,
|
|
||||||
0x03, 0xf4, 0x03, 0x0c, 0x04, 0x23, 0x04, 0x3b, 0x04, 0x52, 0x04, 0x6a, 0x04, 0x82, 0x04, 0x9a, 0x04, 0xb3, 0x04,
|
|
||||||
0xcb, 0x04, 0xe4, 0x04, 0xfd, 0x04, 0x16, 0x05, 0x2f, 0x05, 0x48, 0x05, 0x61, 0x05, 0x7a, 0x05, 0x94, 0x05, 0xad,
|
|
||||||
0x05, 0xc7, 0x05, 0xe1, 0x05, 0xfb, 0x05, 0x15, 0x06, 0x2f, 0x06, 0x49, 0x06, 0x63, 0x06, 0x7e, 0x06, 0x98, 0x06,
|
|
||||||
0xb2, 0x06, 0xcd, 0x06, 0xe7, 0x06, 0x02, 0x07, 0x1d, 0x07, 0x37, 0x07, 0x52, 0x07, 0x6d, 0x07, 0x87, 0x07, 0xa2,
|
|
||||||
0x07, 0xbd, 0x07, 0xd8, 0x07, 0xf3, 0x07, 0x0d, 0x08, 0x28, 0x08, 0x43, 0x08, 0x5e, 0x08, 0x79, 0x08, 0x93, 0x08,
|
|
||||||
0xae, 0x08, 0xc9, 0x08, 0xe3, 0x08, 0xfe, 0x08, 0x19, 0x09, 0x33, 0x09, 0x4e, 0x09, 0x68, 0x09, 0x82, 0x09, 0x9d,
|
|
||||||
0x09, 0xb7, 0x09, 0xd1, 0x09, 0xeb, 0x09, 0x05, 0x0a, 0x1f, 0x0a, 0x39, 0x0a, 0x53, 0x0a, 0x6c, 0x0a, 0x86, 0x0a,
|
|
||||||
0x9f, 0x0a, 0xb8, 0x0a, 0xd1, 0x0a, 0xea, 0x0a, 0x03, 0x0b, 0x1c, 0x0b, 0x35, 0x0b, 0x4d, 0x0b, 0x66, 0x0b, 0x7e,
|
|
||||||
0x0b, 0x96, 0x0b, 0xae, 0x0b, 0xc5, 0x0b, 0xdd, 0x0b, 0xf4, 0x0b, 0x0c, 0x0c, 0x23, 0x0c, 0x39, 0x0c, 0x50, 0x0c,
|
|
||||||
0x67, 0x0c, 0x7d, 0x0c, 0x93, 0x0c, 0xa9, 0x0c, 0xbf, 0x0c, 0xd4, 0x0c, 0xe9, 0x0c, 0xfe, 0x0c, 0x13, 0x0d, 0x28,
|
|
||||||
0x0d, 0x3c, 0x0d, 0x50, 0x0d, 0x64, 0x0d, 0x78, 0x0d, 0x8b, 0x0d, 0x9f, 0x0d, 0xb2, 0x0d, 0xc4, 0x0d, 0xd7, 0x0d,
|
|
||||||
0xe9, 0x0d, 0xfb, 0x0d, 0x0d, 0x0e, 0x1e, 0x0e, 0x2f, 0x0e, 0x40, 0x0e, 0x51, 0x0e, 0x61, 0x0e, 0x71, 0x0e, 0x81,
|
|
||||||
0x0e, 0x90, 0x0e, 0x9f, 0x0e, 0xae, 0x0e, 0xbd, 0x0e, 0xcb, 0x0e, 0xd9, 0x0e, 0xe7, 0x0e, 0xf4, 0x0e, 0x01, 0x0f,
|
|
||||||
0x0e, 0x0f, 0x1b, 0x0f, 0x27, 0x0f, 0x33, 0x0f, 0x3e, 0x0f, 0x49, 0x0f, 0x54, 0x0f, 0x5f, 0x0f, 0x69, 0x0f, 0x73,
|
|
||||||
0x0f, 0x7d, 0x0f, 0x86, 0x0f, 0x8f, 0x0f, 0x98, 0x0f, 0xa0, 0x0f, 0xa8, 0x0f, 0xaf, 0x0f, 0xb7, 0x0f, 0xbe, 0x0f,
|
|
||||||
0xc4, 0x0f, 0xcb, 0x0f, 0xd0, 0x0f, 0xd6, 0x0f, 0xdb, 0x0f, 0xe0, 0x0f, 0xe5, 0x0f, 0xe9, 0x0f, 0xed, 0x0f, 0xf0,
|
|
||||||
0x0f, 0xf3, 0x0f, 0xf6, 0x0f, 0xf9, 0x0f, 0xfb, 0x0f, 0xfc, 0x0f, 0xfe, 0x0f, 0xff, 0x0f, 0x00, 0x10, 0x00, 0x10,
|
|
||||||
0x00, 0x10, 0x00, 0x10, 0xff, 0x0f, 0xfe, 0x0f, 0xfc, 0x0f, 0xfb, 0x0f, 0xf9, 0x0f, 0xf6, 0x0f, 0xf3, 0x0f, 0xf0,
|
|
||||||
0x0f, 0xed, 0x0f, 0xe9, 0x0f, 0xe5, 0x0f, 0xe0, 0x0f, 0xdb, 0x0f, 0xd6, 0x0f, 0xd0, 0x0f, 0xcb, 0x0f, 0xc4, 0x0f,
|
|
||||||
0xbe, 0x0f, 0xb7, 0x0f, 0xaf, 0x0f, 0xa8, 0x0f, 0xa0, 0x0f, 0x98, 0x0f, 0x8f, 0x0f, 0x86, 0x0f, 0x7d, 0x0f, 0x73,
|
|
||||||
0x0f, 0x69, 0x0f, 0x5f, 0x0f, 0x54, 0x0f, 0x49, 0x0f, 0x3e, 0x0f, 0x33, 0x0f, 0x27, 0x0f, 0x1b, 0x0f, 0x0e, 0x0f,
|
|
||||||
0x01, 0x0f, 0xf4, 0x0e, 0xe7, 0x0e, 0xd9, 0x0e, 0xcb, 0x0e, 0xbd, 0x0e, 0xae, 0x0e, 0x9f, 0x0e, 0x90, 0x0e, 0x81,
|
|
||||||
0x0e, 0x71, 0x0e, 0x61, 0x0e, 0x51, 0x0e, 0x40, 0x0e, 0x2f, 0x0e, 0x1e, 0x0e, 0x0d, 0x0e, 0xfb, 0x0d, 0xe9, 0x0d,
|
|
||||||
0xd7, 0x0d, 0xc4, 0x0d, 0xb2, 0x0d, 0x9f, 0x0d, 0x8b, 0x0d, 0x78, 0x0d, 0x64, 0x0d, 0x50, 0x0d, 0x3c, 0x0d, 0x28,
|
|
||||||
0x0d, 0x13, 0x0d, 0xfe, 0x0c, 0xe9, 0x0c, 0xd4, 0x0c, 0xbf, 0x0c, 0xa9, 0x0c, 0x93, 0x0c, 0x7d, 0x0c, 0x67, 0x0c,
|
|
||||||
0x50, 0x0c, 0x39, 0x0c, 0x23, 0x0c, 0x0c, 0x0c, 0xf4, 0x0b, 0xdd, 0x0b, 0xc5, 0x0b, 0xae, 0x0b, 0x96, 0x0b, 0x7e,
|
|
||||||
0x0b, 0x66, 0x0b, 0x4d, 0x0b, 0x35, 0x0b, 0x1c, 0x0b, 0x03, 0x0b, 0xea, 0x0a, 0xd1, 0x0a, 0xb8, 0x0a, 0x9f, 0x0a,
|
|
||||||
0x86, 0x0a, 0x6c, 0x0a, 0x53, 0x0a, 0x39, 0x0a, 0x1f, 0x0a, 0x05, 0x0a, 0xeb, 0x09, 0xd1, 0x09, 0xb7, 0x09, 0x9d,
|
|
||||||
0x09, 0x82, 0x09, 0x68, 0x09, 0x4e, 0x09, 0x33, 0x09, 0x19, 0x09, 0xfe, 0x08, 0xe3, 0x08, 0xc9, 0x08, 0xae, 0x08,
|
|
||||||
0x93, 0x08, 0x79, 0x08, 0x5e, 0x08, 0x43, 0x08, 0x28, 0x08, 0x0d, 0x08, 0xf3, 0x07, 0xd8, 0x07, 0xbd, 0x07, 0xa2,
|
|
||||||
0x07, 0x87, 0x07, 0x6d, 0x07, 0x52, 0x07, 0x37, 0x07, 0x1d, 0x07, 0x02, 0x07, 0xe7, 0x06, 0xcd, 0x06, 0xb2, 0x06,
|
|
||||||
0x98, 0x06, 0x7e, 0x06, 0x63, 0x06, 0x49, 0x06, 0x2f, 0x06, 0x15, 0x06, 0xfb, 0x05, 0xe1, 0x05, 0xc7, 0x05, 0xad,
|
|
||||||
0x05, 0x94, 0x05, 0x7a, 0x05, 0x61, 0x05, 0x48, 0x05, 0x2f, 0x05, 0x16, 0x05, 0xfd, 0x04, 0xe4, 0x04, 0xcb, 0x04,
|
|
||||||
0xb3, 0x04, 0x9a, 0x04, 0x82, 0x04, 0x6a, 0x04, 0x52, 0x04, 0x3b, 0x04, 0x23, 0x04, 0x0c, 0x04, 0xf4, 0x03, 0xdd,
|
|
||||||
0x03, 0xc7, 0x03, 0xb0, 0x03, 0x99, 0x03, 0x83, 0x03, 0x6d, 0x03, 0x57, 0x03, 0x41, 0x03, 0x2c, 0x03, 0x17, 0x03,
|
|
||||||
0x02, 0x03, 0xed, 0x02, 0xd8, 0x02, 0xc4, 0x02, 0xb0, 0x02, 0x9c, 0x02, 0x88, 0x02, 0x75, 0x02, 0x61, 0x02, 0x4e,
|
|
||||||
0x02, 0x3c, 0x02, 0x29, 0x02, 0x17, 0x02, 0x05, 0x02, 0xf3, 0x01, 0xe2, 0x01, 0xd1, 0x01, 0xc0, 0x01, 0xaf, 0x01,
|
|
||||||
0x9f, 0x01, 0x8f, 0x01, 0x7f, 0x01, 0x70, 0x01, 0x61, 0x01, 0x52, 0x01, 0x43, 0x01, 0x35, 0x01, 0x27, 0x01, 0x19,
|
|
||||||
0x01, 0x0c, 0x01, 0xff, 0x00, 0xf2, 0x00, 0xe5, 0x00, 0xd9, 0x00, 0xcd, 0x00, 0xc2, 0x00, 0xb7, 0x00, 0xac, 0x00,
|
|
||||||
0xa1, 0x00, 0x97, 0x00, 0x8d, 0x00, 0x83, 0x00, 0x7a, 0x00, 0x71, 0x00, 0x68, 0x00, 0x60, 0x00, 0x58, 0x00, 0x51,
|
|
||||||
0x00, 0x49, 0x00, 0x42, 0x00, 0x3c, 0x00, 0x35, 0x00, 0x30, 0x00, 0x2a, 0x00, 0x25, 0x00, 0x20, 0x00, 0x1b, 0x00,
|
|
||||||
0x17, 0x00, 0x13, 0x00, 0x10, 0x00, 0x0d, 0x00, 0x0a, 0x00, 0x07, 0x00, 0x05, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0xee, 0xff, 0xff, 0x38, 0xee, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x4d, 0x4c,
|
|
||||||
0x49, 0x52, 0x20, 0x43, 0x6f, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x2e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x04, 0x00,
|
|
||||||
0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0xf4, 0x05, 0x00, 0x00, 0xf8, 0x05, 0x00,
|
|
||||||
0x00, 0xfc, 0x05, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x6d, 0x61, 0x69, 0x6e, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00,
|
|
||||||
0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x68, 0x05, 0x00, 0x00, 0x24, 0x05, 0x00, 0x00, 0xc8, 0x04, 0x00, 0x00, 0x70,
|
|
||||||
0x04, 0x00, 0x00, 0x4c, 0x04, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0xc8, 0x03, 0x00, 0x00, 0xa4, 0x03, 0x00, 0x00,
|
|
||||||
0x4c, 0x03, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00, 0x6c, 0x01, 0x00,
|
|
||||||
0x00, 0x48, 0x01, 0x00, 0x00, 0x14, 0x01, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x78, 0x00,
|
|
||||||
0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xf6, 0xfa, 0xff, 0xff, 0x0c,
|
|
||||||
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x16, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00,
|
|
||||||
0x00, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
||||||
0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3a, 0xfb, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00,
|
|
||||||
0x0e, 0x00, 0x00, 0x00, 0xa6, 0xfc, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00, 0x00,
|
|
||||||
0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x68, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x27, 0x00,
|
|
||||||
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xd6, 0xfc, 0xff, 0xff, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
|
|
||||||
0x98, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00,
|
|
||||||
0x00, 0x12, 0x00, 0x00, 0x00, 0x06, 0xfd, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x10, 0x00,
|
|
||||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xc8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x25,
|
|
||||||
0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x36, 0xfd, 0xff, 0xff,
|
|
||||||
0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00,
|
|
||||||
0x00, 0xf8, 0xef, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x23, 0x00,
|
|
||||||
0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1e, 0xfc, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00,
|
|
||||||
0x84, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00,
|
|
||||||
0x00, 0x30, 0x00, 0x00, 0x00, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x63, 0x6f, 0x72, 0x72, 0x65, 0x63, 0x74, 0x69,
|
|
||||||
0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x73, 0x63, 0x61, 0x6c,
|
|
||||||
0x65, 0x00, 0x02, 0x24, 0x0f, 0x02, 0x01, 0x02, 0x03, 0x40, 0x04, 0x04, 0x04, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x22, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0xdc, 0xfc, 0xff, 0xff, 0x10, 0x00, 0x00,
|
|
||||||
0x00, 0x24, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x73, 0x6e,
|
|
||||||
0x72, 0x5f, 0x73, 0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x0b, 0x01, 0x01, 0x01, 0x06, 0x04, 0x02, 0x24, 0x01, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00,
|
|
||||||
0x08, 0x00, 0x00, 0x00, 0x20, 0xfd, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00,
|
|
||||||
0x00, 0x0a, 0x00, 0x00, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f,
|
|
||||||
0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67,
|
|
||||||
0x00, 0x61, 0x6c, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e,
|
|
||||||
0x67, 0x00, 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x00, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x69, 0x67, 0x6e,
|
|
||||||
0x61, 0x6c, 0x5f, 0x72, 0x65, 0x6d, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68,
|
|
||||||
0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x6f, 0x6e, 0x65, 0x5f, 0x6d, 0x69, 0x6e, 0x75, 0x73, 0x5f, 0x73, 0x6d,
|
|
||||||
0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73, 0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x00, 0x73,
|
|
||||||
0x6d, 0x6f, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x5f, 0x62, 0x69, 0x74, 0x73, 0x00, 0x73, 0x70, 0x65, 0x63, 0x74,
|
|
||||||
0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x62, 0x69, 0x74,
|
|
||||||
0x73, 0x00, 0x09, 0xa5, 0x88, 0x75, 0x6d, 0x59, 0x4d, 0x3a, 0x31, 0x23, 0x09, 0x00, 0x01, 0x00, 0x09, 0x00, 0x29,
|
|
||||||
0x3c, 0xd7, 0x03, 0x00, 0x00, 0x33, 0x03, 0x28, 0x00, 0x67, 0x3e, 0x99, 0x01, 0x0a, 0x00, 0x0e, 0x00, 0x05, 0x05,
|
|
||||||
0x69, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x1b, 0x25, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00,
|
|
||||||
0x00, 0x20, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x20, 0xfe, 0xff, 0xff, 0x10, 0x00,
|
|
||||||
0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
||||||
0x1d, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x54, 0xfe, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
|
|
||||||
0x00, 0x2c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x6e, 0x75, 0x6d, 0x5f, 0x63, 0x68,
|
|
||||||
0x61, 0x6e, 0x6e, 0x65, 0x6c, 0x73, 0x00, 0x01, 0x0e, 0x01, 0x01, 0x01, 0x28, 0x04, 0x02, 0x24, 0x01, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00,
|
|
||||||
0x0c, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x62, 0xfe, 0xff,
|
|
||||||
0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1c, 0x00,
|
|
||||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0xca, 0xff, 0xff, 0xff, 0x14, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x0a, 0x10, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x8c, 0xf2, 0xff, 0xff,
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00,
|
|
||||||
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x18, 0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x0b, 0x00,
|
|
||||||
0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xd0, 0xf2, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
|
|
||||||
0x04, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
|
|
||||||
0x00, 0xfe, 0xfe, 0xff, 0xff, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
||||||
0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x64, 0xff, 0xff, 0xff, 0x10,
|
|
||||||
0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00,
|
|
||||||
0x65, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x00, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x69, 0x6e, 0x64,
|
|
||||||
0x65, 0x78, 0x00, 0x02, 0x17, 0x0e, 0x00, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0xf1, 0x00, 0x05, 0x00, 0x05, 0x05,
|
|
||||||
0x06, 0x25, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17,
|
|
||||||
0x00, 0x00, 0x00, 0xb8, 0xff, 0xff, 0xff, 0x10, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00,
|
|
||||||
0x03, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x54, 0x00, 0x66, 0x66, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74,
|
|
||||||
0x68, 0x00, 0x02, 0x0e, 0x0d, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x07, 0x00, 0x00, 0x02, 0x05, 0x05, 0x06, 0x25,
|
|
||||||
0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x10,
|
|
||||||
0x00, 0x14, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00, 0x00, 0x00,
|
|
||||||
0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x24, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x16, 0x00,
|
|
||||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08,
|
|
||||||
0x00, 0x04, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00,
|
|
||||||
0x00, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x10, 0x00,
|
|
||||||
0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x73,
|
|
||||||
0x68, 0x69, 0x66, 0x74, 0x00, 0x01, 0x07, 0x01, 0x01, 0x01, 0x0c, 0x04, 0x02, 0x24, 0x01, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x13, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
||||||
0x00, 0x2a, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xc4, 0x0a,
|
|
||||||
0x00, 0x00, 0x74, 0x0a, 0x00, 0x00, 0x3c, 0x0a, 0x00, 0x00, 0x04, 0x0a, 0x00, 0x00, 0xd0, 0x09, 0x00, 0x00, 0x88,
|
|
||||||
0x09, 0x00, 0x00, 0x40, 0x09, 0x00, 0x00, 0xfc, 0x08, 0x00, 0x00, 0xb8, 0x08, 0x00, 0x00, 0x6c, 0x08, 0x00, 0x00,
|
|
||||||
0x20, 0x08, 0x00, 0x00, 0xd4, 0x07, 0x00, 0x00, 0x88, 0x07, 0x00, 0x00, 0x3c, 0x07, 0x00, 0x00, 0xf8, 0x06, 0x00,
|
|
||||||
0x00, 0xb8, 0x06, 0x00, 0x00, 0x84, 0x06, 0x00, 0x00, 0x50, 0x06, 0x00, 0x00, 0x1c, 0x06, 0x00, 0x00, 0xd8, 0x05,
|
|
||||||
0x00, 0x00, 0xa0, 0x05, 0x00, 0x00, 0x58, 0x05, 0x00, 0x00, 0x14, 0x05, 0x00, 0x00, 0xd8, 0x04, 0x00, 0x00, 0x98,
|
|
||||||
0x04, 0x00, 0x00, 0x60, 0x04, 0x00, 0x00, 0x20, 0x04, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x00,
|
|
||||||
0x6c, 0x03, 0x00, 0x00, 0x1c, 0x03, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x68, 0x02, 0x00, 0x00, 0x2c, 0x02, 0x00,
|
|
||||||
0x00, 0xe4, 0x01, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x08, 0x01,
|
|
||||||
0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xfe,
|
|
||||||
0xf5, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x09, 0x20, 0x00, 0x00, 0x00, 0x44, 0xf5, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x50, 0x61, 0x72,
|
|
||||||
0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x65, 0x64, 0x43, 0x61, 0x6c, 0x6c, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00,
|
|
||||||
0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x3e, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x84, 0xf5, 0xff, 0xff,
|
|
||||||
0x0d, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x00, 0x00,
|
|
||||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x7a, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
|
|
||||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0xc0,
|
|
||||||
0xf5, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75,
|
|
||||||
0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
|
|
||||||
0x00, 0xbe, 0xf6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x04, 0xf6, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x61,
|
|
||||||
0x64, 0x64, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf2, 0xf6, 0xff, 0xff,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x02, 0x18, 0x00, 0x00, 0x00, 0x38, 0xf6, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x54, 0x72, 0x75, 0x6e, 0x63, 0x61,
|
|
||||||
0x74, 0x65, 0x44, 0x69, 0x76, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2a, 0xf7, 0xff, 0xff, 0x00,
|
|
||||||
0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
|
||||||
0x10, 0x00, 0x00, 0x00, 0x70, 0xf6, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x61, 0x64, 0x64, 0x00, 0x01, 0x00, 0x00,
|
|
||||||
0x00, 0x28, 0x00, 0x00, 0x00, 0x5a, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00,
|
|
||||||
0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0xa0, 0xf6, 0xff, 0xff, 0x03,
|
|
||||||
0x00, 0x00, 0x00, 0x6d, 0x75, 0x6c, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x8a, 0xf7, 0xff, 0xff,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x02, 0x14, 0x00, 0x00, 0x00, 0xd0, 0xf6, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x32,
|
|
||||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0xbe, 0xf7, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00,
|
|
||||||
0x04, 0xf7, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74,
|
|
||||||
0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x6c, 0x6f, 0x67, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
||||||
0x00, 0x00, 0x02, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x18, 0x00, 0x00, 0x00, 0x48, 0xf7, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00,
|
|
||||||
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00,
|
|
||||||
0x00, 0x3a, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x21, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x38, 0x00, 0x00, 0x00, 0x80, 0xf7, 0xff, 0xff, 0x28, 0x00, 0x00, 0x00, 0x73,
|
|
||||||
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73,
|
|
||||||
0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c, 0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
|
|
||||||
0x31, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x92, 0xf8, 0xff, 0xff, 0x00, 0x00,
|
|
||||||
0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x34,
|
|
||||||
0x00, 0x00, 0x00, 0xd8, 0xf7, 0xff, 0xff, 0x27, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66,
|
|
||||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f, 0x73, 0x70, 0x65, 0x63, 0x74, 0x72, 0x61, 0x6c,
|
|
||||||
0x5f, 0x73, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
||||||
0x00, 0x00, 0xe6, 0xf8, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1f,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x2c, 0x00, 0x00, 0x00, 0x2c, 0xf8, 0xff, 0xff, 0x1e, 0x00, 0x00, 0x00,
|
|
||||||
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x5f,
|
|
||||||
0x73, 0x71, 0x75, 0x61, 0x72, 0x65, 0x5f, 0x72, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00,
|
|
||||||
0x00, 0x00, 0x32, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1e,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x20, 0x00, 0x00, 0x00, 0x78, 0xf8, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00,
|
|
||||||
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x00,
|
|
||||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x72, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
|
|
||||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x14, 0x00, 0x00, 0x00, 0xb8,
|
|
||||||
0xf8, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x01, 0x01, 0x00, 0x00, 0xa6, 0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
|
|
||||||
0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xec, 0xf8, 0xff, 0xff, 0x06, 0x00,
|
|
||||||
0x00, 0x00, 0x63, 0x6f, 0x6e, 0x63, 0x61, 0x74, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0xda,
|
|
||||||
0xf9, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00, 0x00, 0x20, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72,
|
|
||||||
0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xec, 0x00,
|
|
||||||
0x00, 0x00, 0x16, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x1a,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xf9, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00,
|
|
||||||
0x43, 0x61, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x4a, 0xfa, 0xff,
|
|
||||||
0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x0f, 0x1c, 0x00, 0x00, 0x00, 0x90, 0xf9, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61,
|
|
||||||
0x6c, 0x5f, 0x65, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
|
|
||||||
0x86, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xf9, 0xff, 0xff, 0x0b, 0x00, 0x00, 0x00, 0x73, 0x69,
|
|
||||||
0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x72, 0x66, 0x66, 0x74, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0xbe,
|
|
||||||
0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x04, 0xfa, 0xff, 0xff, 0x16, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67,
|
|
||||||
0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f, 0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x31,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfa, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x24, 0x00, 0x00, 0x00, 0x44, 0xfa, 0xff, 0xff,
|
|
||||||
0x15, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x66, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x6f,
|
|
||||||
0x5f, 0x73, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x42, 0xfb,
|
|
||||||
0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x88, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68,
|
|
||||||
0x61, 0x70, 0x65, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x76, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00,
|
|
||||||
0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x1c, 0x00,
|
|
||||||
0x00, 0x00, 0xbc, 0xfa, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x77, 0x69,
|
|
||||||
0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00,
|
|
||||||
0xb6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xfc, 0xfa, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43, 0x6f,
|
|
||||||
0x6e, 0x73, 0x74, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xfb, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14,
|
|
||||||
0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00,
|
|
||||||
0x2c, 0xfb, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x16, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x11, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x5c, 0xfb, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x43,
|
|
||||||
0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
|
|
||||||
0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1c, 0x00, 0x00,
|
|
||||||
0x00, 0x8c, 0xfb, 0xff, 0xff, 0x0d, 0x00, 0x00, 0x00, 0x52, 0x65, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2f, 0x73, 0x68,
|
|
||||||
0x61, 0x70, 0x65, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x82, 0xfc, 0xff, 0xff, 0x00,
|
|
||||||
0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
|
|
||||||
0x24, 0x00, 0x00, 0x00, 0xc8, 0xfb, 0xff, 0xff, 0x17, 0x00, 0x00, 0x00, 0x63, 0x6c, 0x69, 0x70, 0x5f, 0x62, 0x79,
|
|
||||||
0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x69, 0x6d, 0x75, 0x6d, 0x2f, 0x79, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0xc2, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0e,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x08, 0xfc, 0xff, 0xff, 0x18, 0x00, 0x00, 0x00,
|
|
||||||
0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f,
|
|
||||||
0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x0a, 0xfd,
|
|
||||||
0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x50, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e,
|
|
||||||
0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73,
|
|
||||||
0x74, 0x5f, 0x31, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x52, 0xfd, 0xff, 0xff, 0x00, 0x00,
|
|
||||||
0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28,
|
|
||||||
0x00, 0x00, 0x00, 0x98, 0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66,
|
|
||||||
0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x32, 0x00,
|
|
||||||
0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x9a, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
|
|
||||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0xe0,
|
|
||||||
0xfc, 0xff, 0xff, 0x1a, 0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65,
|
|
||||||
0x72, 0x5f, 0x62, 0x61, 0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x33, 0x00, 0x00, 0x01, 0x00, 0x00,
|
|
||||||
0x00, 0x29, 0x00, 0x00, 0x00, 0xe2, 0xfd, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00,
|
|
||||||
0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x28, 0x00, 0x00, 0x00, 0x28, 0xfd, 0xff, 0xff, 0x1a,
|
|
||||||
0x00, 0x00, 0x00, 0x73, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5f, 0x62, 0x61,
|
|
||||||
0x6e, 0x6b, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x5f, 0x34, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00,
|
|
||||||
0x00, 0x2a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x09, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00, 0x00, 0x70, 0xfd, 0xff, 0xff, 0x11, 0x00, 0x00, 0x00, 0x73,
|
|
||||||
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x63, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6e, 0x73, 0x74, 0x00, 0x00, 0x00,
|
|
||||||
0x01, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x6a, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00,
|
|
||||||
0x00, 0x14, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x00, 0xb0, 0xfd,
|
|
||||||
0xff, 0xff, 0x13, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65,
|
|
||||||
0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xaa, 0xfe, 0xff, 0xff,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x02, 0x24, 0x00, 0x00, 0x00, 0xf0, 0xfd, 0xff, 0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65,
|
|
||||||
0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x31, 0x00, 0x00, 0x00, 0x01,
|
|
||||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xee, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00,
|
|
||||||
0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x24, 0x00, 0x00, 0x00, 0x34, 0xfe, 0xff,
|
|
||||||
0xff, 0x15, 0x00, 0x00, 0x00, 0x73, 0x74, 0x72, 0x69, 0x64, 0x65, 0x64, 0x5f, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x2f,
|
|
||||||
0x73, 0x74, 0x61, 0x63, 0x6b, 0x5f, 0x32, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x32,
|
|
||||||
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0x78, 0xfe, 0xff, 0xff, 0x06, 0x00, 0x00, 0x00, 0x43, 0x61, 0x73,
|
|
||||||
0x74, 0x5f, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00,
|
|
||||||
0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xa8,
|
|
||||||
0xfe, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x05, 0x00, 0x00, 0x00, 0x96, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
|
|
||||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x14, 0x00, 0x00, 0x00, 0xdc, 0xfe, 0xff, 0xff, 0x07, 0x00,
|
|
||||||
0x00, 0x00, 0x7a, 0x65, 0x72, 0x6f, 0x73, 0x5f, 0x31, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0xca,
|
|
||||||
0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x07, 0x14, 0x00, 0x00, 0x00, 0x10, 0xff, 0xff, 0xff, 0x05, 0x00, 0x00, 0x00, 0x43, 0x6f, 0x6e,
|
|
||||||
0x73, 0x74, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x1c, 0x00,
|
|
||||||
0x18, 0x00, 0x17, 0x00, 0x10, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x16,
|
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x14, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x07, 0x2c, 0x00, 0x00, 0x00, 0x5c, 0xff, 0xff, 0xff, 0x1d, 0x00, 0x00, 0x00, 0x73, 0x65, 0x72,
|
|
||||||
0x76, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x5f,
|
|
||||||
0x66, 0x72, 0x61, 0x6d, 0x65, 0x3a, 0x30, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xe0,
|
|
||||||
0x01, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1c, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0xc8, 0x01, 0x00, 0x00,
|
|
||||||
0xa4, 0x01, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, 0x68, 0x01, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, 0x3c, 0x01, 0x00,
|
|
||||||
0x00, 0x10, 0x01, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x50, 0x00,
|
|
||||||
0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x04,
|
|
||||||
0x00, 0x00, 0x00, 0x50, 0xfe, 0xff, 0xff, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x5c, 0xfe, 0xff, 0xff,
|
|
||||||
0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x68, 0xfe, 0xff, 0xff, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x2a, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x7c, 0xfe, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x12, 0x70, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x13,
|
|
||||||
0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b,
|
|
||||||
0x4c, 0x6f, 0x67, 0x00, 0x98, 0xfe, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x20, 0x0a, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x50, 0x43, 0x41, 0x4e, 0x00, 0x00, 0xb8, 0xfe,
|
|
||||||
0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x23, 0x00, 0x00, 0x00, 0x53,
|
|
||||||
0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x70, 0x65, 0x63,
|
|
||||||
0x74, 0x72, 0x61, 0x6c, 0x53, 0x75, 0x62, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x00, 0xf0, 0xfe, 0xff,
|
|
||||||
0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x1a, 0x00, 0x00, 0x00, 0x53, 0x69,
|
|
||||||
0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x42, 0x61, 0x6e, 0x6b, 0x53, 0x71, 0x75, 0x61, 0x72,
|
|
||||||
0x65, 0x52, 0x6f, 0x6f, 0x74, 0x00, 0x00, 0x20, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x74, 0x65,
|
|
||||||
0x72, 0x42, 0x61, 0x6e, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x60, 0xff, 0xff, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x02, 0x6c, 0xff, 0xff, 0xff, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2d, 0x0c, 0x00, 0x10, 0x00, 0x0f,
|
|
||||||
0x00, 0x00, 0x00, 0x08, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x00, 0x35, 0x7c, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x45, 0x6e, 0x65, 0x72, 0x67, 0x79, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0xa0, 0xff, 0xff, 0xff, 0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0a,
|
|
||||||
0x00, 0x00, 0x00, 0x53, 0x69, 0x67, 0x6e, 0x61, 0x6c, 0x52, 0x66, 0x66, 0x74, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff,
|
|
||||||
0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x12, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67,
|
|
||||||
0x6e, 0x61, 0x6c, 0x46, 0x66, 0x74, 0x41, 0x75, 0x74, 0x6f, 0x53, 0x63, 0x61, 0x6c, 0x65, 0x00, 0x00, 0x0c, 0x00,
|
|
||||||
0x0c, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00,
|
|
||||||
0x00, 0x00, 0x16, 0x0c, 0x00, 0x10, 0x00, 0x0f, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00,
|
|
||||||
0x20, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x0c, 0x00, 0x00, 0x00, 0x53, 0x69, 0x67,
|
|
||||||
0x6e, 0x61, 0x6c, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
} // namespace micro_wake_word
|
|
||||||
} // namespace esphome
|
|
||||||
|
|
||||||
#endif // USE_ESP_IDF
|
|
@ -1,12 +1,5 @@
|
|||||||
#include "micro_wake_word.h"
|
#include "micro_wake_word.h"
|
||||||
|
#include "streaming_model.h"
|
||||||
/**
|
|
||||||
* This is a workaround until we can figure out a way to get
|
|
||||||
* the tflite-micro idf component code available in CI
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
//
|
|
||||||
#ifndef CLANG_TIDY
|
|
||||||
|
|
||||||
#ifdef USE_ESP_IDF
|
#ifdef USE_ESP_IDF
|
||||||
|
|
||||||
@ -14,13 +7,13 @@
|
|||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
#include "audio_preprocessor_int8_model_data.h"
|
#include <frontend.h>
|
||||||
|
#include <frontend_util.h>
|
||||||
|
|
||||||
#include <tensorflow/lite/core/c/common.h>
|
#include <tensorflow/lite/core/c/common.h>
|
||||||
#include <tensorflow/lite/micro/micro_interpreter.h>
|
#include <tensorflow/lite/micro/micro_interpreter.h>
|
||||||
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
|
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
|
||||||
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
@ -29,9 +22,9 @@ namespace micro_wake_word {
|
|||||||
static const char *const TAG = "micro_wake_word";
|
static const char *const TAG = "micro_wake_word";
|
||||||
|
|
||||||
static const size_t SAMPLE_RATE_HZ = 16000; // 16 kHz
|
static const size_t SAMPLE_RATE_HZ = 16000; // 16 kHz
|
||||||
static const size_t BUFFER_LENGTH = 500; // 0.5 seconds
|
static const size_t BUFFER_LENGTH = 64; // 0.064 seconds
|
||||||
static const size_t BUFFER_SIZE = SAMPLE_RATE_HZ / 1000 * BUFFER_LENGTH;
|
static const size_t BUFFER_SIZE = SAMPLE_RATE_HZ / 1000 * BUFFER_LENGTH;
|
||||||
static const size_t INPUT_BUFFER_SIZE = 32 * SAMPLE_RATE_HZ / 1000; // 32ms * 16kHz / 1000ms
|
static const size_t INPUT_BUFFER_SIZE = 16 * SAMPLE_RATE_HZ / 1000; // 16ms * 16kHz / 1000ms
|
||||||
|
|
||||||
float MicroWakeWord::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
|
float MicroWakeWord::get_setup_priority() const { return setup_priority::AFTER_CONNECTION; }
|
||||||
|
|
||||||
@ -56,57 +49,55 @@ static const LogString *micro_wake_word_state_to_string(State state) {
|
|||||||
|
|
||||||
void MicroWakeWord::dump_config() {
|
void MicroWakeWord::dump_config() {
|
||||||
ESP_LOGCONFIG(TAG, "microWakeWord:");
|
ESP_LOGCONFIG(TAG, "microWakeWord:");
|
||||||
ESP_LOGCONFIG(TAG, " Wake Word: %s", this->get_wake_word().c_str());
|
ESP_LOGCONFIG(TAG, " models:");
|
||||||
ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_);
|
for (auto &model : this->wake_word_models_) {
|
||||||
ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_average_size_);
|
model.log_model_config();
|
||||||
|
}
|
||||||
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
this->vad_model_->log_model_config();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroWakeWord::setup() {
|
void MicroWakeWord::setup() {
|
||||||
ESP_LOGCONFIG(TAG, "Setting up microWakeWord...");
|
ESP_LOGCONFIG(TAG, "Setting up microWakeWord...");
|
||||||
|
|
||||||
if (!this->initialize_models()) {
|
if (!this->register_streaming_ops_(this->streaming_op_resolver_)) {
|
||||||
ESP_LOGE(TAG, "Failed to initialize models");
|
|
||||||
this->mark_failed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ExternalRAMAllocator<int16_t> allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
|
|
||||||
this->input_buffer_ = allocator.allocate(INPUT_BUFFER_SIZE * sizeof(int16_t));
|
|
||||||
if (this->input_buffer_ == nullptr) {
|
|
||||||
ESP_LOGW(TAG, "Could not allocate input buffer");
|
|
||||||
this->mark_failed();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t));
|
|
||||||
if (this->ring_buffer_ == nullptr) {
|
|
||||||
ESP_LOGW(TAG, "Could not allocate ring buffer");
|
|
||||||
this->mark_failed();
|
this->mark_failed();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGCONFIG(TAG, "Micro Wake Word initialized");
|
ESP_LOGCONFIG(TAG, "Micro Wake Word initialized");
|
||||||
|
|
||||||
|
this->frontend_config_.window.size_ms = FEATURE_DURATION_MS;
|
||||||
|
this->frontend_config_.window.step_size_ms = this->features_step_size_;
|
||||||
|
this->frontend_config_.filterbank.num_channels = PREPROCESSOR_FEATURE_SIZE;
|
||||||
|
this->frontend_config_.filterbank.lower_band_limit = 125.0;
|
||||||
|
this->frontend_config_.filterbank.upper_band_limit = 7500.0;
|
||||||
|
this->frontend_config_.noise_reduction.smoothing_bits = 10;
|
||||||
|
this->frontend_config_.noise_reduction.even_smoothing = 0.025;
|
||||||
|
this->frontend_config_.noise_reduction.odd_smoothing = 0.06;
|
||||||
|
this->frontend_config_.noise_reduction.min_signal_remaining = 0.05;
|
||||||
|
this->frontend_config_.pcan_gain_control.enable_pcan = 1;
|
||||||
|
this->frontend_config_.pcan_gain_control.strength = 0.95;
|
||||||
|
this->frontend_config_.pcan_gain_control.offset = 80.0;
|
||||||
|
this->frontend_config_.pcan_gain_control.gain_bits = 21;
|
||||||
|
this->frontend_config_.log_scale.enable_log = 1;
|
||||||
|
this->frontend_config_.log_scale.scale_shift = 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
int MicroWakeWord::read_microphone_() {
|
void MicroWakeWord::add_wake_word_model(const uint8_t *model_start, float probability_cutoff,
|
||||||
size_t bytes_read = this->microphone_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t));
|
size_t sliding_window_average_size, const std::string &wake_word,
|
||||||
if (bytes_read == 0) {
|
size_t tensor_arena_size) {
|
||||||
return 0;
|
this->wake_word_models_.emplace_back(model_start, probability_cutoff, sliding_window_average_size, wake_word,
|
||||||
|
tensor_arena_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t bytes_free = this->ring_buffer_->free();
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
void MicroWakeWord::add_vad_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size,
|
||||||
if (bytes_free < bytes_read) {
|
size_t tensor_arena_size) {
|
||||||
ESP_LOGW(TAG,
|
this->vad_model_ = make_unique<VADModel>(model_start, probability_cutoff, sliding_window_size, tensor_arena_size);
|
||||||
"Not enough free bytes in ring buffer to store incoming audio data (free bytes=%d, incoming bytes=%d). "
|
|
||||||
"Resetting the ring buffer. Wake word detection accuracy will be reduced.",
|
|
||||||
bytes_free, bytes_read);
|
|
||||||
|
|
||||||
this->ring_buffer_->reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->ring_buffer_->write((void *) this->input_buffer_, bytes_read);
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
void MicroWakeWord::loop() {
|
void MicroWakeWord::loop() {
|
||||||
switch (this->state_) {
|
switch (this->state_) {
|
||||||
@ -124,9 +115,12 @@ void MicroWakeWord::loop() {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case State::DETECTING_WAKE_WORD:
|
case State::DETECTING_WAKE_WORD:
|
||||||
|
while (!this->has_enough_samples_()) {
|
||||||
this->read_microphone_();
|
this->read_microphone_();
|
||||||
if (this->detect_wake_word_()) {
|
}
|
||||||
ESP_LOGD(TAG, "Wake Word Detected");
|
this->update_model_probabilities_();
|
||||||
|
if (this->detect_wake_words_()) {
|
||||||
|
ESP_LOGD(TAG, "Wake Word '%s' Detected", (this->detected_wake_word_).c_str());
|
||||||
this->detected_ = true;
|
this->detected_ = true;
|
||||||
this->set_state_(State::STOP_MICROPHONE);
|
this->set_state_(State::STOP_MICROPHONE);
|
||||||
}
|
}
|
||||||
@ -136,13 +130,16 @@ void MicroWakeWord::loop() {
|
|||||||
this->microphone_->stop();
|
this->microphone_->stop();
|
||||||
this->set_state_(State::STOPPING_MICROPHONE);
|
this->set_state_(State::STOPPING_MICROPHONE);
|
||||||
this->high_freq_.stop();
|
this->high_freq_.stop();
|
||||||
|
this->unload_models_();
|
||||||
|
this->deallocate_buffers_();
|
||||||
break;
|
break;
|
||||||
case State::STOPPING_MICROPHONE:
|
case State::STOPPING_MICROPHONE:
|
||||||
if (this->microphone_->is_stopped()) {
|
if (this->microphone_->is_stopped()) {
|
||||||
this->set_state_(State::IDLE);
|
this->set_state_(State::IDLE);
|
||||||
if (this->detected_) {
|
if (this->detected_) {
|
||||||
|
this->wake_word_detected_trigger_->trigger(this->detected_wake_word_);
|
||||||
this->detected_ = false;
|
this->detected_ = false;
|
||||||
this->wake_word_detected_trigger_->trigger(this->wake_word_);
|
this->detected_wake_word_ = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -150,14 +147,34 @@ void MicroWakeWord::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MicroWakeWord::start() {
|
void MicroWakeWord::start() {
|
||||||
|
if (!this->is_ready()) {
|
||||||
|
ESP_LOGW(TAG, "Wake word detection can't start as the component hasn't been setup yet");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->is_failed()) {
|
if (this->is_failed()) {
|
||||||
ESP_LOGW(TAG, "Wake word component is marked as failed. Please check setup logs");
|
ESP_LOGW(TAG, "Wake word component is marked as failed. Please check setup logs");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this->load_models_() || !this->allocate_buffers_()) {
|
||||||
|
ESP_LOGE(TAG, "Failed to load the wake word model(s) or allocate buffers");
|
||||||
|
this->status_set_error();
|
||||||
|
} else {
|
||||||
|
this->status_clear_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->status_has_error()) {
|
||||||
|
ESP_LOGW(TAG, "Wake word component has an error. Please check logs");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (this->state_ != State::IDLE) {
|
if (this->state_ != State::IDLE) {
|
||||||
ESP_LOGW(TAG, "Wake word is already running");
|
ESP_LOGW(TAG, "Wake word is already running");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->reset_states_();
|
||||||
this->set_state_(State::START_MICROPHONE);
|
this->set_state_(State::START_MICROPHONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,289 +196,218 @@ void MicroWakeWord::set_state_(State state) {
|
|||||||
this->state_ = state;
|
this->state_ = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MicroWakeWord::initialize_models() {
|
size_t MicroWakeWord::read_microphone_() {
|
||||||
ExternalRAMAllocator<uint8_t> arena_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
size_t bytes_read = this->microphone_->read(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t));
|
||||||
ExternalRAMAllocator<int8_t> features_allocator(ExternalRAMAllocator<int8_t>::ALLOW_FAILURE);
|
if (bytes_read == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t bytes_free = this->ring_buffer_->free();
|
||||||
|
|
||||||
|
if (bytes_free < bytes_read) {
|
||||||
|
ESP_LOGW(TAG,
|
||||||
|
"Not enough free bytes in ring buffer to store incoming audio data (free bytes=%d, incoming bytes=%d). "
|
||||||
|
"Resetting the ring buffer. Wake word detection accuracy will be reduced.",
|
||||||
|
bytes_free, bytes_read);
|
||||||
|
|
||||||
|
this->ring_buffer_->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this->ring_buffer_->write((void *) this->input_buffer_, bytes_read);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MicroWakeWord::allocate_buffers_() {
|
||||||
ExternalRAMAllocator<int16_t> audio_samples_allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
|
ExternalRAMAllocator<int16_t> audio_samples_allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
|
||||||
|
|
||||||
this->streaming_tensor_arena_ = arena_allocator.allocate(STREAMING_MODEL_ARENA_SIZE);
|
if (this->input_buffer_ == nullptr) {
|
||||||
if (this->streaming_tensor_arena_ == nullptr) {
|
this->input_buffer_ = audio_samples_allocator.allocate(INPUT_BUFFER_SIZE * sizeof(int16_t));
|
||||||
ESP_LOGE(TAG, "Could not allocate the streaming model's tensor arena.");
|
if (this->input_buffer_ == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Could not allocate input buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->streaming_var_arena_ = arena_allocator.allocate(STREAMING_MODEL_VARIABLE_ARENA_SIZE);
|
|
||||||
if (this->streaming_var_arena_ == nullptr) {
|
|
||||||
ESP_LOGE(TAG, "Could not allocate the streaming model variable's tensor arena.");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->preprocessor_tensor_arena_ = arena_allocator.allocate(PREPROCESSOR_ARENA_SIZE);
|
if (this->preprocessor_audio_buffer_ == nullptr) {
|
||||||
if (this->preprocessor_tensor_arena_ == nullptr) {
|
this->preprocessor_audio_buffer_ = audio_samples_allocator.allocate(this->new_samples_to_get_());
|
||||||
ESP_LOGE(TAG, "Could not allocate the audio preprocessor model's tensor arena.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->new_features_data_ = features_allocator.allocate(PREPROCESSOR_FEATURE_SIZE);
|
|
||||||
if (this->new_features_data_ == nullptr) {
|
|
||||||
ESP_LOGE(TAG, "Could not allocate the audio features buffer.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->preprocessor_audio_buffer_ = audio_samples_allocator.allocate(SAMPLE_DURATION_COUNT);
|
|
||||||
if (this->preprocessor_audio_buffer_ == nullptr) {
|
if (this->preprocessor_audio_buffer_ == nullptr) {
|
||||||
ESP_LOGE(TAG, "Could not allocate the audio preprocessor's buffer.");
|
ESP_LOGE(TAG, "Could not allocate the audio preprocessor's buffer.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->preprocessor_model_ = tflite::GetModel(G_AUDIO_PREPROCESSOR_INT8_TFLITE);
|
|
||||||
if (this->preprocessor_model_->version() != TFLITE_SCHEMA_VERSION) {
|
|
||||||
ESP_LOGE(TAG, "Wake word's audio preprocessor model's schema is not supported");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this->streaming_model_ = tflite::GetModel(this->model_start_);
|
if (this->ring_buffer_ == nullptr) {
|
||||||
if (this->streaming_model_->version() != TFLITE_SCHEMA_VERSION) {
|
this->ring_buffer_ = RingBuffer::create(BUFFER_SIZE * sizeof(int16_t));
|
||||||
ESP_LOGE(TAG, "Wake word's streaming model's schema is not supported");
|
if (this->ring_buffer_ == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Could not allocate ring buffer");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static tflite::MicroMutableOpResolver<18> preprocessor_op_resolver;
|
|
||||||
static tflite::MicroMutableOpResolver<17> streaming_op_resolver;
|
|
||||||
|
|
||||||
if (!this->register_preprocessor_ops_(preprocessor_op_resolver))
|
|
||||||
return false;
|
|
||||||
if (!this->register_streaming_ops_(streaming_op_resolver))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
tflite::MicroAllocator *ma =
|
|
||||||
tflite::MicroAllocator::Create(this->streaming_var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
|
|
||||||
this->mrv_ = tflite::MicroResourceVariables::Create(ma, 15);
|
|
||||||
|
|
||||||
static tflite::MicroInterpreter static_preprocessor_interpreter(
|
|
||||||
this->preprocessor_model_, preprocessor_op_resolver, this->preprocessor_tensor_arena_, PREPROCESSOR_ARENA_SIZE);
|
|
||||||
|
|
||||||
static tflite::MicroInterpreter static_streaming_interpreter(this->streaming_model_, streaming_op_resolver,
|
|
||||||
this->streaming_tensor_arena_,
|
|
||||||
STREAMING_MODEL_ARENA_SIZE, this->mrv_);
|
|
||||||
|
|
||||||
this->preprocessor_interperter_ = &static_preprocessor_interpreter;
|
|
||||||
this->streaming_interpreter_ = &static_streaming_interpreter;
|
|
||||||
|
|
||||||
// Allocate tensors for each models.
|
|
||||||
if (this->preprocessor_interperter_->AllocateTensors() != kTfLiteOk) {
|
|
||||||
ESP_LOGE(TAG, "Failed to allocate tensors for the audio preprocessor");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (this->streaming_interpreter_->AllocateTensors() != kTfLiteOk) {
|
|
||||||
ESP_LOGE(TAG, "Failed to allocate tensors for the streaming model");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify input tensor matches expected values
|
|
||||||
TfLiteTensor *input = this->streaming_interpreter_->input(0);
|
|
||||||
if ((input->dims->size != 3) || (input->dims->data[0] != 1) || (input->dims->data[0] != 1) ||
|
|
||||||
(input->dims->data[1] != 1) || (input->dims->data[2] != PREPROCESSOR_FEATURE_SIZE)) {
|
|
||||||
ESP_LOGE(TAG, "Wake word detection model tensor input dimensions is not 1x1x%u", input->dims->data[2]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input->type != kTfLiteInt8) {
|
|
||||||
ESP_LOGE(TAG, "Wake word detection model tensor input is not int8.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify output tensor matches expected values
|
|
||||||
TfLiteTensor *output = this->streaming_interpreter_->output(0);
|
|
||||||
if ((output->dims->size != 2) || (output->dims->data[0] != 1) || (output->dims->data[1] != 1)) {
|
|
||||||
ESP_LOGE(TAG, "Wake word detection model tensor output dimensions is not 1x1.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (output->type != kTfLiteUInt8) {
|
|
||||||
ESP_LOGE(TAG, "Wake word detection model tensor input is not uint8.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MicroWakeWord::update_features_() {
|
|
||||||
// Retrieve strided audio samples
|
|
||||||
int16_t *audio_samples = nullptr;
|
|
||||||
if (!this->stride_audio_samples_(&audio_samples)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute the features for the newest audio samples
|
|
||||||
if (!this->generate_single_feature_(audio_samples, SAMPLE_DURATION_COUNT, this->new_features_data_)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
float MicroWakeWord::perform_streaming_inference_() {
|
void MicroWakeWord::deallocate_buffers_() {
|
||||||
TfLiteTensor *input = this->streaming_interpreter_->input(0);
|
ExternalRAMAllocator<int16_t> audio_samples_allocator(ExternalRAMAllocator<int16_t>::ALLOW_FAILURE);
|
||||||
|
audio_samples_allocator.deallocate(this->input_buffer_, INPUT_BUFFER_SIZE * sizeof(int16_t));
|
||||||
|
this->input_buffer_ = nullptr;
|
||||||
|
audio_samples_allocator.deallocate(this->preprocessor_audio_buffer_, this->new_samples_to_get_());
|
||||||
|
this->preprocessor_audio_buffer_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
size_t bytes_to_copy = input->bytes;
|
bool MicroWakeWord::load_models_() {
|
||||||
|
// Setup preprocesor feature generator
|
||||||
memcpy((void *) (tflite::GetTensorData<int8_t>(input)), (const void *) (this->new_features_data_), bytes_to_copy);
|
if (!FrontendPopulateState(&this->frontend_config_, &this->frontend_state_, AUDIO_SAMPLE_FREQUENCY)) {
|
||||||
|
ESP_LOGD(TAG, "Failed to populate frontend state");
|
||||||
uint32_t prior_invoke = millis();
|
FrontendFreeStateContents(&this->frontend_state_);
|
||||||
|
|
||||||
TfLiteStatus invoke_status = this->streaming_interpreter_->Invoke();
|
|
||||||
if (invoke_status != kTfLiteOk) {
|
|
||||||
ESP_LOGW(TAG, "Streaming Interpreter Invoke failed");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGV(TAG, "Streaming Inference Latency=%" PRIu32 " ms", (millis() - prior_invoke));
|
// Setup streaming models
|
||||||
|
for (auto &model : this->wake_word_models_) {
|
||||||
TfLiteTensor *output = this->streaming_interpreter_->output(0);
|
if (!model.load_model(this->streaming_op_resolver_)) {
|
||||||
|
ESP_LOGE(TAG, "Failed to initialize a wake word model.");
|
||||||
return static_cast<float>(output->data.uint8[0]) / 255.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MicroWakeWord::detect_wake_word_() {
|
|
||||||
// Preprocess the newest audio samples into features
|
|
||||||
if (!this->update_features_()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
if (!this->vad_model_->load_model(this->streaming_op_resolver_)) {
|
||||||
|
ESP_LOGE(TAG, "Failed to initialize VAD model.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Perform inference
|
return true;
|
||||||
float streaming_prob = this->perform_streaming_inference_();
|
|
||||||
|
|
||||||
// Add the most recent probability to the sliding window
|
|
||||||
this->recent_streaming_probabilities_[this->last_n_index_] = streaming_prob;
|
|
||||||
++this->last_n_index_;
|
|
||||||
if (this->last_n_index_ == this->sliding_window_average_size_)
|
|
||||||
this->last_n_index_ = 0;
|
|
||||||
|
|
||||||
float sum = 0.0;
|
|
||||||
for (auto &prob : this->recent_streaming_probabilities_) {
|
|
||||||
sum += prob;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float sliding_window_average = sum / static_cast<float>(this->sliding_window_average_size_);
|
void MicroWakeWord::unload_models_() {
|
||||||
|
FrontendFreeStateContents(&this->frontend_state_);
|
||||||
|
|
||||||
// Ensure we have enough samples since the last positive detection
|
for (auto &model : this->wake_word_models_) {
|
||||||
|
model.unload_model();
|
||||||
|
}
|
||||||
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
this->vad_model_->unload_model();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void MicroWakeWord::update_model_probabilities_() {
|
||||||
|
int8_t audio_features[PREPROCESSOR_FEATURE_SIZE];
|
||||||
|
|
||||||
|
if (!this->generate_features_for_window_(audio_features)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Increase the counter since the last positive detection
|
||||||
this->ignore_windows_ = std::min(this->ignore_windows_ + 1, 0);
|
this->ignore_windows_ = std::min(this->ignore_windows_ + 1, 0);
|
||||||
|
|
||||||
|
for (auto &model : this->wake_word_models_) {
|
||||||
|
// Perform inference
|
||||||
|
model.perform_streaming_inference(audio_features);
|
||||||
|
}
|
||||||
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
this->vad_model_->perform_streaming_inference(audio_features);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MicroWakeWord::detect_wake_words_() {
|
||||||
|
// Verify we have processed samples since the last positive detection
|
||||||
if (this->ignore_windows_ < 0) {
|
if (this->ignore_windows_ < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect the wake word if the sliding window average is above the cutoff
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
if (sliding_window_average > this->probability_cutoff_) {
|
bool vad_state = this->vad_model_->determine_detected();
|
||||||
this->ignore_windows_ = -MIN_SLICES_BEFORE_DETECTION;
|
#endif
|
||||||
for (auto &prob : this->recent_streaming_probabilities_) {
|
|
||||||
prob = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Wake word sliding average probability is %.3f and most recent probability is %.3f",
|
for (auto &model : this->wake_word_models_) {
|
||||||
sliding_window_average, streaming_prob);
|
if (model.determine_detected()) {
|
||||||
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
if (vad_state) {
|
||||||
|
#endif
|
||||||
|
this->detected_wake_word_ = model.get_wake_word();
|
||||||
return true;
|
return true;
|
||||||
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
} else {
|
||||||
|
ESP_LOGD(TAG, "Wake word model predicts %s, but VAD model doesn't.", model.get_wake_word().c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MicroWakeWord::set_sliding_window_average_size(size_t size) {
|
bool MicroWakeWord::has_enough_samples_() {
|
||||||
this->sliding_window_average_size_ = size;
|
return this->ring_buffer_->available() >=
|
||||||
this->recent_streaming_probabilities_.resize(this->sliding_window_average_size_, 0.0);
|
(this->features_step_size_ * (AUDIO_SAMPLE_FREQUENCY / 1000)) * sizeof(int16_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MicroWakeWord::slice_available_() {
|
bool MicroWakeWord::generate_features_for_window_(int8_t features[PREPROCESSOR_FEATURE_SIZE]) {
|
||||||
size_t available = this->ring_buffer_->available();
|
// Ensure we have enough new audio samples in the ring buffer for a full window
|
||||||
|
if (!this->has_enough_samples_()) {
|
||||||
return available > (NEW_SAMPLES_TO_GET * sizeof(int16_t));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MicroWakeWord::stride_audio_samples_(int16_t **audio_samples) {
|
|
||||||
if (!this->slice_available_()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy the last 320 bytes (160 samples over 10 ms) from the audio buffer to the start of the audio buffer
|
size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_),
|
||||||
memcpy((void *) (this->preprocessor_audio_buffer_), (void *) (this->preprocessor_audio_buffer_ + NEW_SAMPLES_TO_GET),
|
this->new_samples_to_get_() * sizeof(int16_t), pdMS_TO_TICKS(200));
|
||||||
HISTORY_SAMPLES_TO_KEEP * sizeof(int16_t));
|
|
||||||
|
|
||||||
// Copy 640 bytes (320 samples over 20 ms) from the ring buffer into the audio buffer offset 320 bytes (160 samples
|
|
||||||
// over 10 ms)
|
|
||||||
size_t bytes_read = this->ring_buffer_->read((void *) (this->preprocessor_audio_buffer_ + HISTORY_SAMPLES_TO_KEEP),
|
|
||||||
NEW_SAMPLES_TO_GET * sizeof(int16_t), pdMS_TO_TICKS(200));
|
|
||||||
|
|
||||||
if (bytes_read == 0) {
|
if (bytes_read == 0) {
|
||||||
ESP_LOGE(TAG, "Could not read data from Ring Buffer");
|
ESP_LOGE(TAG, "Could not read data from Ring Buffer");
|
||||||
} else if (bytes_read < NEW_SAMPLES_TO_GET * sizeof(int16_t)) {
|
} else if (bytes_read < this->new_samples_to_get_() * sizeof(int16_t)) {
|
||||||
ESP_LOGD(TAG, "Partial Read of Data by Model");
|
ESP_LOGD(TAG, "Partial Read of Data by Model");
|
||||||
ESP_LOGD(TAG, "Could only read %d bytes when required %d bytes ", bytes_read,
|
ESP_LOGD(TAG, "Could only read %d bytes when required %d bytes ", bytes_read,
|
||||||
(int) (NEW_SAMPLES_TO_GET * sizeof(int16_t)));
|
(int) (this->new_samples_to_get_() * sizeof(int16_t)));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*audio_samples = this->preprocessor_audio_buffer_;
|
size_t num_samples_read;
|
||||||
return true;
|
struct FrontendOutput frontend_output = FrontendProcessSamples(
|
||||||
}
|
&this->frontend_state_, this->preprocessor_audio_buffer_, this->new_samples_to_get_(), &num_samples_read);
|
||||||
|
|
||||||
bool MicroWakeWord::generate_single_feature_(const int16_t *audio_data, const int audio_data_size,
|
for (size_t i = 0; i < frontend_output.size; ++i) {
|
||||||
int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]) {
|
// These scaling values are set to match the TFLite audio frontend int8 output.
|
||||||
TfLiteTensor *input = this->preprocessor_interperter_->input(0);
|
// The feature pipeline outputs 16-bit signed integers in roughly a 0 to 670
|
||||||
TfLiteTensor *output = this->preprocessor_interperter_->output(0);
|
// range. In training, these are then arbitrarily divided by 25.6 to get
|
||||||
std::copy_n(audio_data, audio_data_size, tflite::GetTensorData<int16_t>(input));
|
// float values in the rough range of 0.0 to 26.0. This scaling is performed
|
||||||
|
// for historical reasons, to match up with the output of other feature
|
||||||
if (this->preprocessor_interperter_->Invoke() != kTfLiteOk) {
|
// generators.
|
||||||
ESP_LOGE(TAG, "Failed to preprocess audio for local wake word.");
|
// The process is then further complicated when we quantize the model. This
|
||||||
return false;
|
// means we have to scale the 0.0 to 26.0 real values to the -128 to 127
|
||||||
|
// signed integer numbers.
|
||||||
|
// All this means that to get matching values from our integer feature
|
||||||
|
// output into the tensor input, we have to perform:
|
||||||
|
// input = (((feature / 25.6) / 26.0) * 256) - 128
|
||||||
|
// To simplify this and perform it in 32-bit integer math, we rearrange to:
|
||||||
|
// input = (feature * 256) / (25.6 * 26.0) - 128
|
||||||
|
constexpr int32_t value_scale = 256;
|
||||||
|
constexpr int32_t value_div = 666; // 666 = 25.6 * 26.0 after rounding
|
||||||
|
int32_t value = ((frontend_output.values[i] * value_scale) + (value_div / 2)) / value_div;
|
||||||
|
value -= 128;
|
||||||
|
if (value < -128) {
|
||||||
|
value = -128;
|
||||||
|
}
|
||||||
|
if (value > 127) {
|
||||||
|
value = 127;
|
||||||
|
}
|
||||||
|
features[i] = value;
|
||||||
}
|
}
|
||||||
std::memcpy(feature_output, tflite::GetTensorData<int8_t>(output), PREPROCESSOR_FEATURE_SIZE * sizeof(int8_t));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MicroWakeWord::register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver) {
|
void MicroWakeWord::reset_states_() {
|
||||||
if (op_resolver.AddReshape() != kTfLiteOk)
|
ESP_LOGD(TAG, "Resetting buffers and probabilities");
|
||||||
return false;
|
this->ring_buffer_->reset();
|
||||||
if (op_resolver.AddCast() != kTfLiteOk)
|
this->ignore_windows_ = -MIN_SLICES_BEFORE_DETECTION;
|
||||||
return false;
|
for (auto &model : this->wake_word_models_) {
|
||||||
if (op_resolver.AddStridedSlice() != kTfLiteOk)
|
model.reset_probabilities();
|
||||||
return false;
|
}
|
||||||
if (op_resolver.AddConcatenation() != kTfLiteOk)
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
return false;
|
this->vad_model_->reset_probabilities();
|
||||||
if (op_resolver.AddMul() != kTfLiteOk)
|
#endif
|
||||||
return false;
|
|
||||||
if (op_resolver.AddAdd() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddDiv() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddMinimum() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddMaximum() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddWindow() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddFftAutoScale() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddRfft() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddEnergy() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddFilterBank() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddFilterBankSquareRoot() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddFilterBankSpectralSubtraction() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddPCAN() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
if (op_resolver.AddFilterBankLog() != kTfLiteOk)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver) {
|
bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<20> &op_resolver) {
|
||||||
if (op_resolver.AddCallOnce() != kTfLiteOk)
|
if (op_resolver.AddCallOnce() != kTfLiteOk)
|
||||||
return false;
|
return false;
|
||||||
if (op_resolver.AddVarHandle() != kTfLiteOk)
|
if (op_resolver.AddVarHandle() != kTfLiteOk)
|
||||||
@ -496,6 +442,12 @@ bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> &
|
|||||||
return false;
|
return false;
|
||||||
if (op_resolver.AddMaxPool2D() != kTfLiteOk)
|
if (op_resolver.AddMaxPool2D() != kTfLiteOk)
|
||||||
return false;
|
return false;
|
||||||
|
if (op_resolver.AddPad() != kTfLiteOk)
|
||||||
|
return false;
|
||||||
|
if (op_resolver.AddPack() != kTfLiteOk)
|
||||||
|
return false;
|
||||||
|
if (op_resolver.AddSplitV() != kTfLiteOk)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -504,5 +456,3 @@ bool MicroWakeWord::register_streaming_ops_(tflite::MicroMutableOpResolver<17> &
|
|||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_ESP_IDF
|
#endif // USE_ESP_IDF
|
||||||
|
|
||||||
#endif // CLANG_TIDY
|
|
||||||
|
@ -1,21 +1,18 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
/**
|
|
||||||
* This is a workaround until we can figure out a way to get
|
|
||||||
* the tflite-micro idf component code available in CI
|
|
||||||
*
|
|
||||||
* */
|
|
||||||
//
|
|
||||||
#ifndef CLANG_TIDY
|
|
||||||
|
|
||||||
#ifdef USE_ESP_IDF
|
#ifdef USE_ESP_IDF
|
||||||
|
|
||||||
|
#include "preprocessor_settings.h"
|
||||||
|
#include "streaming_model.h"
|
||||||
|
|
||||||
#include "esphome/core/automation.h"
|
#include "esphome/core/automation.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/ring_buffer.h"
|
#include "esphome/core/ring_buffer.h"
|
||||||
|
|
||||||
#include "esphome/components/microphone/microphone.h"
|
#include "esphome/components/microphone/microphone.h"
|
||||||
|
|
||||||
|
#include <frontend_util.h>
|
||||||
|
|
||||||
#include <tensorflow/lite/core/c/common.h>
|
#include <tensorflow/lite/core/c/common.h>
|
||||||
#include <tensorflow/lite/micro/micro_interpreter.h>
|
#include <tensorflow/lite/micro/micro_interpreter.h>
|
||||||
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
|
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
|
||||||
@ -23,35 +20,6 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace micro_wake_word {
|
namespace micro_wake_word {
|
||||||
|
|
||||||
// The following are dictated by the preprocessor model
|
|
||||||
//
|
|
||||||
// The number of features the audio preprocessor generates per slice
|
|
||||||
static const uint8_t PREPROCESSOR_FEATURE_SIZE = 40;
|
|
||||||
// How frequently the preprocessor generates a new set of features
|
|
||||||
static const uint8_t FEATURE_STRIDE_MS = 20;
|
|
||||||
// Duration of each slice used as input into the preprocessor
|
|
||||||
static const uint8_t FEATURE_DURATION_MS = 30;
|
|
||||||
// Audio sample frequency in hertz
|
|
||||||
static const uint16_t AUDIO_SAMPLE_FREQUENCY = 16000;
|
|
||||||
// The number of old audio samples that are saved to be part of the next feature window
|
|
||||||
static const uint16_t HISTORY_SAMPLES_TO_KEEP =
|
|
||||||
((FEATURE_DURATION_MS - FEATURE_STRIDE_MS) * (AUDIO_SAMPLE_FREQUENCY / 1000));
|
|
||||||
// The number of new audio samples to receive to be included with the next feature window
|
|
||||||
static const uint16_t NEW_SAMPLES_TO_GET = (FEATURE_STRIDE_MS * (AUDIO_SAMPLE_FREQUENCY / 1000));
|
|
||||||
// The total number of audio samples included in the feature window
|
|
||||||
static const uint16_t SAMPLE_DURATION_COUNT = FEATURE_DURATION_MS * AUDIO_SAMPLE_FREQUENCY / 1000;
|
|
||||||
// Number of bytes in memory needed for the preprocessor arena
|
|
||||||
static const uint32_t PREPROCESSOR_ARENA_SIZE = 9528;
|
|
||||||
|
|
||||||
// The following configure the streaming wake word model
|
|
||||||
//
|
|
||||||
// The number of audio slices to process before accepting a positive detection
|
|
||||||
static const uint8_t MIN_SLICES_BEFORE_DETECTION = 74;
|
|
||||||
|
|
||||||
// Number of bytes in memory needed for the streaming wake word model
|
|
||||||
static const uint32_t STREAMING_MODEL_ARENA_SIZE = 64000;
|
|
||||||
static const uint32_t STREAMING_MODEL_VARIABLE_ARENA_SIZE = 1024;
|
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
IDLE,
|
IDLE,
|
||||||
START_MICROPHONE,
|
START_MICROPHONE,
|
||||||
@ -61,6 +29,9 @@ enum State {
|
|||||||
STOPPING_MICROPHONE,
|
STOPPING_MICROPHONE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The number of audio slices to process before accepting a positive detection
|
||||||
|
static const uint8_t MIN_SLICES_BEFORE_DETECTION = 74;
|
||||||
|
|
||||||
class MicroWakeWord : public Component {
|
class MicroWakeWord : public Component {
|
||||||
public:
|
public:
|
||||||
void setup() override;
|
void setup() override;
|
||||||
@ -73,28 +44,21 @@ class MicroWakeWord : public Component {
|
|||||||
|
|
||||||
bool is_running() const { return this->state_ != State::IDLE; }
|
bool is_running() const { return this->state_ != State::IDLE; }
|
||||||
|
|
||||||
bool initialize_models();
|
void set_features_step_size(uint8_t step_size) { this->features_step_size_ = step_size; }
|
||||||
|
|
||||||
std::string get_wake_word() { return this->wake_word_; }
|
|
||||||
|
|
||||||
// Increasing either of these will reduce the rate of false acceptances while increasing the false rejection rate
|
|
||||||
void set_probability_cutoff(float probability_cutoff) { this->probability_cutoff_ = probability_cutoff; }
|
|
||||||
void set_sliding_window_average_size(size_t size);
|
|
||||||
|
|
||||||
void set_microphone(microphone::Microphone *microphone) { this->microphone_ = microphone; }
|
void set_microphone(microphone::Microphone *microphone) { this->microphone_ = microphone; }
|
||||||
|
|
||||||
Trigger<std::string> *get_wake_word_detected_trigger() const { return this->wake_word_detected_trigger_; }
|
Trigger<std::string> *get_wake_word_detected_trigger() const { return this->wake_word_detected_trigger_; }
|
||||||
|
|
||||||
void set_model_start(const uint8_t *model_start) { this->model_start_ = model_start; }
|
void add_wake_word_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size,
|
||||||
void set_wake_word(const std::string &wake_word) { this->wake_word_ = wake_word; }
|
const std::string &wake_word, size_t tensor_arena_size);
|
||||||
|
|
||||||
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
|
void add_vad_model(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size,
|
||||||
|
size_t tensor_arena_size);
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void set_state_(State state);
|
|
||||||
int read_microphone_();
|
|
||||||
|
|
||||||
const uint8_t *model_start_;
|
|
||||||
std::string wake_word_;
|
|
||||||
|
|
||||||
microphone::Microphone *microphone_{nullptr};
|
microphone::Microphone *microphone_{nullptr};
|
||||||
Trigger<std::string> *wake_word_detected_trigger_ = new Trigger<std::string>();
|
Trigger<std::string> *wake_word_detected_trigger_ = new Trigger<std::string>();
|
||||||
State state_{State::IDLE};
|
State state_{State::IDLE};
|
||||||
@ -102,85 +66,93 @@ class MicroWakeWord : public Component {
|
|||||||
|
|
||||||
std::unique_ptr<RingBuffer> ring_buffer_;
|
std::unique_ptr<RingBuffer> ring_buffer_;
|
||||||
|
|
||||||
int16_t *input_buffer_;
|
std::vector<WakeWordModel> wake_word_models_;
|
||||||
|
|
||||||
const tflite::Model *preprocessor_model_{nullptr};
|
#ifdef USE_MICRO_WAKE_WORD_VAD
|
||||||
const tflite::Model *streaming_model_{nullptr};
|
std::unique_ptr<VADModel> vad_model_;
|
||||||
tflite::MicroInterpreter *streaming_interpreter_{nullptr};
|
#endif
|
||||||
tflite::MicroInterpreter *preprocessor_interperter_{nullptr};
|
|
||||||
|
|
||||||
std::vector<float> recent_streaming_probabilities_;
|
tflite::MicroMutableOpResolver<20> streaming_op_resolver_;
|
||||||
size_t last_n_index_{0};
|
|
||||||
|
|
||||||
float probability_cutoff_{0.5};
|
// Audio frontend handles generating spectrogram features
|
||||||
size_t sliding_window_average_size_{10};
|
struct FrontendConfig frontend_config_;
|
||||||
|
struct FrontendState frontend_state_;
|
||||||
|
|
||||||
// When the wake word detection first starts or after the word has been detected once, we ignore this many audio
|
// When the wake word detection first starts, we ignore this many audio
|
||||||
// feature slices before accepting a positive detection again
|
// feature slices before accepting a positive detection
|
||||||
int16_t ignore_windows_{-MIN_SLICES_BEFORE_DETECTION};
|
int16_t ignore_windows_{-MIN_SLICES_BEFORE_DETECTION};
|
||||||
|
|
||||||
uint8_t *streaming_var_arena_{nullptr};
|
uint8_t features_step_size_;
|
||||||
uint8_t *streaming_tensor_arena_{nullptr};
|
|
||||||
uint8_t *preprocessor_tensor_arena_{nullptr};
|
|
||||||
int8_t *new_features_data_{nullptr};
|
|
||||||
|
|
||||||
tflite::MicroResourceVariables *mrv_{nullptr};
|
// Stores audio read from the microphone before being added to the ring buffer.
|
||||||
|
int16_t *input_buffer_{nullptr};
|
||||||
// Stores audio fed into feature generator preprocessor
|
// Stores audio to be fed into the audio frontend for generating features.
|
||||||
int16_t *preprocessor_audio_buffer_;
|
int16_t *preprocessor_audio_buffer_{nullptr};
|
||||||
|
|
||||||
bool detected_{false};
|
bool detected_{false};
|
||||||
|
std::string detected_wake_word_{""};
|
||||||
|
|
||||||
/** Detects if wake word has been said
|
void set_state_(State state);
|
||||||
|
|
||||||
|
/// @brief Tests if there are enough samples in the ring buffer to generate new features.
|
||||||
|
/// @return True if enough samples, false otherwise.
|
||||||
|
bool has_enough_samples_();
|
||||||
|
|
||||||
|
/** Reads audio from microphone into the ring buffer
|
||||||
|
*
|
||||||
|
* Audio data (16000 kHz with int16 samples) is read into the input_buffer_.
|
||||||
|
* Verifies the ring buffer has enough space for all audio data. If not, it logs
|
||||||
|
* a warning and resets the ring buffer entirely.
|
||||||
|
* @return Number of bytes written to the ring buffer
|
||||||
|
*/
|
||||||
|
size_t read_microphone_();
|
||||||
|
|
||||||
|
/// @brief Allocates memory for input_buffer_, preprocessor_audio_buffer_, and ring_buffer_
|
||||||
|
/// @return True if successful, false otherwise
|
||||||
|
bool allocate_buffers_();
|
||||||
|
|
||||||
|
/// @brief Frees memory allocated for input_buffer_ and preprocessor_audio_buffer_
|
||||||
|
void deallocate_buffers_();
|
||||||
|
|
||||||
|
/// @brief Loads streaming models and prepares the feature generation frontend
|
||||||
|
/// @return True if successful, false otherwise
|
||||||
|
bool load_models_();
|
||||||
|
|
||||||
|
/// @brief Deletes each model's TFLite interpreters and frees tensor arena memory. Frees memory used by the feature
|
||||||
|
/// generation frontend.
|
||||||
|
void unload_models_();
|
||||||
|
|
||||||
|
/** Performs inference with each configured model
|
||||||
*
|
*
|
||||||
* If enough audio samples are available, it will generate one slice of new features.
|
* If enough audio samples are available, it will generate one slice of new features.
|
||||||
* If the streaming model predicts the wake word, then the nonstreaming model confirms it.
|
* It then loops through and performs inference with each of the loaded models.
|
||||||
* @param ring_Buffer Ring buffer containing raw audio samples
|
|
||||||
* @return True if the wake word is detected, false otherwise
|
|
||||||
*/
|
*/
|
||||||
bool detect_wake_word_();
|
void update_model_probabilities_();
|
||||||
|
|
||||||
/// @brief Returns true if there are enough audio samples in the buffer to generate another slice of features
|
/** Checks every model's recent probabilities to determine if the wake word has been predicted
|
||||||
bool slice_available_();
|
|
||||||
|
|
||||||
/** Shifts previous feature slices over by one and generates a new slice of features
|
|
||||||
*
|
*
|
||||||
* @param ring_buffer ring buffer containing raw audio samples
|
* Verifies the models have processed enough new samples for accurate predictions.
|
||||||
* @return True if a new slice of features was generated, false otherwise
|
* Sets detected_wake_word_ to the wake word, if one is detected.
|
||||||
|
* @return True if a wake word is predicted, false otherwise
|
||||||
*/
|
*/
|
||||||
bool update_features_();
|
bool detect_wake_words_();
|
||||||
|
|
||||||
/** Generates features from audio samples
|
/** Generates features for a window of audio samples
|
||||||
*
|
*
|
||||||
* Adapted from TFLite micro speech example
|
* Reads samples from the ring buffer and feeds them into the preprocessor frontend.
|
||||||
* @param audio_data Pointer to array with the audio samples
|
* Adapted from TFLite microspeech frontend.
|
||||||
* @param audio_data_size The number of samples to use as input to the preprocessor model
|
* @param features int8_t array to store the audio features
|
||||||
* @param feature_output Array that will store the features
|
|
||||||
* @return True if successful, false otherwise.
|
* @return True if successful, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool generate_single_feature_(const int16_t *audio_data, int audio_data_size,
|
bool generate_features_for_window_(int8_t features[PREPROCESSOR_FEATURE_SIZE]);
|
||||||
int8_t feature_output[PREPROCESSOR_FEATURE_SIZE]);
|
|
||||||
|
|
||||||
/** Performs inference over the most recent feature slice with the streaming model
|
/// @brief Resets the ring buffer, ignore_windows_, and sliding window probabilities
|
||||||
*
|
void reset_states_();
|
||||||
* @return Probability of the wake word between 0.0 and 1.0
|
|
||||||
*/
|
|
||||||
float perform_streaming_inference_();
|
|
||||||
|
|
||||||
/** Strides the audio samples by keeping the last 10 ms of the previous slice
|
|
||||||
*
|
|
||||||
* Adapted from the TFLite micro speech example
|
|
||||||
* @param ring_buffer Ring buffer containing raw audio samples
|
|
||||||
* @param audio_samples Pointer to an array that will store the strided audio samples
|
|
||||||
* @return True if successful, false otherwise
|
|
||||||
*/
|
|
||||||
bool stride_audio_samples_(int16_t **audio_samples);
|
|
||||||
|
|
||||||
/// @brief Returns true if successfully registered the preprocessor's TensorFlow operations
|
|
||||||
bool register_preprocessor_ops_(tflite::MicroMutableOpResolver<18> &op_resolver);
|
|
||||||
|
|
||||||
/// @brief Returns true if successfully registered the streaming model's TensorFlow operations
|
/// @brief Returns true if successfully registered the streaming model's TensorFlow operations
|
||||||
bool register_streaming_ops_(tflite::MicroMutableOpResolver<17> &op_resolver);
|
bool register_streaming_ops_(tflite::MicroMutableOpResolver<20> &op_resolver);
|
||||||
|
|
||||||
|
inline uint16_t new_samples_to_get_() { return (this->features_step_size_ * (AUDIO_SAMPLE_FREQUENCY / 1000)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<MicroWakeWord> {
|
template<typename... Ts> class StartAction : public Action<Ts...>, public Parented<MicroWakeWord> {
|
||||||
@ -202,5 +174,3 @@ template<typename... Ts> class IsRunningCondition : public Condition<Ts...>, pub
|
|||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
||||||
#endif // USE_ESP_IDF
|
#endif // USE_ESP_IDF
|
||||||
|
|
||||||
#endif // CLANG_TIDY
|
|
||||||
|
20
esphome/components/micro_wake_word/preprocessor_settings.h
Normal file
20
esphome/components/micro_wake_word/preprocessor_settings.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_ESP_IDF
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace micro_wake_word {
|
||||||
|
|
||||||
|
// The number of features the audio preprocessor generates per slice
|
||||||
|
static const uint8_t PREPROCESSOR_FEATURE_SIZE = 40;
|
||||||
|
// Duration of each slice used as input into the preprocessor
|
||||||
|
static const uint8_t FEATURE_DURATION_MS = 30;
|
||||||
|
// Audio sample frequency in hertz
|
||||||
|
static const uint16_t AUDIO_SAMPLE_FREQUENCY = 16000;
|
||||||
|
|
||||||
|
} // namespace micro_wake_word
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif
|
189
esphome/components/micro_wake_word/streaming_model.cpp
Normal file
189
esphome/components/micro_wake_word/streaming_model.cpp
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
#ifdef USE_ESP_IDF
|
||||||
|
|
||||||
|
#include "streaming_model.h"
|
||||||
|
|
||||||
|
#include "esphome/core/hal.h"
|
||||||
|
#include "esphome/core/helpers.h"
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
static const char *const TAG = "micro_wake_word";
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace micro_wake_word {
|
||||||
|
|
||||||
|
void WakeWordModel::log_model_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, " - Wake Word: %s", this->wake_word_.c_str());
|
||||||
|
ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VADModel::log_model_config() {
|
||||||
|
ESP_LOGCONFIG(TAG, " - VAD Model");
|
||||||
|
ESP_LOGCONFIG(TAG, " Probability cutoff: %.3f", this->probability_cutoff_);
|
||||||
|
ESP_LOGCONFIG(TAG, " Sliding window size: %d", this->sliding_window_size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StreamingModel::load_model(tflite::MicroMutableOpResolver<20> &op_resolver) {
|
||||||
|
ExternalRAMAllocator<uint8_t> arena_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
||||||
|
|
||||||
|
if (this->tensor_arena_ == nullptr) {
|
||||||
|
this->tensor_arena_ = arena_allocator.allocate(this->tensor_arena_size_);
|
||||||
|
if (this->tensor_arena_ == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Could not allocate the streaming model's tensor arena.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->var_arena_ == nullptr) {
|
||||||
|
this->var_arena_ = arena_allocator.allocate(STREAMING_MODEL_VARIABLE_ARENA_SIZE);
|
||||||
|
if (this->var_arena_ == nullptr) {
|
||||||
|
ESP_LOGE(TAG, "Could not allocate the streaming model's variable tensor arena.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this->ma_ = tflite::MicroAllocator::Create(this->var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
|
||||||
|
this->mrv_ = tflite::MicroResourceVariables::Create(this->ma_, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tflite::Model *model = tflite::GetModel(this->model_start_);
|
||||||
|
if (model->version() != TFLITE_SCHEMA_VERSION) {
|
||||||
|
ESP_LOGE(TAG, "Streaming model's schema is not supported");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->interpreter_ == nullptr) {
|
||||||
|
this->interpreter_ = make_unique<tflite::MicroInterpreter>(
|
||||||
|
tflite::GetModel(this->model_start_), op_resolver, this->tensor_arena_, this->tensor_arena_size_, this->mrv_);
|
||||||
|
if (this->interpreter_->AllocateTensors() != kTfLiteOk) {
|
||||||
|
ESP_LOGE(TAG, "Failed to allocate tensors for the streaming model");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify input tensor matches expected values
|
||||||
|
// Dimension 3 will represent the first layer stride, so skip it may vary
|
||||||
|
TfLiteTensor *input = this->interpreter_->input(0);
|
||||||
|
if ((input->dims->size != 3) || (input->dims->data[0] != 1) ||
|
||||||
|
(input->dims->data[2] != PREPROCESSOR_FEATURE_SIZE)) {
|
||||||
|
ESP_LOGE(TAG, "Streaming model tensor input dimensions has improper dimensions.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input->type != kTfLiteInt8) {
|
||||||
|
ESP_LOGE(TAG, "Streaming model tensor input is not int8.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify output tensor matches expected values
|
||||||
|
TfLiteTensor *output = this->interpreter_->output(0);
|
||||||
|
if ((output->dims->size != 2) || (output->dims->data[0] != 1) || (output->dims->data[1] != 1)) {
|
||||||
|
ESP_LOGE(TAG, "Streaming model tensor output dimension is not 1x1.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (output->type != kTfLiteUInt8) {
|
||||||
|
ESP_LOGE(TAG, "Streaming model tensor output is not uint8.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamingModel::unload_model() {
|
||||||
|
this->interpreter_.reset();
|
||||||
|
|
||||||
|
ExternalRAMAllocator<uint8_t> arena_allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
||||||
|
|
||||||
|
arena_allocator.deallocate(this->tensor_arena_, this->tensor_arena_size_);
|
||||||
|
this->tensor_arena_ = nullptr;
|
||||||
|
arena_allocator.deallocate(this->var_arena_, STREAMING_MODEL_VARIABLE_ARENA_SIZE);
|
||||||
|
this->var_arena_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StreamingModel::perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE]) {
|
||||||
|
if (this->interpreter_ != nullptr) {
|
||||||
|
TfLiteTensor *input = this->interpreter_->input(0);
|
||||||
|
|
||||||
|
std::memmove(
|
||||||
|
(int8_t *) (tflite::GetTensorData<int8_t>(input)) + PREPROCESSOR_FEATURE_SIZE * this->current_stride_step_,
|
||||||
|
features, PREPROCESSOR_FEATURE_SIZE);
|
||||||
|
++this->current_stride_step_;
|
||||||
|
|
||||||
|
uint8_t stride = this->interpreter_->input(0)->dims->data[1];
|
||||||
|
|
||||||
|
if (this->current_stride_step_ >= stride) {
|
||||||
|
this->current_stride_step_ = 0;
|
||||||
|
|
||||||
|
TfLiteStatus invoke_status = this->interpreter_->Invoke();
|
||||||
|
if (invoke_status != kTfLiteOk) {
|
||||||
|
ESP_LOGW(TAG, "Streaming interpreter invoke failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
TfLiteTensor *output = this->interpreter_->output(0);
|
||||||
|
|
||||||
|
++this->last_n_index_;
|
||||||
|
if (this->last_n_index_ == this->sliding_window_size_)
|
||||||
|
this->last_n_index_ = 0;
|
||||||
|
this->recent_streaming_probabilities_[this->last_n_index_] = output->data.uint8[0]; // probability;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ESP_LOGE(TAG, "Streaming interpreter is not initialized.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamingModel::reset_probabilities() {
|
||||||
|
for (auto &prob : this->recent_streaming_probabilities_) {
|
||||||
|
prob = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WakeWordModel::WakeWordModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size,
|
||||||
|
const std::string &wake_word, size_t tensor_arena_size) {
|
||||||
|
this->model_start_ = model_start;
|
||||||
|
this->probability_cutoff_ = probability_cutoff;
|
||||||
|
this->sliding_window_size_ = sliding_window_average_size;
|
||||||
|
this->recent_streaming_probabilities_.resize(sliding_window_average_size, 0);
|
||||||
|
this->wake_word_ = wake_word;
|
||||||
|
this->tensor_arena_size_ = tensor_arena_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool WakeWordModel::determine_detected() {
|
||||||
|
int32_t sum = 0;
|
||||||
|
for (auto &prob : this->recent_streaming_probabilities_) {
|
||||||
|
sum += prob;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sliding_window_average = static_cast<float>(sum) / static_cast<float>(255 * this->sliding_window_size_);
|
||||||
|
|
||||||
|
// Detect the wake word if the sliding window average is above the cutoff
|
||||||
|
if (sliding_window_average > this->probability_cutoff_) {
|
||||||
|
ESP_LOGD(TAG, "The '%s' model sliding average probability is %.3f and most recent probability is %.3f",
|
||||||
|
this->wake_word_.c_str(), sliding_window_average,
|
||||||
|
this->recent_streaming_probabilities_[this->last_n_index_] / (255.0));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
VADModel::VADModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size,
|
||||||
|
size_t tensor_arena_size) {
|
||||||
|
this->model_start_ = model_start;
|
||||||
|
this->probability_cutoff_ = probability_cutoff;
|
||||||
|
this->sliding_window_size_ = sliding_window_size;
|
||||||
|
this->recent_streaming_probabilities_.resize(sliding_window_size, 0);
|
||||||
|
this->tensor_arena_size_ = tensor_arena_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool VADModel::determine_detected() {
|
||||||
|
uint8_t max = 0;
|
||||||
|
for (auto &prob : this->recent_streaming_probabilities_) {
|
||||||
|
max = std::max(prob, max);
|
||||||
|
}
|
||||||
|
|
||||||
|
return max > this->probability_cutoff_;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace micro_wake_word
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif
|
84
esphome/components/micro_wake_word/streaming_model.h
Normal file
84
esphome/components/micro_wake_word/streaming_model.h
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef USE_ESP_IDF
|
||||||
|
|
||||||
|
#include "preprocessor_settings.h"
|
||||||
|
|
||||||
|
#include <tensorflow/lite/core/c/common.h>
|
||||||
|
#include <tensorflow/lite/micro/micro_interpreter.h>
|
||||||
|
#include <tensorflow/lite/micro/micro_mutable_op_resolver.h>
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace micro_wake_word {
|
||||||
|
|
||||||
|
static const uint32_t STREAMING_MODEL_VARIABLE_ARENA_SIZE = 1024;
|
||||||
|
|
||||||
|
class StreamingModel {
|
||||||
|
public:
|
||||||
|
virtual void log_model_config() = 0;
|
||||||
|
virtual bool determine_detected() = 0;
|
||||||
|
|
||||||
|
bool perform_streaming_inference(const int8_t features[PREPROCESSOR_FEATURE_SIZE]);
|
||||||
|
|
||||||
|
/// @brief Sets all recent_streaming_probabilities to 0
|
||||||
|
void reset_probabilities();
|
||||||
|
|
||||||
|
/// @brief Allocates tensor and variable arenas and sets up the model interpreter
|
||||||
|
/// @param op_resolver MicroMutableOpResolver object that must exist until the model is unloaded
|
||||||
|
/// @return True if successful, false otherwise
|
||||||
|
bool load_model(tflite::MicroMutableOpResolver<20> &op_resolver);
|
||||||
|
|
||||||
|
/// @brief Destroys the TFLite interpreter and frees the tensor and variable arenas' memory
|
||||||
|
void unload_model();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t current_stride_step_{0};
|
||||||
|
|
||||||
|
float probability_cutoff_;
|
||||||
|
size_t sliding_window_size_;
|
||||||
|
size_t last_n_index_{0};
|
||||||
|
size_t tensor_arena_size_;
|
||||||
|
std::vector<uint8_t> recent_streaming_probabilities_;
|
||||||
|
|
||||||
|
const uint8_t *model_start_;
|
||||||
|
uint8_t *tensor_arena_{nullptr};
|
||||||
|
uint8_t *var_arena_{nullptr};
|
||||||
|
std::unique_ptr<tflite::MicroInterpreter> interpreter_;
|
||||||
|
tflite::MicroResourceVariables *mrv_{nullptr};
|
||||||
|
tflite::MicroAllocator *ma_{nullptr};
|
||||||
|
};
|
||||||
|
|
||||||
|
class WakeWordModel final : public StreamingModel {
|
||||||
|
public:
|
||||||
|
WakeWordModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_average_size,
|
||||||
|
const std::string &wake_word, size_t tensor_arena_size);
|
||||||
|
|
||||||
|
void log_model_config() override;
|
||||||
|
|
||||||
|
/// @brief Checks for the wake word by comparing the mean probability in the sliding window with the probability
|
||||||
|
/// cutoff
|
||||||
|
/// @return True if wake word is detected, false otherwise
|
||||||
|
bool determine_detected() override;
|
||||||
|
|
||||||
|
const std::string &get_wake_word() const { return this->wake_word_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::string wake_word_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class VADModel final : public StreamingModel {
|
||||||
|
public:
|
||||||
|
VADModel(const uint8_t *model_start, float probability_cutoff, size_t sliding_window_size, size_t tensor_arena_size);
|
||||||
|
|
||||||
|
void log_model_config() override;
|
||||||
|
|
||||||
|
/// @brief Checks for voice activity by comparing the max probability in the sliding window with the probability
|
||||||
|
/// cutoff
|
||||||
|
/// @return True if voice activity is detected, false otherwise
|
||||||
|
bool determine_detected() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace micro_wake_word
|
||||||
|
} // namespace esphome
|
||||||
|
|
||||||
|
#endif
|
@ -86,6 +86,7 @@
|
|||||||
#define USE_ESP32_BLE_SERVER
|
#define USE_ESP32_BLE_SERVER
|
||||||
#define USE_ESP32_CAMERA
|
#define USE_ESP32_CAMERA
|
||||||
#define USE_IMPROV
|
#define USE_IMPROV
|
||||||
|
#define USE_MICRO_WAKE_WORD_VAD
|
||||||
#define USE_MICROPHONE
|
#define USE_MICROPHONE
|
||||||
#define USE_PSRAM
|
#define USE_PSRAM
|
||||||
#define USE_SOCKET_IMPL_BSD_SOCKETS
|
#define USE_SOCKET_IMPL_BSD_SOCKETS
|
||||||
|
@ -143,6 +143,7 @@ framework = espidf
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
${common:idf.lib_deps}
|
${common:idf.lib_deps}
|
||||||
droscy/esp_wireguard@0.4.2 ; wireguard
|
droscy/esp_wireguard@0.4.2 ; wireguard
|
||||||
|
kahrendt/ESPMicroSpeechFeatures@1.0.0 ; micro_wake_word
|
||||||
build_flags =
|
build_flags =
|
||||||
${common:idf.build_flags}
|
${common:idf.build_flags}
|
||||||
-Wno-nonnull-compare
|
-Wno-nonnull-compare
|
||||||
|
@ -10,6 +10,10 @@ microphone:
|
|||||||
pdm: true
|
pdm: true
|
||||||
|
|
||||||
micro_wake_word:
|
micro_wake_word:
|
||||||
model: hey_jarvis
|
|
||||||
on_wake_word_detected:
|
on_wake_word_detected:
|
||||||
- logger.log: "Wake word detected"
|
- logger.log: "Wake word detected"
|
||||||
|
models:
|
||||||
|
- model: hey_jarvis
|
||||||
|
probability_cutoff: 0.7
|
||||||
|
- model: okay_nabu
|
||||||
|
sliding_window_size: 5
|
||||||
|
1
tests/components/micro_wake_word/test.esp32-idf.yaml
Normal file
1
tests/components/micro_wake_word/test.esp32-idf.yaml
Normal file
@ -0,0 +1 @@
|
|||||||
|
<<: !include common.yaml
|
Loading…
Reference in New Issue
Block a user