inoryQwQ commited on
Commit
8784afc
·
1 Parent(s): 74c35f0

Remove C++ sources/build scripts from HF release (keep precompiled binaries only)

Browse files

Per HF release convention, only prebuilt artifacts belong on the Hub:
- keep cpp/bin/openwakeword_ax650 / openwakeword_ax630c
- remove cpp sources (openwakeword_ax.cpp, engine_wrapper, wav_reader),
CMakeLists.txt, build/download scripts; source stays in the GitHub repo
- also drop tracked __pycache__ from scripts/

cpp/CMakeLists.txt DELETED
@@ -1,57 +0,0 @@
1
- cmake_minimum_required(VERSION 3.13)
2
- project(openwakeword_axera_cpp LANGUAGES C CXX)
3
-
4
- set(CMAKE_CXX_STANDARD 17)
5
- set(CMAKE_CXX_STANDARD_REQUIRED ON)
6
- set(CMAKE_BUILD_TYPE Release CACHE STRING "")
7
-
8
- set(AXERA_TARGET "AX650" CACHE STRING "AXERA target: AX650 or AX630C")
9
- set_property(CACHE AXERA_TARGET PROPERTY STRINGS AX650 AX630C)
10
- string(TOUPPER "${AXERA_TARGET}" AXERA_TARGET)
11
- if(AXERA_TARGET STREQUAL "AX650")
12
- set(KWS_EXECUTABLE openwakeword_ax650)
13
- set(DEFAULT_BSP_MSP_DIR
14
- "${CMAKE_SOURCE_DIR}/toolchains/ax650n_bsp_sdk/msp/out")
15
- elseif(AXERA_TARGET STREQUAL "AX630C")
16
- set(KWS_EXECUTABLE openwakeword_ax630c)
17
- set(DEFAULT_BSP_MSP_DIR
18
- "${CMAKE_SOURCE_DIR}/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc")
19
- else()
20
- message(FATAL_ERROR "AXERA_TARGET must be AX650 or AX630C")
21
- endif()
22
-
23
- set(BSP_MSP_DIR "${DEFAULT_BSP_MSP_DIR}" CACHE PATH
24
- "BSP directory containing include/ and lib/")
25
- if(NOT EXISTS "${BSP_MSP_DIR}/include/ax_engine_api.h")
26
- message(FATAL_ERROR
27
- "${AXERA_TARGET} BSP not found: ${BSP_MSP_DIR}. "
28
- "Set BSP_MSP_DIR to the directory containing include/ and lib/.")
29
- endif()
30
-
31
- add_executable(${KWS_EXECUTABLE}
32
- openwakeword_ax.cpp
33
- src/engine_wrapper.cpp
34
- )
35
- target_include_directories(${KWS_EXECUTABLE} PRIVATE
36
- ${CMAKE_SOURCE_DIR}
37
- ${CMAKE_SOURCE_DIR}/src
38
- ${BSP_MSP_DIR}/include
39
- )
40
- target_link_directories(${KWS_EXECUTABLE} PRIVATE ${BSP_MSP_DIR}/lib)
41
- target_compile_definitions(${KWS_EXECUTABLE} PRIVATE
42
- AXERA_TARGET_NAME="${AXERA_TARGET}"
43
- )
44
- target_compile_options(${KWS_EXECUTABLE} PRIVATE
45
- -O3 -Wall -Wextra -Wpedantic
46
- -fvisibility=hidden -fdata-sections -ffunction-sections
47
- )
48
- target_link_libraries(${KWS_EXECUTABLE} PRIVATE
49
- ax_sys ax_engine ax_interpreter pthread dl m
50
- )
51
- target_link_options(${KWS_EXECUTABLE} PRIVATE
52
- -Wl,--enable-new-dtags -Wl,--allow-shlib-undefined
53
- )
54
- set_target_properties(${KWS_EXECUTABLE} PROPERTIES
55
- BUILD_WITH_INSTALL_RPATH TRUE
56
- INSTALL_RPATH "$ORIGIN"
57
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/README.md CHANGED
@@ -87,3 +87,10 @@ CPU mel 和 NPU 推理,不包含一次性模型加载与初始化。
87
  THRESHOLD=0.6 AUDIO=audio/openwakeword/hey_mycroft_test.wav \
88
  bash cpp/run_openwakeword_ax630c.sh
89
  ```
 
 
 
 
 
 
 
 
87
  THRESHOLD=0.6 AUDIO=audio/openwakeword/hey_mycroft_test.wav \
88
  bash cpp/run_openwakeword_ax630c.sh
89
  ```
90
+
91
+ ## 源码
92
+
93
+ C++ 源码、构建脚本与 BSP 下载脚本在 GitHub 仓库:
94
+ https://github.com/AXERA-TECH/openWakeWord.AXERA
95
+ (HuggingFace 仅发布预编译二进制。)
96
+
cpp/build_ax630c.sh DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
- CPP_DIR="${ROOT}/cpp"
6
- TOOLCHAIN_ROOT="${TOOLCHAIN_ROOT:-${CPP_DIR}/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu}"
7
- BSP_MSP_DIR="${BSP_MSP_DIR:-${CPP_DIR}/toolchains/ax620e_bsp_sdk/msp/out/arm64_glibc}"
8
- BUILD_DIR="${CPP_DIR}/build/ax630c"
9
-
10
- if [[ ! -x "${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" ]]; then
11
- echo "ERROR: AArch64 toolchain not found: ${TOOLCHAIN_ROOT}" >&2
12
- exit 2
13
- fi
14
- if [[ ! -f "${BSP_MSP_DIR}/include/ax_engine_api.h" ]]; then
15
- echo "ERROR: AX630C BSP arm64_glibc directory not found: ${BSP_MSP_DIR}" >&2
16
- exit 2
17
- fi
18
-
19
- mkdir -p "${BUILD_DIR}" "${CPP_DIR}/bin"
20
- cmake -S "${CPP_DIR}" -B "${BUILD_DIR}" \
21
- -DCMAKE_BUILD_TYPE=Release \
22
- -DCMAKE_SYSTEM_NAME=Linux \
23
- -DCMAKE_SYSTEM_PROCESSOR=aarch64 \
24
- -DCMAKE_C_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-gcc" \
25
- -DCMAKE_CXX_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" \
26
- -DAXERA_TARGET=AX630C \
27
- -DBSP_MSP_DIR="${BSP_MSP_DIR}"
28
- cmake --build "${BUILD_DIR}" -j"$(nproc)"
29
- cp "${BUILD_DIR}/openwakeword_ax630c" "${CPP_DIR}/bin/"
30
- "${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-strip" --strip-unneeded \
31
- "${CPP_DIR}/bin/openwakeword_ax630c"
32
- echo "Built ${CPP_DIR}/bin/openwakeword_ax630c"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/build_ax650.sh DELETED
@@ -1,32 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
- CPP_DIR="${ROOT}/cpp"
6
- TOOLCHAIN_ROOT="${TOOLCHAIN_ROOT:-${CPP_DIR}/toolchains/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu}"
7
- BSP_MSP_DIR="${BSP_MSP_DIR:-${CPP_DIR}/toolchains/ax650n_bsp_sdk/msp/out}"
8
- BUILD_DIR="${CPP_DIR}/build/ax650"
9
-
10
- if [[ ! -x "${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" ]]; then
11
- echo "ERROR: AArch64 toolchain not found: ${TOOLCHAIN_ROOT}" >&2
12
- exit 2
13
- fi
14
- if [[ ! -f "${BSP_MSP_DIR}/include/ax_engine_api.h" ]]; then
15
- echo "ERROR: AX650 BSP msp/out not found: ${BSP_MSP_DIR}" >&2
16
- exit 2
17
- fi
18
-
19
- mkdir -p "${BUILD_DIR}" "${CPP_DIR}/bin"
20
- cmake -S "${CPP_DIR}" -B "${BUILD_DIR}" \
21
- -DCMAKE_BUILD_TYPE=Release \
22
- -DCMAKE_SYSTEM_NAME=Linux \
23
- -DCMAKE_SYSTEM_PROCESSOR=aarch64 \
24
- -DCMAKE_C_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-gcc" \
25
- -DCMAKE_CXX_COMPILER="${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-g++" \
26
- -DAXERA_TARGET=AX650 \
27
- -DBSP_MSP_DIR="${BSP_MSP_DIR}"
28
- cmake --build "${BUILD_DIR}" -j"$(nproc)"
29
- cp "${BUILD_DIR}/openwakeword_ax650" "${CPP_DIR}/bin/"
30
- "${TOOLCHAIN_ROOT}/bin/aarch64-none-linux-gnu-strip" --strip-unneeded \
31
- "${CPP_DIR}/bin/openwakeword_ax650"
32
- echo "Built ${CPP_DIR}/bin/openwakeword_ax650"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/download_bsp.sh DELETED
@@ -1,45 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
-
4
- CPP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
- TOOLCHAINS_DIR="${CPP_DIR}/toolchains"
6
- PLATFORM="${1:-all}"
7
-
8
- download_sdk() {
9
- local directory="$1"
10
- local archive_name="$2"
11
- local extracted_name="$3"
12
- local url="$4"
13
-
14
- if [[ -d "${TOOLCHAINS_DIR}/${directory}" ]]; then
15
- echo "Found ${TOOLCHAINS_DIR}/${directory}"
16
- return
17
- fi
18
- mkdir -p "${TOOLCHAINS_DIR}"
19
- wget -c "${url}" -O "${TOOLCHAINS_DIR}/${archive_name}"
20
- unzip -q "${TOOLCHAINS_DIR}/${archive_name}" -d "${TOOLCHAINS_DIR}"
21
- mv "${TOOLCHAINS_DIR}/${extracted_name}" "${TOOLCHAINS_DIR}/${directory}"
22
- rm -f "${TOOLCHAINS_DIR}/${archive_name}"
23
- echo "Downloaded ${TOOLCHAINS_DIR}/${directory}"
24
- }
25
-
26
- case "${PLATFORM}" in
27
- 650|AX650|ax650)
28
- download_sdk \
29
- ax650n_bsp_sdk msp_50_3.10.2.zip msp_50_3.10.2 \
30
- https://github.com/ZHEQIUSHUI/assets/releases/download/ax_3.6.2/msp_50_3.10.2.zip
31
- ;;
32
- 630C|AX630C|ax630c)
33
- download_sdk \
34
- ax620e_bsp_sdk msp_20e_3.0.0.zip msp_20e_3.0.0 \
35
- https://github.com/ZHEQIUSHUI/assets/releases/download/ax_3.6.2/msp_20e_3.0.0.zip
36
- ;;
37
- all)
38
- bash "${BASH_SOURCE[0]}" 650
39
- bash "${BASH_SOURCE[0]}" 630C
40
- ;;
41
- *)
42
- echo "Usage: bash cpp/download_bsp.sh [650|630C|all]" >&2
43
- exit 2
44
- ;;
45
- esac
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/openwakeword_ax.cpp DELETED
@@ -1,379 +0,0 @@
1
- #include <algorithm>
2
- #include <array>
3
- #include <chrono>
4
- #include <cmath>
5
- #include <cstdint>
6
- #include <cstdio>
7
- #include <cstring>
8
- #include <fstream>
9
- #include <limits>
10
- #include <stdexcept>
11
- #include <string>
12
- #include <vector>
13
-
14
- #include "ax_engine_api.h"
15
- #include "ax_sys_api.h"
16
- #include "src/engine_wrapper.hpp"
17
- #include "src/wav_reader.hpp"
18
-
19
- #ifndef AXERA_TARGET_NAME
20
- #define AXERA_TARGET_NAME "AXERA"
21
- #endif
22
-
23
- namespace {
24
- constexpr int kSampleRate = 16000;
25
- constexpr int kChunkSamples = 1280;
26
- constexpr int kHistorySamples = 480;
27
- constexpr int kFftSize = 512;
28
- constexpr int kSpectrumBins = 257;
29
- constexpr int kMelBins = 32;
30
- constexpr int kMelFrames = 8;
31
- constexpr int kEmbeddingFrames = 76;
32
- constexpr int kEmbeddingSize = 96;
33
- constexpr int kFeatureFrames = 34;
34
- using Clock = std::chrono::steady_clock;
35
-
36
- double ElapsedSeconds(Clock::time_point begin, Clock::time_point end) {
37
- return std::chrono::duration<double>(end - begin).count();
38
- }
39
-
40
- struct Args {
41
- std::string models_dir = "models";
42
- std::string weights = "config/openwakeword_mel_weights.bin";
43
- std::string audio = "audio/openwakeword/alexa_test.wav";
44
- float threshold = 0.5f;
45
- };
46
-
47
- void Usage(const char *program) {
48
- std::printf(
49
- "Usage: %s [--models-dir DIR] [--mel-weights FILE] [--audio WAV] "
50
- "[--threshold VALUE]\n",
51
- program);
52
- }
53
-
54
- Args ParseArgs(int argc, char **argv) {
55
- Args args;
56
- for (int i = 1; i < argc; ++i) {
57
- const std::string key = argv[i];
58
- auto value = [&]() -> std::string {
59
- if (++i >= argc) throw std::runtime_error("Missing value for " + key);
60
- return argv[i];
61
- };
62
- if (key == "--models-dir") {
63
- args.models_dir = value();
64
- } else if (key == "--mel-weights") {
65
- args.weights = value();
66
- } else if (key == "--audio") {
67
- args.audio = value();
68
- } else if (key == "--threshold") {
69
- args.threshold = std::stof(value());
70
- } else if (key == "-h" || key == "--help") {
71
- Usage(argv[0]);
72
- std::exit(0);
73
- } else {
74
- throw std::runtime_error("Unknown argument: " + key);
75
- }
76
- }
77
- return args;
78
- }
79
-
80
- std::string Join(const std::string &left, const std::string &right) {
81
- return left.empty() || left.back() == '/' ? left + right
82
- : left + "/" + right;
83
- }
84
-
85
- class AxRuntime {
86
- public:
87
- AxRuntime() {
88
- if (AX_SYS_Init() != 0) throw std::runtime_error("AX_SYS_Init failed");
89
- sys_initialized_ = true;
90
- AX_ENGINE_NPU_ATTR_T attr{};
91
- if (AX_ENGINE_Init(&attr) != 0) {
92
- AX_SYS_Deinit();
93
- sys_initialized_ = false;
94
- throw std::runtime_error("AX_ENGINE_Init failed");
95
- }
96
- engine_initialized_ = true;
97
- }
98
- ~AxRuntime() {
99
- if (engine_initialized_) AX_ENGINE_Deinit();
100
- if (sys_initialized_) AX_SYS_Deinit();
101
- }
102
-
103
- private:
104
- bool sys_initialized_ = false;
105
- bool engine_initialized_ = false;
106
- };
107
-
108
- template <typename T>
109
- T ReadScalar(std::istream &input) {
110
- T value{};
111
- input.read(reinterpret_cast<char *>(&value), sizeof(value));
112
- if (!input) throw std::runtime_error("Truncated mel weight file");
113
- return value;
114
- }
115
-
116
- struct MelWeights {
117
- std::vector<float> real;
118
- std::vector<float> imag;
119
- std::vector<float> mel;
120
- float floor = 0.0f;
121
-
122
- static MelWeights Load(const std::string &path) {
123
- std::ifstream input(path, std::ios::binary);
124
- if (!input) throw std::runtime_error("Cannot open mel weights: " + path);
125
- char magic[8]{};
126
- input.read(magic, 8);
127
- if (std::memcmp(magic, "OWWMEL1", 7) != 0 ||
128
- ReadScalar<uint32_t>(input) != 1) {
129
- throw std::runtime_error("Invalid openWakeWord mel weight file");
130
- }
131
- const uint32_t real_rows = ReadScalar<uint32_t>(input);
132
- const uint32_t real_cols = ReadScalar<uint32_t>(input);
133
- const uint32_t imag_rows = ReadScalar<uint32_t>(input);
134
- const uint32_t imag_cols = ReadScalar<uint32_t>(input);
135
- const uint32_t mel_rows = ReadScalar<uint32_t>(input);
136
- const uint32_t mel_cols = ReadScalar<uint32_t>(input);
137
- MelWeights result;
138
- result.floor = ReadScalar<float>(input);
139
- if (real_rows != kSpectrumBins || real_cols != kFftSize ||
140
- imag_rows != kSpectrumBins || imag_cols != kFftSize ||
141
- mel_rows != kSpectrumBins || mel_cols != kMelBins) {
142
- throw std::runtime_error("Unexpected openWakeWord mel weight shapes");
143
- }
144
- result.real.resize(static_cast<std::size_t>(real_rows) * real_cols);
145
- result.imag.resize(static_cast<std::size_t>(imag_rows) * imag_cols);
146
- result.mel.resize(static_cast<std::size_t>(mel_rows) * mel_cols);
147
- input.read(reinterpret_cast<char *>(result.real.data()),
148
- result.real.size() * sizeof(float));
149
- input.read(reinterpret_cast<char *>(result.imag.data()),
150
- result.imag.size() * sizeof(float));
151
- input.read(reinterpret_cast<char *>(result.mel.data()),
152
- result.mel.size() * sizeof(float));
153
- if (!input) throw std::runtime_error("Truncated openWakeWord mel weights");
154
- return result;
155
- }
156
- };
157
-
158
- std::array<float, kMelFrames * kMelBins> ComputeMel(
159
- const std::array<float, kHistorySamples + kChunkSamples> &samples,
160
- const MelWeights &weights) {
161
- std::array<float, kMelFrames * kMelBins> result{};
162
- std::array<float, kSpectrumBins> power{};
163
- float max_db = -std::numeric_limits<float>::infinity();
164
- for (int frame = 0; frame < kMelFrames; ++frame) {
165
- const float *frame_samples = samples.data() + frame * 160;
166
- for (int frequency = 0; frequency < kSpectrumBins; ++frequency) {
167
- const float *real = weights.real.data() + frequency * kFftSize;
168
- const float *imag = weights.imag.data() + frequency * kFftSize;
169
- float real_sum = 0.0f;
170
- float imag_sum = 0.0f;
171
- for (int n = 0; n < kFftSize; ++n) {
172
- real_sum += frame_samples[n] * real[n];
173
- imag_sum += frame_samples[n] * imag[n];
174
- }
175
- power[frequency] = real_sum * real_sum + imag_sum * imag_sum;
176
- }
177
- for (int bin = 0; bin < kMelBins; ++bin) {
178
- float value = 0.0f;
179
- for (int frequency = 0; frequency < kSpectrumBins; ++frequency) {
180
- value += power[frequency] *
181
- weights.mel[frequency * kMelBins + bin];
182
- }
183
- value = std::max(value, weights.floor);
184
- const float db = std::log(value) * 10.0f / 2.3025851249694824f;
185
- result[frame * kMelBins + bin] = db;
186
- max_db = std::max(max_db, db);
187
- }
188
- }
189
- const float minimum = max_db - 80.0f;
190
- for (float &value : result) {
191
- value = std::max(value, minimum) / 10.0f + 2.0f;
192
- }
193
- return result;
194
- }
195
-
196
- struct Classifier {
197
- std::string name;
198
- int frames;
199
- EngineWrapper engine;
200
- std::vector<float> maximum;
201
- };
202
-
203
- void Run(const Args &args) {
204
- const PcmWav wav = ReadPcmWav(args.audio);
205
- if (wav.sample_rate != kSampleRate) {
206
- throw std::runtime_error("Input WAV must use 16 kHz sample rate");
207
- }
208
- const double audio_seconds =
209
- static_cast<double>(wav.samples.size()) / kSampleRate;
210
- if (audio_seconds <= 0.0) {
211
- throw std::runtime_error("Input WAV contains no samples");
212
- }
213
- const MelWeights weights = MelWeights::Load(args.weights);
214
- const auto model_load_begin = Clock::now();
215
- AxRuntime runtime;
216
-
217
- EngineWrapper embedding;
218
- if (embedding.Init(Join(args.models_dir,
219
- "openwakeword__embedding_model.axmodel")) != 0) {
220
- throw std::runtime_error("Failed to load embedding model");
221
- }
222
- const std::array<std::pair<const char *, int>, 6> definitions{{
223
- {"alexa_v0.1", 16},
224
- {"hey_jarvis_v0.1", 16},
225
- {"hey_mycroft_v0.1", 16},
226
- {"hey_rhasspy_v0.1", 16},
227
- {"timer_v0.1", 34},
228
- {"weather_v0.1", 22},
229
- }};
230
- std::array<Classifier, 6> classifiers;
231
- for (std::size_t classifier_index = 0;
232
- classifier_index < definitions.size(); ++classifier_index) {
233
- const auto &definition = definitions[classifier_index];
234
- Classifier &classifier = classifiers[classifier_index];
235
- classifier.name = definition.first;
236
- classifier.frames = definition.second;
237
- const std::string model =
238
- Join(args.models_dir, "openwakeword__" + classifier.name + ".axmodel");
239
- if (classifier.engine.Init(model) != 0) {
240
- throw std::runtime_error("Failed to load classifier: " + classifier.name);
241
- }
242
- const int output_bytes = classifier.engine.GetOutputSizeByName(
243
- classifier.engine.OutputName(0));
244
- if (output_bytes <= 0 || output_bytes % sizeof(float) != 0) {
245
- throw std::runtime_error("Unexpected classifier output: " +
246
- classifier.name);
247
- }
248
- classifier.maximum.assign(output_bytes / sizeof(float),
249
- -std::numeric_limits<float>::infinity());
250
- }
251
- const double model_load_seconds =
252
- ElapsedSeconds(model_load_begin, Clock::now());
253
-
254
- std::vector<int16_t> padded = wav.samples;
255
- const std::size_t remainder = padded.size() % kChunkSamples;
256
- if (remainder != 0) padded.resize(padded.size() + kChunkSamples - remainder);
257
- std::array<int16_t, kHistorySamples> history{};
258
- std::array<float, kEmbeddingFrames * kMelBins> mel_buffer{};
259
- mel_buffer.fill(1.0f);
260
- std::array<float, kFeatureFrames * kEmbeddingSize> feature_buffer{};
261
- int chunks = 0;
262
- double feature_seconds = 0.0;
263
- double npu_seconds = 0.0;
264
- const auto inference_begin = Clock::now();
265
-
266
- for (std::size_t start = 0; start < padded.size(); start += kChunkSamples) {
267
- std::array<float, kHistorySamples + kChunkSamples> mel_input{};
268
- for (int i = 0; i < kHistorySamples; ++i) mel_input[i] = history[i];
269
- for (int i = 0; i < kChunkSamples; ++i) {
270
- mel_input[kHistorySamples + i] = padded[start + i];
271
- }
272
- for (int i = 0; i < kHistorySamples; ++i) {
273
- history[i] = padded[start + kChunkSamples - kHistorySamples + i];
274
- }
275
- const auto feature_begin = Clock::now();
276
- const auto mel = ComputeMel(mel_input, weights);
277
- feature_seconds += ElapsedSeconds(feature_begin, Clock::now());
278
- std::memmove(mel_buffer.data(), mel_buffer.data() + kMelFrames * kMelBins,
279
- (kEmbeddingFrames - kMelFrames) * kMelBins * sizeof(float));
280
- std::memcpy(mel_buffer.data() +
281
- (kEmbeddingFrames - kMelFrames) * kMelBins,
282
- mel.data(), mel.size() * sizeof(float));
283
-
284
- const std::string &embedding_input = embedding.InputName(0);
285
- if (embedding.SetInputByName(embedding_input, mel_buffer.data(),
286
- mel_buffer.size() * sizeof(float)) != 0) {
287
- throw std::runtime_error("Failed to set embedding input");
288
- }
289
- const auto embedding_begin = Clock::now();
290
- const int embedding_ret = embedding.RunSync();
291
- npu_seconds += ElapsedSeconds(embedding_begin, Clock::now());
292
- if (embedding_ret != 0) {
293
- throw std::runtime_error("Embedding inference failed");
294
- }
295
- std::array<float, kEmbeddingSize> feature{};
296
- if (embedding.GetOutputByName(embedding.OutputName(0), feature.data(),
297
- feature.size() * sizeof(float)) != 0) {
298
- throw std::runtime_error("Failed to read embedding output");
299
- }
300
- std::memmove(feature_buffer.data(), feature_buffer.data() + kEmbeddingSize,
301
- (kFeatureFrames - 1) * kEmbeddingSize * sizeof(float));
302
- std::memcpy(feature_buffer.data() +
303
- (kFeatureFrames - 1) * kEmbeddingSize,
304
- feature.data(), feature.size() * sizeof(float));
305
-
306
- for (Classifier &classifier : classifiers) {
307
- const float *input =
308
- feature_buffer.data() +
309
- (kFeatureFrames - classifier.frames) * kEmbeddingSize;
310
- const std::string &input_name = classifier.engine.InputName(0);
311
- if (classifier.engine.SetInputByName(
312
- input_name, input,
313
- classifier.frames * kEmbeddingSize * sizeof(float)) != 0) {
314
- throw std::runtime_error("Failed to set classifier input: " +
315
- classifier.name);
316
- }
317
- const auto classifier_begin = Clock::now();
318
- const int classifier_ret = classifier.engine.RunSync();
319
- npu_seconds += ElapsedSeconds(classifier_begin, Clock::now());
320
- if (classifier_ret != 0) {
321
- throw std::runtime_error("Classifier inference failed: " +
322
- classifier.name);
323
- }
324
- std::vector<float> output(classifier.maximum.size());
325
- if (classifier.engine.GetOutputByName(
326
- classifier.engine.OutputName(0), output.data(),
327
- output.size() * sizeof(float)) != 0) {
328
- throw std::runtime_error("Failed to read classifier output");
329
- }
330
- for (std::size_t i = 0; i < output.size(); ++i) {
331
- classifier.maximum[i] = std::max(classifier.maximum[i], output[i]);
332
- }
333
- }
334
- ++chunks;
335
- }
336
- const double inference_seconds =
337
- ElapsedSeconds(inference_begin, Clock::now());
338
- const double rtf = inference_seconds / audio_seconds;
339
-
340
- std::printf("\nopenWakeWord C++ inference complete\n");
341
- std::printf("target: %s\naudio: %s\nchunks: %d\nthreshold: %.3f\n",
342
- AXERA_TARGET_NAME, args.audio.c_str(), chunks, args.threshold);
343
- bool detected = false;
344
- for (const Classifier &classifier : classifiers) {
345
- std::printf("%-22s", classifier.name.c_str());
346
- float score = -std::numeric_limits<float>::infinity();
347
- for (std::size_t i = 0; i < classifier.maximum.size(); ++i) {
348
- const float value = classifier.maximum[i];
349
- std::printf(" %.6f", value);
350
- if (classifier.name != "timer_v0.1" || i != 0) {
351
- score = std::max(score, value);
352
- }
353
- }
354
- if (score >= args.threshold) {
355
- std::printf(" WAKEUP");
356
- detected = true;
357
- }
358
- std::printf("\n");
359
- }
360
- std::printf("detected: %s\n", detected ? "true" : "false");
361
- std::printf("audio_seconds: %.6f\n", audio_seconds);
362
- std::printf("feature_seconds: %.6f\n", feature_seconds);
363
- std::printf("npu_seconds: %.6f\n", npu_seconds);
364
- std::printf("model_load_seconds: %.6f\n", model_load_seconds);
365
- std::printf("inference_seconds: %.6f\n", inference_seconds);
366
- std::printf("rtf: %.6f\n", rtf);
367
- }
368
- } // namespace
369
-
370
- int main(int argc, char **argv) {
371
- try {
372
- const Args args = ParseArgs(argc, argv);
373
- Run(args);
374
- return 0;
375
- } catch (const std::exception &error) {
376
- std::fprintf(stderr, "ERROR: %s\n", error.what());
377
- return 1;
378
- }
379
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/engine_wrapper.cpp DELETED
@@ -1,197 +0,0 @@
1
- #include "engine_wrapper.hpp"
2
-
3
- #include <cstdio>
4
- #include <cstring>
5
- #include <fstream>
6
- #include <vector>
7
-
8
- #include "ax_sys_api.h"
9
-
10
- namespace {
11
- constexpr int kAlignment = 128;
12
-
13
- void FreeIo(AX_ENGINE_IO_T *io) {
14
- for (AX_U32 i = 0; io->pInputs && i < io->nInputSize; ++i) {
15
- if (io->pInputs[i].pVirAddr) {
16
- AX_SYS_MemFree(io->pInputs[i].phyAddr, io->pInputs[i].pVirAddr);
17
- }
18
- }
19
- for (AX_U32 i = 0; io->pOutputs && i < io->nOutputSize; ++i) {
20
- if (io->pOutputs[i].pVirAddr) {
21
- AX_SYS_MemFree(io->pOutputs[i].phyAddr, io->pOutputs[i].pVirAddr);
22
- }
23
- }
24
- delete[] io->pInputs;
25
- delete[] io->pOutputs;
26
- std::memset(io, 0, sizeof(*io));
27
- }
28
- } // namespace
29
-
30
- EngineWrapper::~EngineWrapper() { Release(); }
31
-
32
- int EngineWrapper::Init(const std::string &path) {
33
- std::ifstream input(path, std::ios::binary);
34
- if (!input) {
35
- std::fprintf(stderr, "Failed to read model: %s\n", path.c_str());
36
- return -1;
37
- }
38
- input.seekg(0, std::ios::end);
39
- const std::streamoff model_size = input.tellg();
40
- if (model_size <= 0 || model_size > static_cast<std::streamoff>(UINT32_MAX)) {
41
- std::fprintf(stderr, "Invalid model size: %s\n", path.c_str());
42
- return -1;
43
- }
44
- input.seekg(0, std::ios::beg);
45
- std::vector<char> model(static_cast<std::size_t>(model_size));
46
- input.read(model.data(), model_size);
47
- if (!input) {
48
- std::fprintf(stderr, "Failed to read model: %s\n", path.c_str());
49
- return -1;
50
- }
51
- const AX_S32 create_ret = AX_ENGINE_CreateHandle(
52
- &handle_, model.data(), static_cast<AX_U32>(model.size()));
53
- if (create_ret != 0 || !handle_) {
54
- std::fprintf(stderr, "AX_ENGINE_CreateHandle failed: %s ret=0x%x\n",
55
- path.c_str(), static_cast<unsigned>(create_ret));
56
- return -1;
57
- }
58
- if (AX_ENGINE_CreateContext(handle_) != 0 ||
59
- AX_ENGINE_GetIOInfo(handle_, &info_) != 0 || !info_) {
60
- Release();
61
- return -1;
62
- }
63
-
64
- io_.nInputSize = info_->nInputSize;
65
- io_.nOutputSize = info_->nOutputSize;
66
- io_.pInputs = new AX_ENGINE_IO_BUFFER_T[io_.nInputSize]{};
67
- io_.pOutputs = new AX_ENGINE_IO_BUFFER_T[io_.nOutputSize]{};
68
- AX_S8 input_tag[] = "KWS-INPUT";
69
- AX_S8 output_tag[] = "KWS-OUTPUT";
70
- for (AX_U32 i = 0; i < io_.nInputSize; ++i) {
71
- io_.pInputs[i].nSize = info_->pInputs[i].nSize;
72
- if (AX_SYS_MemAlloc(&io_.pInputs[i].phyAddr,
73
- &io_.pInputs[i].pVirAddr, io_.pInputs[i].nSize,
74
- kAlignment, input_tag) != 0) {
75
- Release();
76
- return -1;
77
- }
78
- const std::string name = info_->pInputs[i].pName;
79
- inputs_[name] = static_cast<int>(i);
80
- input_names_.push_back(name);
81
- }
82
- for (AX_U32 i = 0; i < io_.nOutputSize; ++i) {
83
- io_.pOutputs[i].nSize = info_->pOutputs[i].nSize;
84
- if (AX_SYS_MemAlloc(&io_.pOutputs[i].phyAddr,
85
- &io_.pOutputs[i].pVirAddr, io_.pOutputs[i].nSize,
86
- kAlignment, output_tag) != 0) {
87
- Release();
88
- return -1;
89
- }
90
- const std::string name = info_->pOutputs[i].pName;
91
- outputs_[name] = static_cast<int>(i);
92
- output_names_.push_back(name);
93
- }
94
- initialized_ = true;
95
- std::printf("Loaded %s (inputs=%u outputs=%u)\n", path.c_str(),
96
- io_.nInputSize, io_.nOutputSize);
97
- return 0;
98
- }
99
-
100
- void EngineWrapper::Release() {
101
- FreeIo(&io_);
102
- if (handle_) AX_ENGINE_DestroyHandle(handle_);
103
- initialized_ = false;
104
- handle_ = nullptr;
105
- info_ = nullptr;
106
- inputs_.clear();
107
- outputs_.clear();
108
- input_names_.clear();
109
- output_names_.clear();
110
- }
111
-
112
- int EngineWrapper::InputIndex(const std::string &name) const {
113
- const auto it = inputs_.find(name);
114
- return it == inputs_.end() ? -1 : it->second;
115
- }
116
-
117
- int EngineWrapper::OutputIndex(const std::string &name) const {
118
- const auto it = outputs_.find(name);
119
- return it == outputs_.end() ? -1 : it->second;
120
- }
121
-
122
- int EngineWrapper::SetInputByName(const std::string &name, const void *data,
123
- std::size_t size) {
124
- const int index = InputIndex(name);
125
- if (!initialized_ || index < 0 || !data) return -1;
126
- const std::size_t expected = io_.pInputs[index].nSize;
127
- if (size != 0 && size != expected) return -1;
128
- std::memcpy(io_.pInputs[index].pVirAddr, data, expected);
129
- return 0;
130
- }
131
-
132
- int EngineWrapper::ZeroInputByName(const std::string &name) {
133
- const int index = InputIndex(name);
134
- if (!initialized_ || index < 0) return -1;
135
- std::memset(io_.pInputs[index].pVirAddr, 0, io_.pInputs[index].nSize);
136
- return 0;
137
- }
138
-
139
- int EngineWrapper::RunSync() {
140
- if (!initialized_) return -1;
141
- for (AX_U32 i = 0; i < io_.nInputSize; ++i) {
142
- const AX_S32 flush_ret = AX_SYS_MflushCache(
143
- io_.pInputs[i].phyAddr, io_.pInputs[i].pVirAddr,
144
- io_.pInputs[i].nSize);
145
- if (flush_ret != 0) {
146
- std::fprintf(stderr, "AX_SYS_MflushCache failed input=%u ret=0x%x\n", i,
147
- static_cast<unsigned>(flush_ret));
148
- return flush_ret;
149
- }
150
- }
151
- const AX_S32 ret = AX_ENGINE_RunSync(handle_, &io_);
152
- if (ret != 0) {
153
- std::fprintf(stderr, "AX_ENGINE_RunSync failed ret=0x%x\n",
154
- static_cast<unsigned>(ret));
155
- return ret;
156
- }
157
- for (AX_U32 i = 0; i < io_.nOutputSize; ++i) {
158
- const AX_S32 invalidate_ret = AX_SYS_MinvalidateCache(
159
- io_.pOutputs[i].phyAddr, io_.pOutputs[i].pVirAddr,
160
- io_.pOutputs[i].nSize);
161
- if (invalidate_ret != 0) {
162
- std::fprintf(stderr,
163
- "AX_SYS_MinvalidateCache failed output=%u ret=0x%x\n", i,
164
- static_cast<unsigned>(invalidate_ret));
165
- return invalidate_ret;
166
- }
167
- }
168
- return 0;
169
- }
170
-
171
- int EngineWrapper::GetOutputByName(const std::string &name, void *data,
172
- std::size_t size) const {
173
- const int index = OutputIndex(name);
174
- if (!initialized_ || index < 0 || !data) return -1;
175
- const std::size_t expected = io_.pOutputs[index].nSize;
176
- if (size != 0 && size != expected) return -1;
177
- std::memcpy(data, io_.pOutputs[index].pVirAddr, expected);
178
- return 0;
179
- }
180
-
181
- int EngineWrapper::GetInputSizeByName(const std::string &name) const {
182
- const int index = InputIndex(name);
183
- return index < 0 ? -1 : static_cast<int>(io_.pInputs[index].nSize);
184
- }
185
-
186
- int EngineWrapper::GetOutputSizeByName(const std::string &name) const {
187
- const int index = OutputIndex(name);
188
- return index < 0 ? -1 : static_cast<int>(io_.pOutputs[index].nSize);
189
- }
190
-
191
- const std::string &EngineWrapper::InputName(std::size_t index) const {
192
- return input_names_.at(index);
193
- }
194
-
195
- const std::string &EngineWrapper::OutputName(std::size_t index) const {
196
- return output_names_.at(index);
197
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/engine_wrapper.hpp DELETED
@@ -1,43 +0,0 @@
1
- #pragma once
2
-
3
- #include <cstddef>
4
- #include <string>
5
- #include <unordered_map>
6
- #include <vector>
7
-
8
- #include "ax_engine_api.h"
9
-
10
- class EngineWrapper {
11
- public:
12
- EngineWrapper() = default;
13
- ~EngineWrapper();
14
-
15
- EngineWrapper(const EngineWrapper &) = delete;
16
- EngineWrapper &operator=(const EngineWrapper &) = delete;
17
-
18
- int Init(const std::string &model_path);
19
- void Release();
20
- int SetInputByName(const std::string &name, const void *data,
21
- std::size_t size = 0);
22
- int ZeroInputByName(const std::string &name);
23
- int RunSync();
24
- int GetOutputByName(const std::string &name, void *data,
25
- std::size_t size = 0) const;
26
- int GetInputSizeByName(const std::string &name) const;
27
- int GetOutputSizeByName(const std::string &name) const;
28
- const std::string &InputName(std::size_t index) const;
29
- const std::string &OutputName(std::size_t index) const;
30
-
31
- private:
32
- int InputIndex(const std::string &name) const;
33
- int OutputIndex(const std::string &name) const;
34
-
35
- bool initialized_ = false;
36
- AX_ENGINE_HANDLE handle_ = nullptr;
37
- AX_ENGINE_IO_INFO_T *info_ = nullptr;
38
- AX_ENGINE_IO_T io_{};
39
- std::unordered_map<std::string, int> inputs_;
40
- std::unordered_map<std::string, int> outputs_;
41
- std::vector<std::string> input_names_;
42
- std::vector<std::string> output_names_;
43
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cpp/src/wav_reader.hpp DELETED
@@ -1,80 +0,0 @@
1
- #pragma once
2
-
3
- #include <cstdint>
4
- #include <cstring>
5
- #include <fstream>
6
- #include <stdexcept>
7
- #include <string>
8
- #include <vector>
9
-
10
- struct PcmWav {
11
- int sample_rate = 0;
12
- std::vector<int16_t> samples;
13
- };
14
-
15
- inline uint16_t ReadLe16(std::istream &input) {
16
- uint8_t bytes[2]{};
17
- input.read(reinterpret_cast<char *>(bytes), 2);
18
- return static_cast<uint16_t>(bytes[0]) |
19
- (static_cast<uint16_t>(bytes[1]) << 8);
20
- }
21
-
22
- inline uint32_t ReadLe32(std::istream &input) {
23
- uint8_t bytes[4]{};
24
- input.read(reinterpret_cast<char *>(bytes), 4);
25
- return static_cast<uint32_t>(bytes[0]) |
26
- (static_cast<uint32_t>(bytes[1]) << 8) |
27
- (static_cast<uint32_t>(bytes[2]) << 16) |
28
- (static_cast<uint32_t>(bytes[3]) << 24);
29
- }
30
-
31
- inline PcmWav ReadPcmWav(const std::string &path) {
32
- std::ifstream input(path, std::ios::binary);
33
- if (!input) throw std::runtime_error("Cannot open WAV: " + path);
34
- char riff[4]{};
35
- char wave[4]{};
36
- input.read(riff, 4);
37
- ReadLe32(input);
38
- input.read(wave, 4);
39
- if (std::memcmp(riff, "RIFF", 4) != 0 ||
40
- std::memcmp(wave, "WAVE", 4) != 0) {
41
- throw std::runtime_error("Invalid RIFF/WAVE file: " + path);
42
- }
43
-
44
- uint16_t format = 0;
45
- uint16_t channels = 0;
46
- uint16_t bits = 0;
47
- uint32_t sample_rate = 0;
48
- std::vector<uint8_t> data;
49
- while (input && (!format || data.empty())) {
50
- char id[4]{};
51
- input.read(id, 4);
52
- if (!input) break;
53
- const uint32_t size = ReadLe32(input);
54
- if (std::memcmp(id, "fmt ", 4) == 0) {
55
- if (size < 16) throw std::runtime_error("Invalid WAV fmt chunk");
56
- format = ReadLe16(input);
57
- channels = ReadLe16(input);
58
- sample_rate = ReadLe32(input);
59
- ReadLe32(input);
60
- ReadLe16(input);
61
- bits = ReadLe16(input);
62
- input.seekg(size - 16, std::ios::cur);
63
- } else if (std::memcmp(id, "data", 4) == 0) {
64
- data.resize(size);
65
- input.read(reinterpret_cast<char *>(data.data()), size);
66
- } else {
67
- input.seekg(size, std::ios::cur);
68
- }
69
- if (size & 1U) input.seekg(1, std::ios::cur);
70
- }
71
- if (format != 1 || channels != 1 || bits != 16 || sample_rate == 0 ||
72
- data.empty() || data.size() % sizeof(int16_t) != 0) {
73
- throw std::runtime_error("Expected mono 16-bit PCM WAV: " + path);
74
- }
75
- PcmWav result;
76
- result.sample_rate = static_cast<int>(sample_rate);
77
- result.samples.resize(data.size() / sizeof(int16_t));
78
- std::memcpy(result.samples.data(), data.data(), data.size());
79
- return result;
80
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
scripts/__pycache__/openwakeword_ax.cpython-312.pyc DELETED
Binary file (16.9 kB)
 
scripts/__pycache__/openwakeword_ax650.cpython-312.pyc DELETED
Binary file (16.8 kB)
 
scripts/__pycache__/runtime.cpython-312.pyc DELETED
Binary file (9.76 kB)