Initial public release of JustOneCacophony

This commit is contained in:
2026-09-01 16:31:38 +08:00
commit aa3a519f79
38 changed files with 9073 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
cmake_minimum_required(VERSION 3.20)
project(eac3joc_core VERSION 1.0.0 LANGUAGES CXX)
include(GNUInstallDirs)
find_package(Threads REQUIRED)
add_library(eac3joc_core SHARED
src/eac3joc_core.cpp
src/speaker_renderer.cpp
src/joc_huffman_tables.h
src/qmf_tables.h
src/speaker_layouts.h
)
target_compile_features(eac3joc_core PRIVATE cxx_std_20)
target_include_directories(eac3joc_core PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/include"
)
target_link_libraries(eac3joc_core PRIVATE Threads::Threads)
set_target_properties(eac3joc_core PROPERTIES
OUTPUT_NAME "eac3joc_core"
CXX_VISIBILITY_PRESET hidden
VISIBILITY_INLINES_HIDDEN YES
POSITION_INDEPENDENT_CODE YES
)
if(MSVC)
set_property(TARGET eac3joc_core PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
target_compile_options(eac3joc_core PRIVATE
/W4 /permissive- /Zc:__cplusplus /utf-8 /EHsc /GR- /fp:precise
$<$<CONFIG:Release>:/O2>
$<$<CONFIG:Release>:/Oi>
$<$<CONFIG:Release>:/GL>
)
target_link_options(eac3joc_core PRIVATE
$<$<CONFIG:Release>:/LTCG>
/INCREMENTAL:NO /OPT:REF /OPT:ICF
)
else()
target_compile_options(eac3joc_core PRIVATE
-Wall -Wextra -Wpedantic -fno-fast-math
$<$<CONFIG:Release>:-O3>
)
endif()
# Install directly into the chosen prefix. Recommended invocation from the
# repository root:
# cmake -S native -B build/cmake -DCMAKE_BUILD_TYPE=Release \
# -DCMAKE_INSTALL_PREFIX=<repo>/lib
# cmake --build build/cmake --config Release
# cmake --install build/cmake --config Release
#
# Result names are supplied by the platform toolchain:
# Windows: eac3joc_core.dll (+ eac3joc_core.lib import library)
# Linux: libeac3joc_core.so
# macOS: libeac3joc_core.dylib
install(TARGETS eac3joc_core
RUNTIME DESTINATION .
LIBRARY DESTINATION .
ARCHIVE DESTINATION .
)
if(MSVC)
install(FILES "$<TARGET_PDB_FILE:eac3joc_core>"
DESTINATION .
OPTIONAL
)
endif()
+119
View File
@@ -0,0 +1,119 @@
#pragma once
#include <stdint.h>
#if defined(_WIN32)
#if defined(EJOC_BUILD_DLL)
#define EJOC_API __declspec(dllexport)
#else
#define EJOC_API __declspec(dllimport)
#endif
#define EJOC_CALL __cdecl
#else
#define EJOC_API __attribute__((visibility("default")))
#define EJOC_CALL
#endif
#ifdef __cplusplus
extern "C" {
#endif
enum {
EJOC_ABI_VERSION = 1,
EJOC_FRAME_SAMPLES = 1536,
EJOC_TIMESLOTS = 24,
EJOC_SUBBANDS = 64,
EJOC_CORE_CHANNELS = 5,
EJOC_OUTPUT_CHANNELS = 16,
EJOC_MAX_OBJECTS = 15,
EJOC_MAX_DPOINTS = 2,
EJOC_MAX_PARAMETER_BANDS = 23,
EJOC_SPEAKER_BLOCK_SAMPLES = 32,
EJOC_SPEAKER_COORDINATES = 3
};
typedef void* ejoc_renderer_handle;
typedef void* ejoc_speaker_renderer_handle;
/*
Fixed array layouts used by ejoc_renderer_process():
bed5_planar [5][1536]
lfe [1536] or NULL
n_bands [15]
n_dpoints [15]
slope_idx [15]
offset_ts [15][2]
dq [15][2][5][23]
output16 [16][1536]
Only objects selected by object_mask are read from the descriptor arrays.
Sparse JOC must be rejected by the caller; this ABI accepts already dequantized
dense matrix coefficients.
*/
EJOC_API uint32_t EJOC_CALL ejoc_abi_version(void);
EJOC_API const char* EJOC_CALL ejoc_build_info(void);
EJOC_API ejoc_renderer_handle EJOC_CALL ejoc_renderer_create(void);
EJOC_API void EJOC_CALL ejoc_renderer_destroy(ejoc_renderer_handle handle);
EJOC_API int EJOC_CALL ejoc_renderer_reset(ejoc_renderer_handle handle);
EJOC_API int EJOC_CALL ejoc_renderer_set_threads(ejoc_renderer_handle handle, uint32_t total_threads);
EJOC_API uint32_t EJOC_CALL ejoc_renderer_thread_count(ejoc_renderer_handle handle);
EJOC_API const char* EJOC_CALL ejoc_renderer_last_error(ejoc_renderer_handle handle);
EJOC_API int EJOC_CALL ejoc_renderer_process(
ejoc_renderer_handle handle,
const float* bed5_planar,
const float* lfe,
uint32_t object_mask,
const uint8_t* n_bands,
const uint8_t* n_dpoints,
const uint8_t* slope_idx,
const uint8_t* offset_ts,
const double* dq,
double clipgain,
float phase_new,
float output_scale,
float* output16_planar);
/*
High-precision object-to-speaker renderer.
The renderer consumes interleaved float32 input PCM arranged as:
objects16_interleaved [sample_count][16]
where channel 0 is LFE and channels 1..15 are point objects. All spatial
calculations, gain ramps, and accumulation use double. Output is interleaved:
output_interleaved [sample_count][layout_channel_count]
Each metadata entry is a complete object-state snapshot:
metadata_offsets [metadata_count], relative to this process call
ramp_durations [metadata_count], in samples
positions_q15 [metadata_count][15][3]
region_indices [metadata_count][15] or NULL (all region 0)
height_enabled [metadata_count][15] or NULL (all enabled)
object_gains [metadata_count][15] or NULL (all 1.0)
metadata_offsets must be nondecreasing and <= sample_count. sample_count must
be a multiple of EJOC_SPEAKER_BLOCK_SAMPLES. State and unfinished ramps are
preserved across calls.
*/
EJOC_API uint32_t EJOC_CALL ejoc_speaker_layout_channel_count(uint32_t speaker_bitfield);
EJOC_API ejoc_speaker_renderer_handle EJOC_CALL ejoc_speaker_renderer_create(uint32_t speaker_bitfield);
EJOC_API void EJOC_CALL ejoc_speaker_renderer_destroy(ejoc_speaker_renderer_handle handle);
EJOC_API int EJOC_CALL ejoc_speaker_renderer_reset(ejoc_speaker_renderer_handle handle);
EJOC_API const char* EJOC_CALL ejoc_speaker_renderer_last_error(ejoc_speaker_renderer_handle handle);
EJOC_API int EJOC_CALL ejoc_speaker_renderer_process(
ejoc_speaker_renderer_handle handle,
const float* objects16_interleaved,
uint32_t sample_count,
uint32_t metadata_count,
const uint32_t* metadata_offsets,
const uint32_t* ramp_durations,
const uint16_t* positions_q15,
const uint8_t* region_indices,
const uint8_t* height_enabled,
const double* object_gains,
double* output_interleaved);
#ifdef __cplusplus
}
#endif
+735
View File
@@ -0,0 +1,735 @@
#define EJOC_BUILD_DLL
#include "eac3joc_core.h"
#include "qmf_tables.h"
#include <algorithm>
#include <atomic>
#include <barrier>
#include <cmath>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <memory>
#include <new>
#include <thread>
#include <vector>
namespace ejoc {
struct Complex {
double re;
double im;
};
inline Complex mul(const Complex a, const Complex b) noexcept {
return {a.re * b.re - a.im * b.im, a.re * b.im + a.im * b.re};
}
inline double clamp_unit(double value) noexcept {
return value < -1.0 ? -1.0 : (value > 1.0 ? 1.0 : value);
}
constexpr double kPi = 3.141592653589793238462643383279502884;
constexpr int kLfeDelay = 1217;
constexpr int kMaxBands = EJOC_MAX_PARAMETER_BANDS;
const uint8_t* parameter_band_map(const int bands) noexcept {
using namespace tables;
switch (bands) {
case 1: return kPbMap1;
case 3: return kPbMap3;
case 5: return kPbMap5;
case 7: return kPbMap7;
case 9: return kPbMap9;
case 12: return kPbMap12;
case 15: return kPbMap15;
case 23: return kPbMap23;
default: return nullptr;
}
}
class Renderer final {
public:
Renderer() noexcept {
initialize_tables();
reset();
}
~Renderer() noexcept {
stop_workers();
}
int reset() noexcept {
std::memset(analysis_fifo_, 0, sizeof(analysis_fifo_));
std::memset(analysis_delay_, 0, sizeof(analysis_delay_));
std::memset(surround_delay_, 0, sizeof(surround_delay_));
std::memset(surround_history_, 0, sizeof(surround_history_));
std::memset(lfe_delay_, 0, sizeof(lfe_delay_));
std::memset(matrix_previous_, 0, sizeof(matrix_previous_));
std::memset(synthesis_state_, 0, sizeof(synthesis_state_));
std::memset(x_, 0, sizeof(x_));
std::memset(z_, 0, sizeof(z_));
analysis_phase_ = 0.0625f;
error_[0] = '\0';
return 0;
}
int set_threads(uint32_t total_threads) noexcept {
if (total_threads < 1) {
total_threads = 1;
}
if (total_threads > EJOC_MAX_OBJECTS) {
total_threads = EJOC_MAX_OBJECTS;
}
stop_workers();
job_count_ = 0;
next_job_.store(0, std::memory_order_relaxed);
if (total_threads == 1) {
return 0;
}
try {
stop_.store(false, std::memory_order_relaxed);
pool_ready_.store(false, std::memory_order_relaxed);
work_barrier_ = std::make_unique<std::barrier<>>(static_cast<std::ptrdiff_t>(total_threads));
workers_.reserve(total_threads - 1);
for (uint32_t index = 1; index < total_threads; ++index) {
workers_.emplace_back([this]() noexcept { worker_loop(); });
}
pool_ready_.store(true, std::memory_order_release);
// Startup rendezvous: ensure every worker has entered the two-phase
// barrier loop before set_threads returns, so an immediate destroy
// cannot race a worker that exits before reaching the barrier.
work_barrier_->arrive_and_wait();
work_barrier_->arrive_and_wait();
} catch (...) {
stop_.store(true, std::memory_order_release);
pool_ready_.store(true, std::memory_order_release);
for (std::thread& worker : workers_) {
if (worker.joinable()) {
worker.join();
}
}
workers_.clear();
work_barrier_.reset();
stop_.store(false, std::memory_order_relaxed);
return fail("failed to create native worker threads");
}
return 0;
}
uint32_t thread_count() const noexcept {
return static_cast<uint32_t>(workers_.size() + 1);
}
const char* error() const noexcept {
return error_[0] ? error_ : "";
}
int process(
const float* bed5,
const float* lfe,
const uint32_t object_mask,
const uint8_t* n_bands,
const uint8_t* n_dpoints,
const uint8_t* slope_idx,
const uint8_t* offset_ts,
const double* dq,
const double clipgain,
const float phase_new,
const float output_scale,
float* output16) noexcept {
error_[0] = '\0';
if (!bed5 || !n_bands || !n_dpoints || !slope_idx || !offset_ts || !dq || !output16) {
return fail("null pointer passed to ejoc_renderer_process");
}
if (object_mask & ~((1u << EJOC_MAX_OBJECTS) - 1u)) {
return fail("object_mask contains an object index above 14");
}
if (!std::isfinite(clipgain) || !std::isfinite(phase_new) || !std::isfinite(output_scale)) {
return fail("clipgain, phase_new, and output_scale must be finite");
}
for (int object = 0; object < EJOC_MAX_OBJECTS; ++object) {
if ((object_mask & (1u << object)) == 0) {
continue;
}
if (!parameter_band_map(n_bands[object])) {
return fail("unsupported parameter-band count");
}
if (n_dpoints[object] < 1 || n_dpoints[object] > 2) {
return fail("n_dpoints must be 1 or 2");
}
if (slope_idx[object] > 1) {
return fail("slope_idx must be 0 or 1");
}
}
std::memset(output16, 0, sizeof(float) * EJOC_OUTPUT_CHANNELS * EJOC_FRAME_SAMPLES);
analysis(bed5, phase_new);
render_lfe(lfe, output_scale, output16);
process_objects(object_mask, n_bands, n_dpoints, slope_idx, offset_ts,
dq, clipgain, output_scale, output16);
return 0;
}
private:
void initialize_tables() noexcept {
for (int i = 0; i < 64; ++i) {
int value = i;
int reversed = 0;
for (int bit = 0; bit < 6; ++bit) {
reversed = (reversed << 1) | (value & 1);
value >>= 1;
}
bit_reverse_[i] = static_cast<uint8_t>(reversed);
const double theta = kPi * static_cast<double>(i) / 128.0;
rotation_sin_[i] = 0.5 * std::sin(theta);
rotation_cos_[i] = 0.5 * std::cos(theta);
}
for (int i = 0; i < 32; ++i) {
const double angle = -2.0 * kPi * static_cast<double>(i) / 64.0;
fft_twiddle_[i] = {std::cos(angle), std::sin(angle)};
}
}
int fail(const char* message) noexcept {
std::snprintf(error_, sizeof(error_), "%s", message);
return -1;
}
void fft64(Complex* values) const noexcept {
for (int i = 0; i < 64; ++i) {
const int j = bit_reverse_[i];
if (j > i) {
const Complex temp = values[i];
values[i] = values[j];
values[j] = temp;
}
}
for (int length = 2; length <= 64; length <<= 1) {
const int half = length >> 1;
const int twiddle_step = 64 / length;
for (int base = 0; base < 64; base += length) {
for (int j = 0; j < half; ++j) {
const Complex even = values[base + j];
const Complex odd = mul(values[base + j + half], fft_twiddle_[j * twiddle_step]);
values[base + j] = {even.re + odd.re, even.im + odd.im};
values[base + j + half] = {even.re - odd.re, even.im - odd.im};
}
}
}
}
void analysis_slot(const int channel, const float* ring, const int timeslot) noexcept {
double v36[64];
double v40[64];
Complex frequency[64];
for (int sample = 0; sample < 64; ++sample) {
v36[sample] =
analysis_fifo_[channel][0][sample] * tables::kAnalysisWindow[8 * 64 + sample] +
analysis_fifo_[channel][2][sample] * tables::kAnalysisWindow[6 * 64 + sample] +
analysis_fifo_[channel][4][sample] * tables::kAnalysisWindow[4 * 64 + sample] +
analysis_fifo_[channel][6][sample] * tables::kAnalysisWindow[2 * 64 + sample] +
analysis_fifo_[channel][8][sample] * tables::kAnalysisWindow[0 * 64 + sample];
v40[sample] =
analysis_fifo_[channel][1][sample] * tables::kAnalysisWindow[7 * 64 + sample] +
analysis_fifo_[channel][3][sample] * tables::kAnalysisWindow[5 * 64 + sample] +
analysis_fifo_[channel][5][sample] * tables::kAnalysisWindow[3 * 64 + sample] +
analysis_fifo_[channel][7][sample] * tables::kAnalysisWindow[1 * 64 + sample] +
static_cast<double>(ring[sample]) * tables::kAnalysisWindow[9 * 64 + sample];
}
for (int k = 0; k < 64; ++k) {
const int source = 63 - k;
const double re = v40[source];
const double im = v36[source];
const double a = rotation_sin_[k];
const double b = rotation_cos_[k];
frequency[k] = {im * a - re * b, im * b + re * a};
}
fft64(frequency);
constexpr double scale = 1.0 / 64.0;
for (int k = 0; k < 32; ++k) {
x_[channel][2 * k][timeslot] = {frequency[k].re * scale, -frequency[k].im * scale};
x_[channel][2 * k + 1][timeslot] = {
frequency[63 - k].re * scale,
frequency[63 - k].im * scale};
}
for (int history = 8; history > 0; --history) {
std::memcpy(analysis_fifo_[channel][history], analysis_fifo_[channel][history - 1],
sizeof(analysis_fifo_[channel][history]));
}
for (int sample = 0; sample < 64; ++sample) {
analysis_fifo_[channel][0][sample] = static_cast<double>(ring[sample]);
}
}
void surround_post() noexcept {
static constexpr double kDcA[21] = {
-.0006242550443857908, -.0019234686624258757, -.0042654648423194885,
-.008168308064341545, -.014327201060950756, -.023759860545396805,
-.03757232800126076, -.05577569454908371, -.07568276673555374,
-.09172472357749939, -.5979374051094055, -.09172472357749939,
-.07568276673555374, -.05577569454908371, -.03757232800126076,
-.023759860545396805, -.014327201060950756, -.008168308064341545,
-.0042654648423194885, -.0019234686624258757, -.0006242550443857908,
};
static constexpr double kDcB[21] = {
.0013996040215715766, .003839150769636035, .007512642536312342,
.012419373728334904, .018367428332567215, .0249701626598835,
.03167900815606117, .03785000368952751, .04283412545919418,
.04607561603188515, .047200120985507965, .04607561603188515,
.04283412545919418, .03785000368952751, .03167900815606117,
.0249701626598835, .018367428332567215, .012419373728334904,
.007512642536312342, .003839150769636035, .0013996040215715766,
};
for (int surround = 0; surround < 2; ++surround) {
const int channel = surround + 3;
for (int group = 0; group < 24; group += 4) {
Complex current[4][64];
Complex dc_buffer[24];
for (int slot = 0; slot < 4; ++slot) {
for (int band = 0; band < 64; ++band) {
current[slot][band] = x_[channel][band][group + slot];
const Complex delayed = surround_delay_[surround][slot][band];
x_[channel][band][group + slot] = {delayed.im, -delayed.re};
}
}
for (int i = 0; i < 20; ++i) {
dc_buffer[i] = surround_history_[surround][i];
}
for (int i = 0; i < 4; ++i) {
dc_buffer[20 + i] = current[i][0];
}
for (int slot = 0; slot < 4; ++slot) {
Complex sum{0.0, 0.0};
for (int tap = 0; tap < 21; ++tap) {
const Complex sample = dc_buffer[slot + tap];
const double cr = kDcB[tap];
const double ci = kDcA[tap];
sum.re += sample.re * cr - sample.im * ci;
sum.im += sample.re * ci + sample.im * cr;
}
x_[channel][0][group + slot] = {2.0 * sum.re, 2.0 * sum.im};
}
for (int i = 0; i < 20; ++i) {
surround_history_[surround][i] = dc_buffer[i + 4];
}
std::memmove(&surround_delay_[surround][0][0],
&surround_delay_[surround][4][0],
sizeof(Complex) * 6 * 64);
for (int slot = 0; slot < 4; ++slot) {
std::memcpy(surround_delay_[surround][6 + slot], current[slot],
sizeof(Complex) * 64);
}
}
}
}
void analysis_channel(const int channel) noexcept {
const float* bed5 = job_bed5_;
const float phase_old = job_phase_old_;
const float phase_new = job_phase_new_;
const bool ramp_phase = phase_old != phase_new;
const float phase_step = static_cast<float>((phase_new - phase_old) / 256.0f);
float scaled[64];
float delayed[64];
for (int timeslot = 0; timeslot < 24; ++timeslot) {
for (int sample = 0; sample < 64; ++sample) {
const int frame_sample = timeslot * 64 + sample;
float gain = phase_new;
if (ramp_phase && frame_sample < 256) {
const float product = static_cast<float>(static_cast<float>(frame_sample) * phase_step);
gain = static_cast<float>(phase_old + product);
}
scaled[sample] = static_cast<float>(bed5[channel * 1536 + frame_sample] * gain);
}
const float* analysis_input = scaled;
if (channel < 3) {
std::memcpy(delayed, analysis_delay_[channel][0], sizeof(delayed));
std::memmove(&analysis_delay_[channel][0][0],
&analysis_delay_[channel][1][0],
sizeof(float) * 9 * 64);
std::memcpy(analysis_delay_[channel][9], scaled, sizeof(scaled));
analysis_input = delayed;
}
analysis_slot(channel, analysis_input, timeslot);
}
}
void analysis(const float* bed5, const float phase_new) noexcept {
job_bed5_ = bed5;
job_phase_old_ = analysis_phase_;
job_phase_new_ = phase_new;
job_kind_ = JobKind::Analysis;
job_count_ = 5;
for (int channel = 0; channel < 5; ++channel) {
job_objects_[channel] = channel;
}
dispatch_jobs();
analysis_phase_ = phase_new;
surround_post();
}
static std::size_t dq_index(const int object, const int point, const int channel, const int band) noexcept {
return static_cast<std::size_t>((((object * 2 + point) * 5 + channel) * kMaxBands) + band);
}
void matrix_object(
const int object,
const uint8_t* n_bands,
const uint8_t* n_dpoints,
const uint8_t* slope_idx,
const uint8_t* offset_ts,
const double* dq) noexcept {
std::memset(z_[object], 0, sizeof(z_[object]));
const int bands = n_bands[object];
const int points = n_dpoints[object];
const int slope = slope_idx[object];
const uint8_t* pb_map = parameter_band_map(bands);
for (int channel = 0; channel < 5; ++channel) {
for (int subband = 0; subband < 64; ++subband) {
const int parameter_band = pb_map[subband];
const double previous = matrix_previous_[object][channel][subband];
const double target0 = dq[dq_index(object, 0, channel, parameter_band)];
const double target1 = points == 2
? dq[dq_index(object, 1, channel, parameter_band)]
: target0;
double last = previous;
for (int timeslot = 0; timeslot < 24; ++timeslot) {
double coefficient;
if (slope == 0) {
if (points == 1) {
const double alpha = static_cast<double>(timeslot + 1) / 24.0;
coefficient = previous * (1.0 - alpha) + target0 * alpha;
} else if (timeslot < 12) {
const double alpha = static_cast<double>(timeslot + 1) / 12.0;
coefficient = previous * (1.0 - alpha) + target0 * alpha;
} else {
const double alpha = static_cast<double>(timeslot - 11) / 12.0;
coefficient = target0 * (1.0 - alpha) + target1 * alpha;
}
} else if (points == 1) {
coefficient = timeslot < offset_ts[object * 2] ? previous : target0;
} else {
coefficient = timeslot < offset_ts[object * 2] ? previous : target0;
if (timeslot >= offset_ts[object * 2 + 1]) {
coefficient = target1;
}
}
z_[object][subband][timeslot].re += x_[channel][subband][timeslot].re * coefficient;
z_[object][subband][timeslot].im += x_[channel][subband][timeslot].im * coefficient;
last = coefficient;
}
matrix_previous_[object][channel][subband] = last;
}
}
}
void qmf5_step(double* state, const double* rotated, double* output) noexcept {
for (int block = 0; block < 16; ++block) {
for (int lane = 0; lane < 4; ++lane) {
const int sample = block * 4 + lane;
const int state_base = block * 36 + lane;
const double even = rotated[block * 8 + lane * 2];
const double odd = rotated[block * 8 + lane * 2 + 1];
output[sample] = 2.0 * (
tables::kQmf5Window[sample] * even + state[state_base]);
state[state_base] = tables::kQmf5Window[1 * 64 + sample] * odd + state[state_base + 4];
for (int slot = 0; slot < 7; ++slot) {
const double alternating = (slot & 1) == 0 ? even : odd;
state[state_base + (slot + 1) * 4] =
tables::kQmf5Window[(slot + 2) * 64 + sample] * alternating +
state[state_base + (slot + 2) * 4];
}
state[state_base + 8 * 4] = tables::kQmf5Window[9 * 64 + sample] * odd;
}
}
}
void synthesis_object(
const int object,
const double clipgain,
const float output_scale,
float* output16) noexcept {
Complex frequency[64];
double rotated[128];
double pcm64[64];
double* state = synthesis_state_[object];
float* destination = output16 + (object + 1) * 1536;
for (int timeslot = 0; timeslot < 24; ++timeslot) {
for (int k = 0; k < 32; ++k) {
const Complex even = z_[object][2 * k][timeslot];
const Complex odd = z_[object][2 * k + 1][timeslot];
frequency[k] = {even.re, -even.im};
frequency[63 - k] = {odd.re, odd.im};
}
fft64(frequency);
for (int k = 0; k < 64; ++k) {
const double re = frequency[k].re;
const double im = frequency[k].im;
const double sin_component = rotation_sin_[k];
const double cos_component = rotation_cos_[k];
rotated[2 * k] = 2.0 * (re * cos_component + im * sin_component);
rotated[2 * k + 1] = 2.0 * (im * cos_component - re * sin_component);
}
qmf5_step(state, rotated, pcm64);
for (int sample = 0; sample < 64; ++sample) {
const double clipped = clamp_unit(16.0 * pcm64[sample]);
const float value = static_cast<float>(clipped * clipgain);
destination[timeslot * 64 + sample] = static_cast<float>(value * output_scale);
}
}
}
void process_one_object(const int object) noexcept {
matrix_object(object, job_n_bands_, job_n_dpoints_, job_slope_idx_,
job_offset_ts_, job_dq_);
synthesis_object(object, job_clipgain_, job_output_scale_, job_output16_);
}
void execute_job_loop() noexcept {
while (true) {
const int index = next_job_.fetch_add(1, std::memory_order_relaxed);
if (index >= job_count_) {
break;
}
const int item = job_objects_[index];
if (job_kind_ == JobKind::Analysis) {
analysis_channel(item);
} else {
process_one_object(item);
}
}
}
void dispatch_jobs() noexcept {
if (workers_.empty() || job_count_ == 1) {
next_job_.store(0, std::memory_order_relaxed);
execute_job_loop();
return;
}
next_job_.store(0, std::memory_order_relaxed);
work_barrier_->arrive_and_wait();
execute_job_loop();
work_barrier_->arrive_and_wait();
}
void worker_loop() noexcept {
while (!pool_ready_.load(std::memory_order_acquire)) {
std::this_thread::yield();
}
if (stop_.load(std::memory_order_acquire)) {
return;
}
while (true) {
work_barrier_->arrive_and_wait();
if (stop_.load(std::memory_order_acquire)) {
return;
}
execute_job_loop();
work_barrier_->arrive_and_wait();
}
}
void stop_workers() noexcept {
if (workers_.empty()) {
work_barrier_.reset();
stop_.store(false, std::memory_order_relaxed);
pool_ready_.store(false, std::memory_order_relaxed);
return;
}
stop_.store(true, std::memory_order_release);
work_barrier_->arrive_and_wait();
for (std::thread& worker : workers_) {
if (worker.joinable()) {
worker.join();
}
}
workers_.clear();
work_barrier_.reset();
stop_.store(false, std::memory_order_relaxed);
pool_ready_.store(false, std::memory_order_relaxed);
}
void process_objects(
const uint32_t object_mask,
const uint8_t* n_bands,
const uint8_t* n_dpoints,
const uint8_t* slope_idx,
const uint8_t* offset_ts,
const double* dq,
const double clipgain,
const float output_scale,
float* output16) noexcept {
int count = 0;
for (int object = 0; object < EJOC_MAX_OBJECTS; ++object) {
if (object_mask & (1u << object)) {
job_objects_[count++] = object;
}
}
if (count == 0) {
return;
}
job_kind_ = JobKind::Objects;
job_count_ = count;
job_n_bands_ = n_bands;
job_n_dpoints_ = n_dpoints;
job_slope_idx_ = slope_idx;
job_offset_ts_ = offset_ts;
job_dq_ = dq;
job_clipgain_ = clipgain;
job_output_scale_ = output_scale;
job_output16_ = output16;
dispatch_jobs();
}
void render_lfe(const float* lfe, const float output_scale, float* output16) noexcept {
if (!lfe) {
return;
}
for (int sample = 0; sample < kLfeDelay; ++sample) {
const float value = static_cast<float>(clamp_unit(lfe_delay_[sample]));
output16[sample] = static_cast<float>(value * output_scale);
}
for (int sample = kLfeDelay; sample < 1536; ++sample) {
const float value = static_cast<float>(clamp_unit(static_cast<double>(lfe[sample - kLfeDelay])));
output16[sample] = static_cast<float>(value * output_scale);
}
for (int sample = 0; sample < kLfeDelay; ++sample) {
lfe_delay_[sample] = static_cast<double>(lfe[sample + (1536 - kLfeDelay)]);
}
}
enum class JobKind : uint8_t { Analysis, Objects };
std::vector<std::thread> workers_;
std::unique_ptr<std::barrier<>> work_barrier_;
std::atomic<bool> stop_{false};
std::atomic<bool> pool_ready_{false};
std::atomic<int> next_job_{0};
int job_objects_[EJOC_MAX_OBJECTS]{};
int job_count_ = 0;
JobKind job_kind_ = JobKind::Objects;
const float* job_bed5_ = nullptr;
float job_phase_old_ = 0.0625f;
float job_phase_new_ = 0.0625f;
const uint8_t* job_n_bands_ = nullptr;
const uint8_t* job_n_dpoints_ = nullptr;
const uint8_t* job_slope_idx_ = nullptr;
const uint8_t* job_offset_ts_ = nullptr;
const double* job_dq_ = nullptr;
double job_clipgain_ = 1.0;
float job_output_scale_ = 1.0f;
float* job_output16_ = nullptr;
alignas(64) double analysis_fifo_[5][9][64];
alignas(64) float analysis_delay_[3][10][64];
float analysis_phase_;
alignas(64) Complex surround_delay_[2][10][64];
alignas(64) Complex surround_history_[2][20];
alignas(64) double lfe_delay_[kLfeDelay];
alignas(64) double matrix_previous_[15][5][64];
alignas(64) double synthesis_state_[15][640];
alignas(64) Complex x_[5][64][24];
alignas(64) Complex z_[15][64][24];
uint8_t bit_reverse_[64];
Complex fft_twiddle_[32];
double rotation_sin_[64];
double rotation_cos_[64];
char error_[256];
};
} // namespace ejoc
extern "C" {
uint32_t EJOC_CALL ejoc_abi_version(void) {
return EJOC_ABI_VERSION;
}
const char* EJOC_CALL ejoc_build_info(void) {
#if defined(_MSC_VER)
return "eac3joc-core abi=1 compiler=MSVC fft=fixed64 speaker=double crt=static-by-build";
#elif defined(__clang__)
return "eac3joc-core abi=1 compiler=Clang fft=fixed64 speaker=double";
#elif defined(__GNUC__)
return "eac3joc-core abi=1 compiler=GCC fft=fixed64 speaker=double";
#else
return "eac3joc-core abi=1 compiler=unknown fft=fixed64 speaker=double";
#endif
}
ejoc_renderer_handle EJOC_CALL ejoc_renderer_create(void) {
return new (std::nothrow) ejoc::Renderer();
}
void EJOC_CALL ejoc_renderer_destroy(ejoc_renderer_handle handle) {
delete static_cast<ejoc::Renderer*>(handle);
}
int EJOC_CALL ejoc_renderer_reset(ejoc_renderer_handle handle) {
if (!handle) {
return -1;
}
return static_cast<ejoc::Renderer*>(handle)->reset();
}
int EJOC_CALL ejoc_renderer_set_threads(ejoc_renderer_handle handle, uint32_t total_threads) {
if (!handle) {
return -1;
}
return static_cast<ejoc::Renderer*>(handle)->set_threads(total_threads);
}
uint32_t EJOC_CALL ejoc_renderer_thread_count(ejoc_renderer_handle handle) {
if (!handle) {
return 0;
}
return static_cast<ejoc::Renderer*>(handle)->thread_count();
}
const char* EJOC_CALL ejoc_renderer_last_error(ejoc_renderer_handle handle) {
if (!handle) {
return "null renderer handle";
}
return static_cast<ejoc::Renderer*>(handle)->error();
}
int EJOC_CALL ejoc_renderer_process(
ejoc_renderer_handle handle,
const float* bed5_planar,
const float* lfe,
const uint32_t object_mask,
const uint8_t* n_bands,
const uint8_t* n_dpoints,
const uint8_t* slope_idx,
const uint8_t* offset_ts,
const double* dq,
const double clipgain,
const float phase_new,
const float output_scale,
float* output16_planar) {
if (!handle) {
return -1;
}
return static_cast<ejoc::Renderer*>(handle)->process(
bed5_planar, lfe, object_mask, n_bands, n_dpoints, slope_idx,
offset_ts, dq, clipgain, phase_new, output_scale, output16_planar);
}
} // extern "C"
+89
View File
@@ -0,0 +1,89 @@
#pragma once
// JOC Huffman trees required by the bitstream parser.
static const int joc_huff_code_coarse_generic[][2] =
{
{ -1, 1}, { 2, -2}, { -96, 3}, { 4, -3}, { -95, 5}, { 6, 7}, { -4, -94}, { 8, 9}, { -5, -93}, { 10, 11},
{ -6, -92}, { 12, 13}, { -7, -91}, { 14, 15}, { 16, -90}, { -8, 17}, { 18, -89}, { -9, 19}, { 20, 21}, { -88, -10},
{ 22, 23}, { -11, -87}, { 24, 25}, { 26, -86}, { -12, 27}, { 28, -85}, { -13, 29}, { 30, 31}, { 32, -84}, { -14, 33},
{ 34, -15}, { -83, 35}, { 36, 37}, { -16, 38}, { -17, -82}, { 39, 40}, { 41, -81}, { 42, 43}, { 44, 45}, { 46, 47},
{ 48, 49}, { 50, 51}, { 52, -18}, { -78, 53}, { -19, 54}, { 55, 56}, { 57, 58}, { -22, 59}, { 60, 61}, { 62, 63},
{ 64, 65}, { 66, 67}, { 68, -20}, { -21, -79}, { -80, -25}, { 69, 70}, { -26, 71}, { 72, 73}, { 74, 75}, { 76, 77},
{ 78, 79}, { 80, 81}, { 82, 83}, { 84, 85}, { 86, 87}, { 88, 89}, { 90, 91}, { 92, 93}, { 94, -23}, { -74, -75},
{ -72, -73}, { -76, -77}, { -34, -35}, { -32, -33}, { -38, -39}, { -36, -37}, { -30, -31}, { -28, -29}, { -50, -51}, { -48, -49},
{ -54, -55}, { -52, -53}, { -42, -43}, { -40, -41}, { -46, -47}, { -44, -45}, { -66, -67}, { -64, -65}, { -70, -71}, { -68, -69},
{ -58, -59}, { -56, -57}, { -62, -63}, { -60, -61}, { -24, -27}
};
static const int joc_huff_code_fine_generic[][2] =
{
{ -1, 1}, { 2, 3}, { -2,-192}, { 4, 5}, { 6, -3}, {-191, 7}, { 8, 9}, { -4,-190}, { 10, 11}, { -5,-189},
{ 12, 13}, { -6, 14}, {-188, 15}, { 16, -7}, {-187, 17}, { 18, -8}, {-186, 19}, { 20, -9}, {-185, 21}, { 22, -10},
{-184, 23}, { 24, -11}, { 25,-183}, { 26, 27}, { -12,-182}, { 28, 29}, { -13,-181}, { 30, 31}, {-180, -14}, { 32, 33},
{ 34,-179}, { -15, 35}, { 36,-178}, { -16, 37}, { 38,-177}, { 39, -17}, { 40, 41}, {-176, 42}, { -18, 43}, { -19, 44},
{-175, 45}, { 46,-174}, { -20, 47}, {-173, 48}, { 49, -21}, { 50, 51}, { 52, -22}, { 53, 54}, {-172, 55}, {-171, -23},
{ 56, 57}, { 58,-170}, { 59, -24}, { -25, 60}, {-169, 61}, { 62, 63}, { 64, 65}, { 66, 67}, {-168, 68}, { -26, 69},
{-167, -27}, { 70,-166}, {-165, 71}, { -29, 72}, { 73, 74}, { -30, 75}, { 76, 77}, { 78, 79}, { 80, -28}, { 81, 82},
{ 83,-163}, { -31, -33}, {-164,-161}, { 84, 85}, { 86, 87}, { 88, 89}, { 90, 91}, { 92, 93}, { 94, 95}, { 96, 97},
{ 98, 99}, { -32,-162}, { 100, 101}, { 102, 103}, { 104, 105}, { 106, 107}, { 108, 109}, { 110, 111}, {-160, 112}, { -36, -38},
{ 113, 114}, { 115, 116}, { 117, 118}, { 119, 120}, { 121, 122}, { 123, 124}, { 125, 126}, { 127, 128}, { 129, 130}, { 131, 132},
{ 133, -35}, {-158, 134}, {-155,-156}, { -37, -42}, { 135, 136}, { 137, 138}, { 139, 140}, { 141, 142}, { 143, 144}, { 145, 146},
{ 147, 148}, { 149, 150}, { 151, 152}, { 153, 154}, { 155, 156}, { 157, 158}, { 159, 160}, { 161, 162}, { 163, 164}, { 165, 166},
{ 167, 168}, { 169, 170}, { 171, 172}, { 173, 174}, { 175, 176}, { 177, 178}, { 179, 180}, { 181, 182}, { 183, 184}, {-157, 185},
{ -45, -48}, { 186, 187}, { 188, 189}, { -34, -41}, { 190, -39}, { -60, -61}, { -58, -59}, { -64, -65}, { -62, -63}, { -52, -53},
{ -50, -51}, { -56, -57}, { -54, -55}, { -76, -77}, { -74, -75}, { -80, -81}, { -78, -79}, { -68, -69}, { -66, -67}, { -72, -73},
{ -70, -71}, { -47, -49}, { -44, -46}, {-124,-125}, {-122,-123}, {-128,-129}, {-126,-127}, {-116,-117}, {-114,-115}, {-120,-121},
{-118,-119}, {-140,-141}, {-138,-139}, {-144,-145}, {-142,-143}, {-132,-133}, {-130,-131}, {-136,-137}, {-134,-135}, { -92, -93},
{ -90, -91}, { -96, -97}, { -94, -95}, { -84, -85}, { -82, -83}, { -88, -89}, { -86, -87}, {-108,-109}, {-106,-107}, {-112,-113},
{-110,-111}, {-100,-101}, { -98, -99}, {-104,-105}, {-102,-103}, {-154,-159}, {-148,-149}, {-146,-147}, {-152,-153}, {-150,-151},
{ -40, -43}
};
static const int joc_huff_code_coarse_coeff_sparse[][2] =
{
{ -1, 1}, { 2, 3}, { -2, -96}, { 4, 5}, { 6, -95}, { -3, 7}, { 8, 9}, { -4, 10}, { -94, 11}, { 12, -5},
{ -93, 13}, { 14, 15}, { -6, -92}, { 16, 17}, { 18, -7}, { -91, 19}, { 20, -8}, { -90, 21}, { 22, 23}, { -9, -89},
{ 24, 25}, { 26, -10}, { -88, 27}, { 28, 29}, { 30, -11}, { -87, 31}, { 32, 33}, { 34, 35}, { -12, -86}, { 36, 37},
{ 38, -13}, { 39, -85}, { 40, 41}, { 42, 43}, { -14, -84}, { 44, 45}, { 46, 47}, { -83, -15}, { 48, 49}, { 50, -16},
{ 51, 52}, { -82, 53}, { 54, -81}, { 55, 56}, { -17, 57}, { 58, -80}, { 59, 60}, { -18, 61}, { 62, 63}, { -79, 64},
{ -19, -78}, { 65, 66}, { 67, 68}, { 69, -20}, { -77, -21}, { 70, 71}, { 72, 73}, { 74, -76}, { 75, -22}, { 76, 77},
{ -75, 78}, { 79, 80}, { -54, -74}, { -73, 81}, { -23, 82}, { -50, -24}, { -55, -25}, { 83, -47}, { -49, -44}, { -71, 84},
{ -48, -51}, { 85, -72}, { -26, -53}, { -70, -27}, { 86, -45}, { 87, 88}, { -68, 89}, { -29, -43}, { 90, -30}, { -46, -69},
{ 91, -28}, { -52, -31}, { 92, -32}, { 93, -64}, { -67, 94}, { -36, -33}, { -63, -37}, { -65, -61}, { -66, -59}, { -34, -38},
{ -41, -42}, { -35, -60}, { -39, -57}, { -56, -40}, { -62, -58}
};
static const int joc_huff_code_fine_coeff_sparse[][2] =
{
{ 1, -1}, { 2, 3}, { 4, -2}, {-192, 5}, { 6, 7}, { 8, -3}, {-191, 9}, { 10, 11}, { 12,-190}, { -4, 13},
{ 14, 15}, {-189, -5}, { 16, 17}, { 18, -6}, {-188, 19}, { 20, 21}, { -7,-187}, { 22, 23}, { -8, 24}, {-186, 25},
{ -9, 26}, { 27,-185}, { 28, -10}, { 29, 30}, {-184, 31}, { -11, 32}, { 33,-183}, { 34, -12}, { 35,-182}, { 36, 37},
{ 38, -13}, {-181, 39}, { 40, -14}, { 41,-180}, { 42, 43}, {-179, -15}, { 44, -16}, { 45,-178}, { 46, 47}, { 48, 49},
{ 50,-177}, { -17, 51}, { -18, 52}, {-176, 53}, { 54, 55}, {-175, -19}, { 56, 57}, { 58, -20}, { 59,-174}, { 60, 61},
{ -21, 62}, { 63,-173}, { 64, 65}, { 66,-172}, { 67, 68}, { -22, 69}, { 70, 71}, { -23, 72}, {-171, 73}, { 74, 75},
{ 76, -24}, { 77,-170}, { -25, 78}, { 79, 80}, { 81,-169}, { 82, 83}, { 84, -26}, { 85,-168}, { 86, 87}, { 88, 89},
{-167, 90}, { -27, 91}, { 92, -28}, { 93,-166}, { 94, -29}, { 95, 96}, { 97, 98}, {-165, 99}, { 100, -30}, {-164, 101},
{ 102, 103}, { 104, 105}, {-163, 106}, { -31, 107}, { -32, 108}, { 109, 110}, {-161, 111}, {-160,-162}, { 112, -34}, { -33, 113},
{ 114, 115}, { 116, 117}, { 118, 119}, { 120,-159}, { 121, 122}, { 123,-158}, { 124, 125}, { -36,-155}, { 126, 127}, { -35, 128},
{ 129, 130}, {-157, 131}, {-156, 132}, { -37, 133}, { 134, 135}, {-154, -38}, { 136, 137}, { -39, -41}, { 138,-153}, { 139, -40},
{-149, 140}, { 141, 142}, { 143, 144}, {-151, 145}, { 146, 147}, { 148, -42}, { -43, 149}, { 150, 151}, {-152, 152}, { -46, -98},
{ 153, 154}, { 155,-147}, { 156, 157}, { 158,-107}, { 159, 160}, {-145,-150}, { -96, 161}, { 162, -45}, {-146, 163}, { 164, -97},
{-108,-105}, {-148,-106}, { -44, 165}, { -94,-141}, { -99, 166}, { -89, 167}, { -50, -95}, {-100, -48}, {-144, 168}, { 169, 170},
{ -51,-142}, { -90, -91}, { -47, -49}, { 171, -53}, { -93,-143}, {-137,-138}, { -55,-101}, { 172, 173}, { -54, -86}, { -88, -87},
{-103, 174}, { 175, -61}, {-109, 176}, { 177, 178}, { -52,-139}, { -57,-140}, { 179, 180}, { -56,-136}, { -58,-102}, { 181, 182},
{ -60,-135}, { 183,-104}, {-128,-134}, { -92, 184}, { -59, -62}, { 185, 186}, { -71,-133}, { 187,-127}, {-126, 188}, { -63, -64},
{ -85,-132}, { 189, -66}, {-121,-125}, { 190, -68}, { -74, -75}, { -70, -73}, { -81, -65}, {-118,-131}, { -72,-110}, {-119,-120},
{ -76, -84}, {-122,-130}, { -83,-117}, { -69, -78}, { -80, -82}, {-123,-124}, { -67,-116}, {-129, -77}, {-113,-114}, {-112,-115},
{ -79,-111}
};
static const int joc_huff_code_5ch_pos_index_sparse[][2] =
{
{ -1, 1}, { 2, 3}, { -4, -3}, { -2, -5}
};
static const int joc_huff_code_7ch_pos_index_sparse[][2] =
{
{ -1, 1}, { 2, 3}, { 4, 5}, { -4, -3}, { -2, -5}, { -6, -7}
};
+388
View File
@@ -0,0 +1,388 @@
#pragma once
#include <stdint.h>
// Generated table data; do not hand-edit.
namespace ejoc::tables {
inline constexpr double kAnalysisWindow[640] = {
0.00019903187057934701, 0.00024947625934146345, 0.00030217695166356862, 0.00035484600812196732,
0.0004058915947098285, 0.00045464080176316202, 0.00050126801943406463, 0.00054649583762511611,
0.00059120741207152605, 0.0006361178238876164, 0.00068160606315359473, 0.00072772568091750145,
0.00077434181002900004, 0.00082129903603345156, 0.00086853635730221868, 0.00091610715026035905,
0.00096411682898178697, 0.0010126305278390646, 0.0010616052895784378, 0.0011108826147392392,
0.0011602368904277682, 0.0012094489065930247, 0.0012583627831190825, 0.0013069023843854666,
0.0013550462899729609, 0.0014027846045792103, 0.0014500867109745741, 0.0014968989416956902,
0.0015431707724928856, 0.0015888890484347939, 0.0016340982401743531, 0.0016788924112915993,
0.0017233812250196934, 0.0017676511779427528, 0.0018117419676855206, 0.0018556505674496293,
0.0018993609119206667, 0.0019428766099736094, 0.0019862416666001081, 0.0020295341964811087,
0.0020728406962007284, 0.0021162291523069143, 0.0021597379818558693, 0.0022033930290490389,
0.0022472396958619356, 0.0022913739085197449, 0.0023359460756182671, 0.0023811329156160355,
0.0024270866997539997, 0.0024738919455558062, 0.0025215502828359604, 0.0025700139813125134,
0.0026192441582679749, 0.0026692659594118595, 0.002720177173614502, 0.0027720888610929251,
0.0028250094037503004, 0.0028787164483219385, 0.0029326770454645157, 0.0029860674403607845,
0.0030379060190171003, 0.0030872693751007318, 0.0031335193198174238, 0.0031764607410877943,
0.0032163741998374462, 0.0032539025414735079, 0.0032898378558456898, 0.0033248732797801495,
0.003359407652169466, 0.0033934540115296841, 0.0034266682341694832, 0.0034584659151732922,
0.0034881711471825838, 0.0035151413176208735, 0.0035388274118304253, 0.0035587677266448736,
0.0035745392087846994, 0.0035856980830430984, 0.0035917432978749275, 0.0035921167582273483,
0.0035862282384186983, 0.0035734928678721189, 0.0035533567424863577, 0.0035253004170954227,
0.0034888240043073893, 0.003443423192948103, 0.0033885682933032513, 0.0033236993476748466,
0.0032482317183166742, 0.0031615688931196928, 0.0030631136614829302, 0.0029522709082812071,
0.0028284420259296894, 0.0026910160668194294, 0.0025393660180270672, 0.0023728485684841871,
0.0021908141206949949, 0.0019926181994378567, 0.0017776311142370105, 0.0015452421503141522,
0.001294855959713459, 0.0010258855763822794, 0.00073774566408246756, 0.00042984966421499848,
0.00010161137470277026, -0.00024754938203841448, -0.00061819725669920444, -0.0010108760325238109,
-0.001426108181476593, -0.0018643926596269011, -0.0023262077011168003, -0.002812013728544116,
-0.0033222525380551815, -0.003857344388961792, -0.0044176783412694931, -0.0050036045722663403,
-0.0056154225021600723, -0.0062533821910619736, -0.0069176913239061832, -0.0076085370965301991,
-0.008326113224029541, -0.0090706516057252884, -0.0098424339666962624, -0.010641784407198429,
-0.011469035409390926, -0.012324465438723564, -0.013208229094743729, -0.014120301231741905,
0.015060451813042164, 0.016028247773647308, 0.017023105174303055, 0.018044359982013702,
0.019091326743364334, 0.020163353532552719, 0.021259821951389313, 0.022380130365490913,
0.02352365106344223, 0.024689681828022003, 0.025877414271235466, 0.027085918933153152,
0.028314167633652687, 0.029561035335063934, 0.030825328081846237, 0.032105788588523865,
0.033401083201169968, 0.034709792584180832, 0.036030396819114685, 0.037361271679401398,
0.03870067372918129, 0.040046781301498413, 0.041397668421268463, 0.042751342058181763,
0.044105727225542068, 0.045458663254976273, 0.046807888895273209, 0.048151064664125443,
0.049485750496387482, 0.050809424370527267, 0.05211947113275528, 0.053413204848766327,
0.054687850177288055, 0.055940557271242142, 0.057168368250131607, 0.058368254452943802,
0.059537097811698914, 0.06067170575261116, 0.061768818646669388, 0.062825113534927368,
0.063837200403213501, 0.064801648259162903, 0.065714947879314423, 0.066573545336723328,
0.067373812198638916, 0.068112112581729889, 0.068784743547439575, 0.069387979805469513,
0.069918066263198853, 0.070371203124523163, 0.070743560791015625, 0.071031264960765839,
0.071230456233024597, 0.071337237954139709, 0.071347743272781372, 0.071258097887039185,
0.07106444239616394, 0.070762887597084045, 0.070349536836147308, 0.069820456206798553,
0.069171726703643799, 0.068399444222450256, 0.067499779164791107, 0.066468983888626099,
0.065303429961204529, 0.063999593257904053, 0.062554046511650085, 0.060963429510593414,
0.059224434196949005, 0.057333782315254211, 0.055288247764110565, 0.05308464914560318,
0.050719890743494034, 0.04819098487496376, 0.045495055615901947, 0.042629346251487732,
0.039591230452060699, 0.036378197371959686, 0.032987859100103378, 0.029417969286441803,
0.025666400790214539, 0.0217311792075634, 0.017610486596822739, 0.013302664272487164,
0.0088062174618244171, 0.0041198157705366611, -0.00075770384864881635, -0.0058273370377719402,
-0.011089906096458435, -0.016546055674552917, -0.022196246311068535, -0.028040755540132523,
-0.034079667180776596, -0.040312871336936951, -0.046740073710680008, -0.053360763937234879,
-0.06017424538731575, -0.0671796053647995, -0.074375726282596588, -0.081761270761489868,
-0.089334696531295776, -0.097094230353832245, -0.10503791272640228, -0.1131635457277298,
-0.12146873027086258, -0.12995083630084991, -0.13860704004764557, -0.1474342942237854,
-0.15642932057380676, -0.1655886322259903, -0.17490856349468231, -0.18438516557216644,
-0.19401434063911438, -0.20379173755645752, -0.21371282637119293, -0.22377283871173859,
-0.23396681249141693, -0.24428960680961609, -0.25473582744598389, -0.26529994606971741,
-0.27597621083259583, -0.2867586612701416, -0.29764124751091003, -0.30861768126487732,
-0.31968152523040771, -0.33082622289657593, -0.34204500913619995, -0.35333094000816345,
0.36467701196670532, 0.37607598304748535, 0.38752046227455139, 0.39900293946266174,
0.41051584482192993, 0.42205137014389038, 0.4336017370223999, 0.44515895843505859,
0.45671501755714417, 0.46826183795928955, 0.47979119420051575, 0.49129492044448853,
0.50276464223861694, 0.51419198513031006, 0.52556860446929932, 0.53688603639602661,
0.54813587665557861, 0.55930960178375244, 0.57039880752563477, 0.58139497041702271,
0.59228962659835815, 0.60307443141937256, 0.61374092102050781, 0.62428075075149536,
0.63468557596206665, 0.64494723081588745, 0.65505754947662354, 0.66500836610794067,
0.67479169368743896, 0.68439966440200806, 0.69382447004318237, 0.70305842161178589,
0.71209394931793213, 0.72092366218566895, 0.72954028844833374, 0.73793661594390869,
0.74610573053359985, 0.75404083728790283, 0.76173526048660278, 0.76918256282806396,
0.77637648582458496, 0.78331100940704346, 0.78998017311096191, 0.79637837409973145,
0.80250018835067749, 0.80834043025970459, 0.81389403343200684, 0.81915634870529175,
0.82412278652191162, 0.82878917455673218, 0.83315145969390869, 0.83720588684082031,
0.84094899892807007, 0.84437751770019531, 0.84748858213424683, 0.85027939081192017,
0.85274755954742432, 0.85489106178283691, 0.85670793056488037, 0.8581966757774353,
0.85935592651367188, 0.86018466949462891, 0.86068224906921387, 0.86084812879562378,
0.86068224906921387, 0.86018466949462891, 0.85935592651367188, 0.8581966757774353,
0.85670793056488037, 0.85489106178283691, 0.85274755954742432, 0.85027939081192017,
0.84748858213424683, 0.84437751770019531, 0.84094899892807007, 0.83720588684082031,
0.83315145969390869, 0.82878917455673218, 0.82412278652191162, 0.81915634870529175,
0.81389403343200684, 0.80834043025970459, 0.80250018835067749, 0.79637837409973145,
0.78998017311096191, 0.78331100940704346, 0.77637648582458496, 0.76918256282806396,
0.76173526048660278, 0.75404083728790283, 0.74610573053359985, 0.73793661594390869,
0.72954028844833374, 0.72092366218566895, 0.71209394931793213, 0.70305842161178589,
0.69382447004318237, 0.68439966440200806, 0.67479169368743896, 0.66500836610794067,
0.65505754947662354, 0.64494723081588745, 0.63468557596206665, 0.62428075075149536,
0.61374092102050781, 0.60307443141937256, 0.59228962659835815, 0.58139497041702271,
0.57039880752563477, 0.55930960178375244, 0.54813587665557861, 0.53688603639602661,
0.52556860446929932, 0.51419198513031006, 0.50276464223861694, 0.49129492044448853,
0.47979119420051575, 0.46826183795928955, 0.45671501755714417, 0.44515895843505859,
0.4336017370223999, 0.42205137014389038, 0.41051584482192993, 0.39900293946266174,
0.38752046227455139, 0.37607598304748535, 0.36467701196670532, 0.35333094000816345,
-0.34204500913619995, -0.33082622289657593, -0.31968152523040771, -0.30861768126487732,
-0.29764124751091003, -0.2867586612701416, -0.27597621083259583, -0.26529994606971741,
-0.25473582744598389, -0.24428960680961609, -0.23396681249141693, -0.22377283871173859,
-0.21371282637119293, -0.20379173755645752, -0.19401434063911438, -0.18438516557216644,
-0.17490856349468231, -0.1655886322259903, -0.15642932057380676, -0.1474342942237854,
-0.13860704004764557, -0.12995083630084991, -0.12146873027086258, -0.1131635457277298,
-0.10503791272640228, -0.097094230353832245, -0.089334696531295776, -0.081761270761489868,
-0.074375726282596588, -0.0671796053647995, -0.06017424538731575, -0.053360763937234879,
-0.046740073710680008, -0.040312871336936951, -0.034079667180776596, -0.028040755540132523,
-0.022196246311068535, -0.016546055674552917, -0.011089906096458435, -0.0058273370377719402,
-0.00075770384864881635, 0.0041198157705366611, 0.0088062174618244171, 0.013302664272487164,
0.017610486596822739, 0.0217311792075634, 0.025666400790214539, 0.029417969286441803,
0.032987859100103378, 0.036378197371959686, 0.039591230452060699, 0.042629346251487732,
0.045495055615901947, 0.04819098487496376, 0.050719890743494034, 0.05308464914560318,
0.055288247764110565, 0.057333782315254211, 0.059224434196949005, 0.060963429510593414,
0.062554046511650085, 0.063999593257904053, 0.065303429961204529, 0.066468983888626099,
0.067499779164791107, 0.068399444222450256, 0.069171726703643799, 0.069820456206798553,
0.070349536836147308, 0.070762887597084045, 0.07106444239616394, 0.071258097887039185,
0.071347743272781372, 0.071337237954139709, 0.071230456233024597, 0.071031264960765839,
0.070743560791015625, 0.070371203124523163, 0.069918066263198853, 0.069387979805469513,
0.068784743547439575, 0.068112112581729889, 0.067373812198638916, 0.066573545336723328,
0.065714947879314423, 0.064801648259162903, 0.063837200403213501, 0.062825113534927368,
0.061768818646669388, 0.06067170575261116, 0.059537097811698914, 0.058368254452943802,
0.057168368250131607, 0.055940557271242142, 0.054687850177288055, 0.053413204848766327,
0.05211947113275528, 0.050809424370527267, 0.049485750496387482, 0.048151064664125443,
0.046807888895273209, 0.045458663254976273, 0.044105727225542068, 0.042751342058181763,
0.041397668421268463, 0.040046781301498413, 0.03870067372918129, 0.037361271679401398,
0.036030396819114685, 0.034709792584180832, 0.033401083201169968, 0.032105788588523865,
0.030825328081846237, 0.029561035335063934, 0.028314167633652687, 0.027085918933153152,
0.025877414271235466, 0.024689681828022003, 0.02352365106344223, 0.022380130365490913,
0.021259821951389313, 0.020163353532552719, 0.019091326743364334, 0.018044359982013702,
0.017023105174303055, 0.016028247773647308, 0.015060451813042164, 0.014120301231741905,
-0.013208229094743729, -0.012324465438723564, -0.011469035409390926, -0.010641784407198429,
-0.0098424339666962624, -0.0090706516057252884, -0.008326113224029541, -0.0076085370965301991,
-0.0069176913239061832, -0.0062533821910619736, -0.0056154225021600723, -0.0050036045722663403,
-0.0044176783412694931, -0.003857344388961792, -0.0033222525380551815, -0.002812013728544116,
-0.0023262077011168003, -0.0018643926596269011, -0.001426108181476593, -0.0010108760325238109,
-0.00061819725669920444, -0.00024754938203841448, 0.00010161137470277026, 0.00042984966421499848,
0.00073774566408246756, 0.0010258855763822794, 0.001294855959713459, 0.0015452421503141522,
0.0017776311142370105, 0.0019926181994378567, 0.0021908141206949949, 0.0023728485684841871,
0.0025393660180270672, 0.0026910160668194294, 0.0028284420259296894, 0.0029522709082812071,
0.0030631136614829302, 0.0031615688931196928, 0.0032482317183166742, 0.0033236993476748466,
0.0033885682933032513, 0.003443423192948103, 0.0034888240043073893, 0.0035253004170954227,
0.0035533567424863577, 0.0035734928678721189, 0.0035862282384186983, 0.0035921167582273483,
0.0035917432978749275, 0.0035856980830430984, 0.0035745392087846994, 0.0035587677266448736,
0.0035388274118304253, 0.0035151413176208735, 0.0034881711471825838, 0.0034584659151732922,
0.0034266682341694832, 0.0033934540115296841, 0.003359407652169466, 0.0033248732797801495,
0.0032898378558456898, 0.0032539025414735079, 0.0032163741998374462, 0.0031764607410877943,
0.0031335193198174238, 0.0030872693751007318, 0.0030379060190171003, 0.0029860674403607845,
0.0029326770454645157, 0.0028787164483219385, 0.0028250094037503004, 0.0027720888610929251,
0.002720177173614502, 0.0026692659594118595, 0.0026192441582679749, 0.0025700139813125134,
0.0025215502828359604, 0.0024738919455558062, 0.0024270866997539997, 0.0023811329156160355,
0.0023359460756182671, 0.0022913739085197449, 0.0022472396958619356, 0.0022033930290490389,
0.0021597379818558693, 0.0021162291523069143, 0.0020728406962007284, 0.0020295341964811087,
0.0019862416666001081, 0.0019428766099736094, 0.0018993609119206667, 0.0018556505674496293,
0.0018117419676855206, 0.0017676511779427528, 0.0017233812250196934, 0.0016788924112915993,
0.0016340982401743531, 0.0015888890484347939, 0.0015431707724928856, 0.0014968989416956902,
0.0014500867109745741, 0.0014027846045792103, 0.0013550462899729609, 0.0013069023843854666,
0.0012583627831190825, 0.0012094489065930247, 0.0011602368904277682, 0.0011108826147392392,
0.0010616052895784378, 0.0010126305278390646, 0.00096411682898178697, 0.00091610715026035905,
0.00086853635730221868, 0.00082129903603345156, 0.00077434181002900004, 0.00072772568091750145,
0.00068160606315359473, 0.0006361178238876164, 0.00059120741207152605, 0.00054649583762511611,
0.00050126801943406463, 0.00045464080176316202, 0.0004058915947098285, 0.00035484600812196732,
0.00030217695166356862, 0.00024947625934146345, 0.00019903187057934701, 0,
};
inline constexpr double kQmf5Window[640] = {
0, 0.00019903187057934701, 0.00024947625934146345, 0.00030217695166356862,
0.00035484600812196732, 0.0004058915947098285, 0.00045464080176316202, 0.00050126801943406463,
0.00054649583762511611, 0.00059120741207152605, 0.0006361178238876164, 0.00068160606315359473,
0.00072772568091750145, 0.00077434181002900004, 0.00082129903603345156, 0.00086853635730221868,
0.00091610715026035905, 0.00096411682898178697, 0.0010126305278390646, 0.0010616052895784378,
0.0011108826147392392, 0.0011602368904277682, 0.0012094489065930247, 0.0012583627831190825,
0.0013069023843854666, 0.0013550462899729609, 0.0014027846045792103, 0.0014500867109745741,
0.0014968989416956902, 0.0015431707724928856, 0.0015888890484347939, 0.0016340982401743531,
0.0016788924112915993, 0.0017233812250196934, 0.0017676511779427528, 0.0018117419676855206,
0.0018556505674496293, 0.0018993609119206667, 0.0019428766099736094, 0.0019862416666001081,
0.0020295341964811087, 0.0020728406962007284, 0.0021162291523069143, 0.0021597379818558693,
0.0022033930290490389, 0.0022472396958619356, 0.0022913739085197449, 0.0023359460756182671,
0.0023811329156160355, 0.0024270866997539997, 0.0024738919455558062, 0.0025215502828359604,
0.0025700139813125134, 0.0026192441582679749, 0.0026692659594118595, 0.002720177173614502,
0.0027720888610929251, 0.0028250094037503004, 0.0028787164483219385, 0.0029326770454645157,
0.0029860674403607845, 0.0030379060190171003, 0.0030872693751007318, 0.0031335193198174238,
0.0031764607410877943, 0.0032163741998374462, 0.0032539025414735079, 0.0032898378558456898,
0.0033248732797801495, 0.003359407652169466, 0.0033934540115296841, 0.0034266682341694832,
0.0034584659151732922, 0.0034881711471825838, 0.0035151413176208735, 0.0035388274118304253,
0.0035587677266448736, 0.0035745392087846994, 0.0035856980830430984, 0.0035917432978749275,
0.0035921167582273483, 0.0035862282384186983, 0.0035734928678721189, 0.0035533567424863577,
0.0035253004170954227, 0.0034888240043073893, 0.003443423192948103, 0.0033885682933032513,
0.0033236993476748466, 0.0032482317183166742, 0.0031615688931196928, 0.0030631136614829302,
0.0029522709082812071, 0.0028284420259296894, 0.0026910160668194294, 0.0025393660180270672,
0.0023728485684841871, 0.0021908141206949949, 0.0019926181994378567, 0.0017776311142370105,
0.0015452421503141522, 0.001294855959713459, 0.0010258855763822794, 0.00073774566408246756,
0.00042984966421499848, 0.00010161137470277026, -0.00024754938203841448, -0.00061819725669920444,
-0.0010108760325238109, -0.001426108181476593, -0.0018643926596269011, -0.0023262077011168003,
-0.002812013728544116, -0.0033222525380551815, -0.003857344388961792, -0.0044176783412694931,
-0.0050036045722663403, -0.0056154225021600723, -0.0062533821910619736, -0.0069176913239061832,
-0.0076085370965301991, -0.008326113224029541, -0.0090706516057252884, -0.0098424339666962624,
-0.010641784407198429, -0.011469035409390926, -0.012324465438723564, -0.013208229094743729,
0.014120301231741905, 0.015060451813042164, 0.016028247773647308, 0.017023105174303055,
0.018044359982013702, 0.019091326743364334, 0.020163353532552719, 0.021259821951389313,
0.022380130365490913, 0.02352365106344223, 0.024689681828022003, 0.025877414271235466,
0.027085918933153152, 0.028314167633652687, 0.029561035335063934, 0.030825328081846237,
0.032105788588523865, 0.033401083201169968, 0.034709792584180832, 0.036030396819114685,
0.037361271679401398, 0.03870067372918129, 0.040046781301498413, 0.041397668421268463,
0.042751342058181763, 0.044105727225542068, 0.045458663254976273, 0.046807888895273209,
0.048151064664125443, 0.049485750496387482, 0.050809424370527267, 0.05211947113275528,
0.053413204848766327, 0.054687850177288055, 0.055940557271242142, 0.057168368250131607,
0.058368254452943802, 0.059537097811698914, 0.06067170575261116, 0.061768818646669388,
0.062825113534927368, 0.063837200403213501, 0.064801648259162903, 0.065714947879314423,
0.066573545336723328, 0.067373812198638916, 0.068112112581729889, 0.068784743547439575,
0.069387979805469513, 0.069918066263198853, 0.070371203124523163, 0.070743560791015625,
0.071031264960765839, 0.071230456233024597, 0.071337237954139709, 0.071347743272781372,
0.071258097887039185, 0.07106444239616394, 0.070762887597084045, 0.070349536836147308,
0.069820456206798553, 0.069171726703643799, 0.068399444222450256, 0.067499779164791107,
0.066468983888626099, 0.065303429961204529, 0.063999593257904053, 0.062554046511650085,
0.060963429510593414, 0.059224434196949005, 0.057333782315254211, 0.055288247764110565,
0.05308464914560318, 0.050719890743494034, 0.04819098487496376, 0.045495055615901947,
0.042629346251487732, 0.039591230452060699, 0.036378197371959686, 0.032987859100103378,
0.029417969286441803, 0.025666400790214539, 0.0217311792075634, 0.017610486596822739,
0.013302664272487164, 0.0088062174618244171, 0.0041198157705366611, -0.00075770384864881635,
-0.0058273370377719402, -0.011089906096458435, -0.016546055674552917, -0.022196246311068535,
-0.028040755540132523, -0.034079667180776596, -0.040312871336936951, -0.046740073710680008,
-0.053360763937234879, -0.06017424538731575, -0.0671796053647995, -0.074375726282596588,
-0.081761270761489868, -0.089334696531295776, -0.097094230353832245, -0.10503791272640228,
-0.1131635457277298, -0.12146873027086258, -0.12995083630084991, -0.13860704004764557,
-0.1474342942237854, -0.15642932057380676, -0.1655886322259903, -0.17490856349468231,
-0.18438516557216644, -0.19401434063911438, -0.20379173755645752, -0.21371282637119293,
-0.22377283871173859, -0.23396681249141693, -0.24428960680961609, -0.25473582744598389,
-0.26529994606971741, -0.27597621083259583, -0.2867586612701416, -0.29764124751091003,
-0.30861768126487732, -0.31968152523040771, -0.33082622289657593, -0.34204500913619995,
0.35333094000816345, 0.36467701196670532, 0.37607598304748535, 0.38752046227455139,
0.39900293946266174, 0.41051584482192993, 0.42205137014389038, 0.4336017370223999,
0.44515895843505859, 0.45671501755714417, 0.46826183795928955, 0.47979119420051575,
0.49129492044448853, 0.50276464223861694, 0.51419198513031006, 0.52556860446929932,
0.53688603639602661, 0.54813587665557861, 0.55930960178375244, 0.57039880752563477,
0.58139497041702271, 0.59228962659835815, 0.60307443141937256, 0.61374092102050781,
0.62428075075149536, 0.63468557596206665, 0.64494723081588745, 0.65505754947662354,
0.66500836610794067, 0.67479169368743896, 0.68439966440200806, 0.69382447004318237,
0.70305842161178589, 0.71209394931793213, 0.72092366218566895, 0.72954028844833374,
0.73793661594390869, 0.74610573053359985, 0.75404083728790283, 0.76173526048660278,
0.76918256282806396, 0.77637648582458496, 0.78331100940704346, 0.78998017311096191,
0.79637837409973145, 0.80250018835067749, 0.80834043025970459, 0.81389403343200684,
0.81915634870529175, 0.82412278652191162, 0.82878917455673218, 0.83315145969390869,
0.83720588684082031, 0.84094899892807007, 0.84437751770019531, 0.84748858213424683,
0.85027939081192017, 0.85274755954742432, 0.85489106178283691, 0.85670793056488037,
0.8581966757774353, 0.85935592651367188, 0.86018466949462891, 0.86068224906921387,
0.86084812879562378, 0.86068224906921387, 0.86018466949462891, 0.85935592651367188,
0.8581966757774353, 0.85670793056488037, 0.85489106178283691, 0.85274755954742432,
0.85027939081192017, 0.84748858213424683, 0.84437751770019531, 0.84094899892807007,
0.83720588684082031, 0.83315145969390869, 0.82878917455673218, 0.82412278652191162,
0.81915634870529175, 0.81389403343200684, 0.80834043025970459, 0.80250018835067749,
0.79637837409973145, 0.78998017311096191, 0.78331100940704346, 0.77637648582458496,
0.76918256282806396, 0.76173526048660278, 0.75404083728790283, 0.74610573053359985,
0.73793661594390869, 0.72954028844833374, 0.72092366218566895, 0.71209394931793213,
0.70305842161178589, 0.69382447004318237, 0.68439966440200806, 0.67479169368743896,
0.66500836610794067, 0.65505754947662354, 0.64494723081588745, 0.63468557596206665,
0.62428075075149536, 0.61374092102050781, 0.60307443141937256, 0.59228962659835815,
0.58139497041702271, 0.57039880752563477, 0.55930960178375244, 0.54813587665557861,
0.53688603639602661, 0.52556860446929932, 0.51419198513031006, 0.50276464223861694,
0.49129492044448853, 0.47979119420051575, 0.46826183795928955, 0.45671501755714417,
0.44515895843505859, 0.4336017370223999, 0.42205137014389038, 0.41051584482192993,
0.39900293946266174, 0.38752046227455139, 0.37607598304748535, 0.36467701196670532,
-0.35333094000816345, -0.34204500913619995, -0.33082622289657593, -0.31968152523040771,
-0.30861768126487732, -0.29764124751091003, -0.2867586612701416, -0.27597621083259583,
-0.26529994606971741, -0.25473582744598389, -0.24428960680961609, -0.23396681249141693,
-0.22377283871173859, -0.21371282637119293, -0.20379173755645752, -0.19401434063911438,
-0.18438516557216644, -0.17490856349468231, -0.1655886322259903, -0.15642932057380676,
-0.1474342942237854, -0.13860704004764557, -0.12995083630084991, -0.12146873027086258,
-0.1131635457277298, -0.10503791272640228, -0.097094230353832245, -0.089334696531295776,
-0.081761270761489868, -0.074375726282596588, -0.0671796053647995, -0.06017424538731575,
-0.053360763937234879, -0.046740073710680008, -0.040312871336936951, -0.034079667180776596,
-0.028040755540132523, -0.022196246311068535, -0.016546055674552917, -0.011089906096458435,
-0.0058273370377719402, -0.00075770384864881635, 0.0041198157705366611, 0.0088062174618244171,
0.013302664272487164, 0.017610486596822739, 0.0217311792075634, 0.025666400790214539,
0.029417969286441803, 0.032987859100103378, 0.036378197371959686, 0.039591230452060699,
0.042629346251487732, 0.045495055615901947, 0.04819098487496376, 0.050719890743494034,
0.05308464914560318, 0.055288247764110565, 0.057333782315254211, 0.059224434196949005,
0.060963429510593414, 0.062554046511650085, 0.063999593257904053, 0.065303429961204529,
0.066468983888626099, 0.067499779164791107, 0.068399444222450256, 0.069171726703643799,
0.069820456206798553, 0.070349536836147308, 0.070762887597084045, 0.07106444239616394,
0.071258097887039185, 0.071347743272781372, 0.071337237954139709, 0.071230456233024597,
0.071031264960765839, 0.070743560791015625, 0.070371203124523163, 0.069918066263198853,
0.069387979805469513, 0.068784743547439575, 0.068112112581729889, 0.067373812198638916,
0.066573545336723328, 0.065714947879314423, 0.064801648259162903, 0.063837200403213501,
0.062825113534927368, 0.061768818646669388, 0.06067170575261116, 0.059537097811698914,
0.058368254452943802, 0.057168368250131607, 0.055940557271242142, 0.054687850177288055,
0.053413204848766327, 0.05211947113275528, 0.050809424370527267, 0.049485750496387482,
0.048151064664125443, 0.046807888895273209, 0.045458663254976273, 0.044105727225542068,
0.042751342058181763, 0.041397668421268463, 0.040046781301498413, 0.03870067372918129,
0.037361271679401398, 0.036030396819114685, 0.034709792584180832, 0.033401083201169968,
0.032105788588523865, 0.030825328081846237, 0.029561035335063934, 0.028314167633652687,
0.027085918933153152, 0.025877414271235466, 0.024689681828022003, 0.02352365106344223,
0.022380130365490913, 0.021259821951389313, 0.020163353532552719, 0.019091326743364334,
0.018044359982013702, 0.017023105174303055, 0.016028247773647308, 0.015060451813042164,
-0.014120301231741905, -0.013208229094743729, -0.012324465438723564, -0.011469035409390926,
-0.010641784407198429, -0.0098424339666962624, -0.0090706516057252884, -0.008326113224029541,
-0.0076085370965301991, -0.0069176913239061832, -0.0062533821910619736, -0.0056154225021600723,
-0.0050036045722663403, -0.0044176783412694931, -0.003857344388961792, -0.0033222525380551815,
-0.002812013728544116, -0.0023262077011168003, -0.0018643926596269011, -0.001426108181476593,
-0.0010108760325238109, -0.00061819725669920444, -0.00024754938203841448, 0.00010161137470277026,
0.00042984966421499848, 0.00073774566408246756, 0.0010258855763822794, 0.001294855959713459,
0.0015452421503141522, 0.0017776311142370105, 0.0019926181994378567, 0.0021908141206949949,
0.0023728485684841871, 0.0025393660180270672, 0.0026910160668194294, 0.0028284420259296894,
0.0029522709082812071, 0.0030631136614829302, 0.0031615688931196928, 0.0032482317183166742,
0.0033236993476748466, 0.0033885682933032513, 0.003443423192948103, 0.0034888240043073893,
0.0035253004170954227, 0.0035533567424863577, 0.0035734928678721189, 0.0035862282384186983,
0.0035921167582273483, 0.0035917432978749275, 0.0035856980830430984, 0.0035745392087846994,
0.0035587677266448736, 0.0035388274118304253, 0.0035151413176208735, 0.0034881711471825838,
0.0034584659151732922, 0.0034266682341694832, 0.0033934540115296841, 0.003359407652169466,
0.0033248732797801495, 0.0032898378558456898, 0.0032539025414735079, 0.0032163741998374462,
0.0031764607410877943, 0.0031335193198174238, 0.0030872693751007318, 0.0030379060190171003,
0.0029860674403607845, 0.0029326770454645157, 0.0028787164483219385, 0.0028250094037503004,
0.0027720888610929251, 0.002720177173614502, 0.0026692659594118595, 0.0026192441582679749,
0.0025700139813125134, 0.0025215502828359604, 0.0024738919455558062, 0.0024270866997539997,
0.0023811329156160355, 0.0023359460756182671, 0.0022913739085197449, 0.0022472396958619356,
0.0022033930290490389, 0.0021597379818558693, 0.0021162291523069143, 0.0020728406962007284,
0.0020295341964811087, 0.0019862416666001081, 0.0019428766099736094, 0.0018993609119206667,
0.0018556505674496293, 0.0018117419676855206, 0.0017676511779427528, 0.0017233812250196934,
0.0016788924112915993, 0.0016340982401743531, 0.0015888890484347939, 0.0015431707724928856,
0.0014968989416956902, 0.0014500867109745741, 0.0014027846045792103, 0.0013550462899729609,
0.0013069023843854666, 0.0012583627831190825, 0.0012094489065930247, 0.0011602368904277682,
0.0011108826147392392, 0.0010616052895784378, 0.0010126305278390646, 0.00096411682898178697,
0.00091610715026035905, 0.00086853635730221868, 0.00082129903603345156, 0.00077434181002900004,
0.00072772568091750145, 0.00068160606315359473, 0.0006361178238876164, 0.00059120741207152605,
0.00054649583762511611, 0.00050126801943406463, 0.00045464080176316202, 0.0004058915947098285,
0.00035484600812196732, 0.00030217695166356862, 0.00024947625934146345, 0.00019903187057934701,
};
inline constexpr uint8_t kPbMap1[64] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
inline constexpr uint8_t kPbMap3[64] = {
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
};
inline constexpr uint8_t kPbMap5[64] = {
0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
};
inline constexpr uint8_t kPbMap7[64] = {
0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5,
5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
};
inline constexpr uint8_t kPbMap9[64] = {
0, 1, 2, 3, 3, 3, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
};
inline constexpr uint8_t kPbMap12[64] = {
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 7, 8, 8,
8, 8, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10,
10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
};
inline constexpr uint8_t kPbMap15[64] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10, 10, 11, 11, 11,
12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
};
inline constexpr uint8_t kPbMap23[64] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 12, 13, 13,
14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 18, 18, 19, 19,
19, 19, 19, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21,
22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
};
} // namespace ejoc::tables
+534
View File
@@ -0,0 +1,534 @@
#pragma once
#include <array>
#include <cstddef>
#include <cstdint>
namespace ejoc::speaker_tables {
inline constexpr std::size_t kMaxPoints = 15;
inline constexpr std::size_t kMaxGroups = 4;
inline constexpr std::size_t kMaxGroupSize = 3;
inline constexpr std::size_t kMaxChannels = 16;
struct SpeakerPoint {
std::array<std::uint16_t, 3> coordinate_q15{};
std::uint8_t speaker_id{};
};
struct AxisGroup {
std::uint8_t size{};
std::array<std::uint8_t, kMaxGroupSize> indices{};
};
struct RegionGeometry {
std::uint8_t point_count{};
std::uint8_t mode{};
std::uint8_t axis0_group_count{};
std::uint8_t axis1_group_count{};
std::array<SpeakerPoint, kMaxPoints> points{};
std::array<AxisGroup, kMaxGroups> axis0_groups{};
std::array<AxisGroup, kMaxGroups> axis1_groups{};
};
struct LayoutGeometry {
std::uint32_t speaker_bitfield{};
std::uint8_t out_ch_config{};
std::uint8_t channel_count{};
std::array<std::uint8_t, kMaxChannels> standard_from_internal{};
std::array<RegionGeometry, 7> regions{};
};
inline constexpr std::array<LayoutGeometry, 10> kLayouts{{
LayoutGeometry{
0x1u, 0, 2,
{{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
{{
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0x7u, 3, 4,
{{0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
{{
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
1, 1, 1, 0,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0xFu, 7, 6,
{{0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
{{
RegionGeometry{
5, 2, 2, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 2, 2, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 2, 2, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 2, 2, 0,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
2, 1, 1, 0,
{{SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0x1Fu, 11, 8,
{{0, 1, 2, 3, 6, 7, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0}},
{{
RegionGeometry{
7, 2, 3, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 2, 2, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 2, 2, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 2, 2, 0,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
4, 2, 2, 0,
{{SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{2, {2, 3, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0x40Fu, 13, 8,
{{0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0}},
{{
RegionGeometry{
7, 3, 2, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 16384, 32767}, 6}, SpeakerPoint{{24840, 16384, 32767}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 16384, 32767}, 6}, SpeakerPoint{{24840, 16384, 32767}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 16384, 32767}, 6}, SpeakerPoint{{24840, 16384, 32767}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 3, 2, 1,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 16384, 32767}, 6}, SpeakerPoint{{24840, 16384, 32767}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 3, 1, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 16384, 32767}, 6}, SpeakerPoint{{24840, 16384, 32767}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
4, 3, 1, 1,
{{SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 16384, 32767}, 6}, SpeakerPoint{{24840, 16384, 32767}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {2, 3, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0xA0Fu, 14, 10,
{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0}},
{{
RegionGeometry{
9, 3, 2, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 7928, 32767}, 6}, SpeakerPoint{{24840, 7928, 32767}, 7}, SpeakerPoint{{7928, 24840, 32767}, 8}, SpeakerPoint{{24840, 24840, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
9, 3, 2, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 7928, 32767}, 6}, SpeakerPoint{{24840, 7928, 32767}, 7}, SpeakerPoint{{7928, 24840, 32767}, 8}, SpeakerPoint{{24840, 24840, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
9, 3, 2, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 7928, 32767}, 6}, SpeakerPoint{{24840, 7928, 32767}, 7}, SpeakerPoint{{7928, 24840, 32767}, 8}, SpeakerPoint{{24840, 24840, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 2,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 7928, 32767}, 6}, SpeakerPoint{{24840, 7928, 32767}, 7}, SpeakerPoint{{7928, 24840, 32767}, 8}, SpeakerPoint{{24840, 24840, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 1, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 7928, 32767}, 6}, SpeakerPoint{{24840, 7928, 32767}, 7}, SpeakerPoint{{7928, 24840, 32767}, 8}, SpeakerPoint{{24840, 24840, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
6, 3, 1, 2,
{{SpeakerPoint{{0, 32767, 0}, 4}, SpeakerPoint{{32767, 32767, 0}, 5}, SpeakerPoint{{7928, 7928, 32767}, 6}, SpeakerPoint{{24840, 7928, 32767}, 7}, SpeakerPoint{{7928, 24840, 32767}, 8}, SpeakerPoint{{24840, 24840, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {2, 3, 0}}, AxisGroup{2, {4, 5, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 3, 1, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 7928, 32767}, 6}, SpeakerPoint{{24840, 7928, 32767}, 7}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0x41Fu, 15, 10,
{{0, 1, 2, 3, 6, 7, 4, 5, 8, 9, 0, 0, 0, 0, 0, 0}},
{{
RegionGeometry{
9, 3, 3, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 16384, 32767}, 8}, SpeakerPoint{{24840, 16384, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}}},
{{AxisGroup{2, {7, 8, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{7928, 16384, 32767}, 8}, SpeakerPoint{{24840, 16384, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 16384, 32767}, 8}, SpeakerPoint{{24840, 16384, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 3, 2, 1,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 16384, 32767}, 8}, SpeakerPoint{{24840, 16384, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 3, 1, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 16384, 32767}, 8}, SpeakerPoint{{24840, 16384, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
6, 3, 2, 1,
{{SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 16384, 32767}, 8}, SpeakerPoint{{24840, 16384, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{2, {2, 3, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {4, 5, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
3, 1, 1, 0,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0xA1Fu, 16, 12,
{{0, 1, 2, 3, 6, 7, 4, 5, 8, 9, 10, 11, 0, 0, 0, 0}},
{{
RegionGeometry{
11, 3, 3, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 8}, SpeakerPoint{{24840, 7928, 32767}, 9}, SpeakerPoint{{7928, 24840, 32767}, 10}, SpeakerPoint{{24840, 24840, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}}},
{{AxisGroup{2, {7, 8, 0}}, AxisGroup{2, {9, 10, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
9, 3, 2, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{7928, 7928, 32767}, 8}, SpeakerPoint{{24840, 7928, 32767}, 9}, SpeakerPoint{{7928, 24840, 32767}, 10}, SpeakerPoint{{24840, 24840, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
9, 3, 2, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 8}, SpeakerPoint{{24840, 7928, 32767}, 9}, SpeakerPoint{{7928, 24840, 32767}, 10}, SpeakerPoint{{24840, 24840, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 2,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 8}, SpeakerPoint{{24840, 7928, 32767}, 9}, SpeakerPoint{{7928, 24840, 32767}, 10}, SpeakerPoint{{24840, 24840, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 1, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 7928, 32767}, 8}, SpeakerPoint{{24840, 7928, 32767}, 9}, SpeakerPoint{{7928, 24840, 32767}, 10}, SpeakerPoint{{24840, 24840, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
8, 3, 2, 2,
{{SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 8}, SpeakerPoint{{24840, 7928, 32767}, 9}, SpeakerPoint{{7928, 24840, 32767}, 10}, SpeakerPoint{{24840, 24840, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{2, {2, 3, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {4, 5, 0}}, AxisGroup{2, {6, 7, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
5, 3, 1, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 7928, 32767}, 8}, SpeakerPoint{{24840, 7928, 32767}, 9}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0xA9Fu, 19, 14,
{{0, 1, 2, 3, 6, 7, 4, 5, 10, 11, 12, 13, 8, 9, 0, 0}},
{{
RegionGeometry{
13, 3, 4, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{0, 5285, 0}, 8}, SpeakerPoint{{32767, 5285, 0}, 9}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 24840, 32767}, 12}, SpeakerPoint{{24840, 24840, 32767}, 13}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}}},
{{AxisGroup{2, {9, 10, 0}}, AxisGroup{2, {11, 12, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
11, 3, 3, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 5285, 0}, 8}, SpeakerPoint{{32767, 5285, 0}, 9}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 24840, 32767}, 12}, SpeakerPoint{{24840, 24840, 32767}, 13}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}}},
{{AxisGroup{2, {7, 8, 0}}, AxisGroup{2, {9, 10, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
9, 3, 2, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 24840, 32767}, 12}, SpeakerPoint{{24840, 24840, 32767}, 13}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 2,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 24840, 32767}, 12}, SpeakerPoint{{24840, 24840, 32767}, 13}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 1, 2,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 24840, 32767}, 12}, SpeakerPoint{{24840, 24840, 32767}, 13}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
8, 3, 2, 2,
{{SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 24840, 32767}, 12}, SpeakerPoint{{24840, 24840, 32767}, 13}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{2, {2, 3, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {4, 5, 0}}, AxisGroup{2, {6, 7, 0}}, AxisGroup{}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 5285, 0}, 8}, SpeakerPoint{{32767, 5285, 0}, 9}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
},
LayoutGeometry{
0xE9Fu, 20, 16,
{{0, 1, 2, 3, 6, 7, 4, 5, 10, 11, 14, 15, 12, 13, 8, 9}},
{{
RegionGeometry{
15, 3, 4, 3,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{0, 5285, 0}, 8}, SpeakerPoint{{32767, 5285, 0}, 9}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 16384, 32767}, 12}, SpeakerPoint{{24840, 16384, 32767}, 13}, SpeakerPoint{{7928, 24840, 32767}, 14}, SpeakerPoint{{24840, 24840, 32767}, 15}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}}},
{{AxisGroup{2, {9, 10, 0}}, AxisGroup{2, {11, 12, 0}}, AxisGroup{2, {13, 14, 0}}, AxisGroup{}}}
},
RegionGeometry{
13, 3, 3, 3,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 5285, 0}, 8}, SpeakerPoint{{32767, 5285, 0}, 9}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 16384, 32767}, 12}, SpeakerPoint{{24840, 16384, 32767}, 13}, SpeakerPoint{{7928, 24840, 32767}, 14}, SpeakerPoint{{24840, 24840, 32767}, 15}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}}},
{{AxisGroup{2, {7, 8, 0}}, AxisGroup{2, {9, 10, 0}}, AxisGroup{2, {11, 12, 0}}, AxisGroup{}}}
},
RegionGeometry{
11, 3, 2, 3,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 16384, 32767}, 12}, SpeakerPoint{{24840, 16384, 32767}, 13}, SpeakerPoint{{7928, 24840, 32767}, 14}, SpeakerPoint{{24840, 24840, 32767}, 15}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{2, {9, 10, 0}}, AxisGroup{}}}
},
RegionGeometry{
9, 3, 2, 3,
{{SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 16384, 32767}, 12}, SpeakerPoint{{24840, 16384, 32767}, 13}, SpeakerPoint{{7928, 24840, 32767}, 14}, SpeakerPoint{{24840, 24840, 32767}, 15}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{1, {0, 0, 0}}, AxisGroup{2, {1, 2, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}}}
},
RegionGeometry{
9, 3, 1, 3,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 16384, 32767}, 12}, SpeakerPoint{{24840, 16384, 32767}, 13}, SpeakerPoint{{7928, 24840, 32767}, 14}, SpeakerPoint{{24840, 24840, 32767}, 15}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {3, 4, 0}}, AxisGroup{2, {5, 6, 0}}, AxisGroup{2, {7, 8, 0}}, AxisGroup{}}}
},
RegionGeometry{
10, 3, 2, 3,
{{SpeakerPoint{{0, 16384, 0}, 4}, SpeakerPoint{{32767, 16384, 0}, 5}, SpeakerPoint{{0, 32767, 0}, 6}, SpeakerPoint{{32767, 32767, 0}, 7}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{{7928, 16384, 32767}, 12}, SpeakerPoint{{24840, 16384, 32767}, 13}, SpeakerPoint{{7928, 24840, 32767}, 14}, SpeakerPoint{{24840, 24840, 32767}, 15}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{2, {0, 1, 0}}, AxisGroup{2, {2, 3, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {4, 5, 0}}, AxisGroup{2, {6, 7, 0}}, AxisGroup{2, {8, 9, 0}}, AxisGroup{}}}
},
RegionGeometry{
7, 3, 2, 1,
{{SpeakerPoint{{0, 0, 0}, 0}, SpeakerPoint{{32767, 0, 0}, 1}, SpeakerPoint{{16384, 0, 0}, 2}, SpeakerPoint{{0, 5285, 0}, 8}, SpeakerPoint{{32767, 5285, 0}, 9}, SpeakerPoint{{7928, 7928, 32767}, 10}, SpeakerPoint{{24840, 7928, 32767}, 11}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}, SpeakerPoint{}}},
{{AxisGroup{3, {0, 2, 1}}, AxisGroup{2, {3, 4, 0}}, AxisGroup{}, AxisGroup{}}},
{{AxisGroup{2, {5, 6, 0}}, AxisGroup{}, AxisGroup{}, AxisGroup{}}}
}
}}
}
}};
inline constexpr const LayoutGeometry* find_layout(const std::uint32_t speaker_bitfield) noexcept {
for (const auto& layout : kLayouts) {
if (layout.speaker_bitfield == speaker_bitfield) {
return &layout;
}
}
return nullptr;
}
} // namespace ejoc::speaker_tables
+495
View File
@@ -0,0 +1,495 @@
#define EJOC_BUILD_DLL
#include "eac3joc_core.h"
#include "speaker_layouts.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <new>
namespace ejoc::speaker {
using speaker_tables::AxisGroup;
using speaker_tables::LayoutGeometry;
using speaker_tables::RegionGeometry;
constexpr double kPi = 3.141592653589793238462643383279502884;
constexpr double kQ15Scale = 32768.0;
constexpr double kQ15Max = 32767.0 / kQ15Scale;
constexpr double kGainSnapThreshold = 1.0e-4;
constexpr std::size_t kObjects = EJOC_MAX_OBJECTS;
constexpr std::size_t kChannels = EJOC_OUTPUT_CHANNELS;
constexpr std::size_t kBlock = EJOC_SPEAKER_BLOCK_SAMPLES;
using PointGains = std::array<double, speaker_tables::kMaxPoints>;
using ChannelGains = std::array<double, kChannels>;
using ObjectChannelGains = std::array<ChannelGains, kObjects>;
using RemainingCounts = std::array<std::array<std::uint32_t, kChannels>, kObjects>;
inline double clamp(const double value, const double low, const double high) noexcept {
return value < low ? low : (value > high ? high : value);
}
inline double coordinate(const RegionGeometry& region, const std::size_t point,
const std::size_t component) noexcept {
return static_cast<double>(region.points[point].coordinate_q15[component]) / kQ15Scale;
}
std::uint64_t expand_speaker_bitfield(const std::uint32_t compact) noexcept {
constexpr std::array<std::uint64_t, 22> expansions{{
0x00000003ULL, 0x00000004ULL, 0x00000008ULL, 0x00000030ULL,
0x000000C0ULL, 0x00000100ULL, 0x00000600ULL, 0x00001800ULL,
0x00006000ULL, 0x00018000ULL, 0x00060000ULL, 0x00180000ULL,
0x00600000ULL, 0x01800000ULL, 0x06000000ULL, 0x18000000ULL,
0x60000000ULL, 0x080000000ULL, 0x600000000ULL, 0x800000000ULL,
0x1000000000ULL, 0x2000000000ULL,
}};
std::uint64_t expanded = 0;
for (std::size_t bit_index = 0; bit_index < expansions.size(); ++bit_index) {
if ((compact & (1u << bit_index)) != 0) {
expanded |= expansions[bit_index];
}
}
return expanded;
}
inline int bit(const std::uint64_t value, const unsigned index) noexcept {
return static_cast<int>((value >> index) & 1ULL);
}
double layout_attenuation_db(const std::uint32_t compact) noexcept {
const std::uint64_t expanded = expand_speaker_bitfield(compact);
const int height_channels = 2 * (
bit(expanded, 13) + bit(expanded, 15) + bit(expanded, 17) +
bit(expanded, 19) + bit(expanded, 21));
const int floor_channels = bit(expanded, 8) + 2 * (
bit(expanded, 31) + bit(expanded, 4) + bit(expanded, 6) +
bit(expanded, 11) + bit(expanded, 25) + bit(expanded, 27) +
bit(expanded, 29) + bit(expanded, 33));
const double height_factor = std::min(static_cast<double>(height_channels) / 4.0, 1.0);
const double floor_factor = std::min(static_cast<double>(floor_channels) / 4.0, 1.0);
return -std::max(4.5 - 1.5 * height_factor - 3.0 * floor_factor, 0.0);
}
int floor_y_exponent(const std::uint32_t compact) noexcept {
const std::uint32_t low = static_cast<std::uint32_t>(expand_speaker_bitfield(compact));
return ((low & 0x130u) != 0 && (low & 0x18C0u) == 0) ? 1 : 0;
}
inline void equal_power_pair(const double position, double& lower, double& upper) noexcept {
const double angle = (kPi * 0.5) * position;
lower = std::cos(angle);
upper = std::sin(angle);
}
void axis0_gains(const RegionGeometry& region,
const std::array<AxisGroup, speaker_tables::kMaxGroups>& groups,
const std::uint8_t group_count,
const double value,
PointGains& output) noexcept {
output.fill(0.0);
for (std::size_t row = 0; row < group_count; ++row) {
const auto& group = groups[row];
if (group.size == 0) {
continue;
}
const std::size_t first = group.indices[0];
const std::size_t last = group.indices[group.size - 1];
const double first_value = coordinate(region, first, 0);
const double last_value = coordinate(region, last, 0);
if (value <= first_value) {
output[first] = 1.0;
continue;
}
if (value >= last_value) {
output[last] = 1.0;
continue;
}
for (std::size_t index = 0; index + 1 < group.size; ++index) {
const std::size_t lower_index = group.indices[index];
const std::size_t upper_index = group.indices[index + 1];
const double lower_value = coordinate(region, lower_index, 0);
const double upper_value = coordinate(region, upper_index, 0);
if (value > lower_value && value <= upper_value) {
const double position = (value - lower_value) / (upper_value - lower_value);
equal_power_pair(position, output[lower_index], output[upper_index]);
break;
}
}
}
}
void axis1_gains(const RegionGeometry& region,
const std::array<AxisGroup, speaker_tables::kMaxGroups>& groups,
const std::uint8_t group_count,
const double value,
PointGains& output) noexcept {
output.fill(0.0);
if (group_count == 0) {
return;
}
const auto& first_group = groups[0];
const auto& last_group = groups[group_count - 1];
const double first_value = coordinate(region, first_group.indices[0], 1);
const double last_value = coordinate(region, last_group.indices[0], 1);
if (value <= first_value) {
for (std::size_t index = 0; index < first_group.size; ++index) {
output[first_group.indices[index]] = 1.0;
}
return;
}
if (value > last_value) {
for (std::size_t index = 0; index < last_group.size; ++index) {
output[last_group.indices[index]] = 1.0;
}
return;
}
for (std::size_t row = 0; row + 1 < group_count; ++row) {
const auto& lower_group = groups[row];
const auto& upper_group = groups[row + 1];
const double lower_value = coordinate(region, lower_group.indices[0], 1);
const double upper_value = coordinate(region, upper_group.indices[0], 1);
if (value >= lower_value && value <= upper_value) {
const double position = (value - lower_value) / (upper_value - lower_value);
double lower_gain = 0.0;
double upper_gain = 0.0;
equal_power_pair(position, lower_gain, upper_gain);
for (std::size_t index = 0; index < lower_group.size; ++index) {
output[lower_group.indices[index]] = lower_gain;
}
for (std::size_t index = 0; index < upper_group.size; ++index) {
output[upper_group.indices[index]] = upper_gain;
}
return;
}
}
}
void plane_gains(const RegionGeometry& region,
const std::array<AxisGroup, speaker_tables::kMaxGroups>& groups,
const std::uint8_t group_count,
const double u,
const double v,
const std::uint8_t mode,
PointGains& output) noexcept {
axis0_gains(region, groups, group_count, u, output);
if (mode >= 2) {
PointGains vertical{};
axis1_gains(region, groups, group_count, v, vertical);
for (std::size_t point = 0; point < region.point_count; ++point) {
output[point] *= vertical[point];
}
}
}
class Renderer {
public:
explicit Renderer(const LayoutGeometry* layout) noexcept : layout_(layout) {
for (std::size_t standard = 0; standard < layout_->channel_count; ++standard) {
standard_index_for_internal_[layout_->standard_from_internal[standard]] =
static_cast<std::uint8_t>(standard);
}
attenuation_db_ = layout_attenuation_db(layout_->speaker_bitfield);
floor_y_exponent_ = floor_y_exponent(layout_->speaker_bitfield);
reset_state();
}
int reset() noexcept {
reset_state();
error_[0] = '\0';
return 0;
}
const char* last_error() const noexcept {
return error_[0] ? error_.data() : "";
}
int process(const float* input,
const std::uint32_t sample_count,
const std::uint32_t metadata_count,
const std::uint32_t* metadata_offsets,
const std::uint32_t* ramp_durations,
const std::uint16_t* positions_q15,
const std::uint8_t* region_indices,
const std::uint8_t* height_enabled,
const double* object_gains,
double* output) noexcept {
error_[0] = '\0';
if (!input || !output) {
return fail("null PCM pointer passed to ejoc_speaker_renderer_process");
}
if ((sample_count % kBlock) != 0) {
return fail("sample_count must be a multiple of 32");
}
if (metadata_count && (!metadata_offsets || !ramp_durations || !positions_q15)) {
return fail("metadata arrays are null while metadata_count is nonzero");
}
if (!validate_metadata(sample_count, metadata_count, metadata_offsets,
positions_q15, region_indices, object_gains)) {
return -1;
}
std::fill(output, output + static_cast<std::size_t>(sample_count) * layout_->channel_count, 0.0);
const bool has_lfe = (layout_->speaker_bitfield & 0x4u) != 0;
const std::size_t total_blocks = sample_count / kBlock;
std::size_t event = 0;
for (std::size_t block = 0; block < total_blocks; ++block) {
while (event < metadata_count && aligned_block(metadata_offsets[event]) == block) {
apply_event(event, ramp_durations, positions_q15, region_indices,
height_enabled, object_gains);
++event;
}
mix_block(input, output, block, has_lfe);
}
while (event < metadata_count && aligned_block(metadata_offsets[event]) == total_blocks) {
apply_event(event, ramp_durations, positions_q15, region_indices,
height_enabled, object_gains);
++event;
}
if (event != metadata_count) {
return fail("metadata alignment produced an event outside this process call");
}
return 0;
}
private:
void reset_state() noexcept {
for (auto& row : current_) row.fill(0.0);
for (auto& row : target_) row.fill(0.0);
for (auto& row : step_) row.fill(0.0);
for (auto& row : remaining_) row.fill(0);
}
int fail(const char* message) noexcept {
std::snprintf(error_.data(), error_.size(), "%s", message);
return -1;
}
bool validate_metadata(const std::uint32_t sample_count,
const std::uint32_t metadata_count,
const std::uint32_t* metadata_offsets,
const std::uint16_t* positions_q15,
const std::uint8_t* region_indices,
const double* object_gains) noexcept {
for (std::size_t event = 0; event < metadata_count; ++event) {
if (metadata_offsets[event] > sample_count) {
fail("metadata offset exceeds sample_count");
return false;
}
if (event && metadata_offsets[event] < metadata_offsets[event - 1]) {
fail("metadata offsets must be nondecreasing");
return false;
}
for (std::size_t object = 0; object < kObjects; ++object) {
const std::size_t object_event = event * kObjects + object;
if (region_indices && region_indices[object_event] >= 7) {
fail("region index is above 6");
return false;
}
if (object_gains && !std::isfinite(object_gains[object_event])) {
fail("object gain is not finite");
return false;
}
const std::size_t coordinate_base = object_event * EJOC_SPEAKER_COORDINATES;
for (std::size_t component = 0; component < EJOC_SPEAKER_COORDINATES; ++component) {
if (positions_q15[coordinate_base + component] > 32767u) {
fail("Q15 object coordinate is above 32767");
return false;
}
}
}
}
return true;
}
static std::size_t aligned_block(const std::uint32_t sample) noexcept {
return (static_cast<std::size_t>(sample) + kBlock / 2 - 1) / kBlock;
}
static std::uint32_t ramp_blocks(const std::uint32_t duration) noexcept {
return static_cast<std::uint32_t>(
(static_cast<std::size_t>(duration) + kBlock / 2 - 1) / kBlock);
}
void render_point(const std::uint16_t* position,
const std::uint8_t region_index,
const bool enable_height,
const double object_gain,
ChannelGains& output) const noexcept {
output.fill(0.0);
const auto& region = layout_->regions[region_index];
const double u = static_cast<double>(position[0]) / kQ15Scale;
const double v = static_cast<double>(position[1]) / kQ15Scale;
const double w = static_cast<double>(position[2]) / kQ15Scale;
const double floor_v = clamp(std::ldexp(v, floor_y_exponent_), 0.0, 1.0);
PointGains floor{};
plane_gains(region, region.axis0_groups, region.axis0_group_count,
u, floor_v, region.mode, floor);
PointGains point = floor;
if (region.mode == 3) {
PointGains height{};
plane_gains(region, region.axis1_groups, region.axis1_group_count,
u, v, 3, height);
const double z = enable_height ? clamp(w, 0.0, kQ15Max) : 0.0;
if (z >= kQ15Max) {
point = height;
} else if (z > 0.0) {
double floor_weight = 0.0;
double height_weight = 0.0;
equal_power_pair(z, floor_weight, height_weight);
for (std::size_t index = 0; index < region.point_count; ++index) {
point[index] = floor[index] * floor_weight + height[index] * height_weight;
}
}
}
const double y_term = clamp(v / 0.6, 0.0, 1.0);
const double z_term = clamp((w - 0.2) / 0.8, 0.0, 1.0);
const double amount = clamp(y_term + z_term, 0.0, 1.0);
const double gain = std::pow(10.0, attenuation_db_ * amount / 20.0) * object_gain;
for (std::size_t index = 0; index < region.point_count; ++index) {
output[region.points[index].speaker_id] = point[index] * gain;
}
}
void apply_event(const std::size_t event,
const std::uint32_t* ramp_durations,
const std::uint16_t* positions_q15,
const std::uint8_t* region_indices,
const std::uint8_t* height_enabled,
const double* object_gains) noexcept {
const std::uint32_t blocks = ramp_blocks(ramp_durations[event]);
for (std::size_t object = 0; object < kObjects; ++object) {
const std::size_t object_event = event * kObjects + object;
const auto* position = positions_q15 + object_event * EJOC_SPEAKER_COORDINATES;
const std::uint8_t region = region_indices ? region_indices[object_event] : 0;
const bool height = !height_enabled || height_enabled[object_event] != 0;
const double object_gain = object_gains ? object_gains[object_event] : 1.0;
ChannelGains next{};
render_point(position, region, height, object_gain, next);
for (std::size_t channel = 0; channel < layout_->channel_count; ++channel) {
const double difference = next[channel] - current_[object][channel];
target_[object][channel] = next[channel];
if (std::abs(difference) >= kGainSnapThreshold && blocks != 0) {
step_[object][channel] = difference / static_cast<double>(blocks);
remaining_[object][channel] = blocks;
} else {
current_[object][channel] = next[channel];
step_[object][channel] = 0.0;
remaining_[object][channel] = 0;
}
}
}
}
void mix_block(const float* input, double* output, const std::size_t block,
const bool has_lfe) noexcept {
const std::size_t start = block * kBlock;
if (has_lfe) {
for (std::size_t sample = 0; sample < kBlock; ++sample) {
output[(start + sample) * layout_->channel_count + 3] =
static_cast<double>(input[(start + sample) * EJOC_OUTPUT_CHANNELS]);
}
}
for (std::size_t object = 0; object < kObjects; ++object) {
for (std::size_t internal = 0; internal < layout_->channel_count; ++internal) {
const bool active = remaining_[object][internal] != 0;
const double fixed_gain = target_[object][internal];
if (!active && fixed_gain == 0.0) {
continue;
}
const std::size_t standard = standard_index_for_internal_[internal];
for (std::size_t sample = 0; sample < kBlock; ++sample) {
const double gain = active
? current_[object][internal] +
(static_cast<double>(sample) / static_cast<double>(kBlock)) *
step_[object][internal]
: fixed_gain;
output[(start + sample) * layout_->channel_count + standard] +=
static_cast<double>(
input[(start + sample) * EJOC_OUTPUT_CHANNELS + object + 1]) * gain;
}
if (active) {
current_[object][internal] += step_[object][internal];
--remaining_[object][internal];
if (remaining_[object][internal] == 0) {
current_[object][internal] = target_[object][internal];
}
} else {
current_[object][internal] = target_[object][internal];
}
}
}
}
const LayoutGeometry* layout_;
double attenuation_db_{};
int floor_y_exponent_{};
ObjectChannelGains current_{};
ObjectChannelGains target_{};
ObjectChannelGains step_{};
RemainingCounts remaining_{};
std::array<std::uint8_t, kChannels> standard_index_for_internal_{};
std::array<char, 256> error_{};
};
} // namespace ejoc::speaker
extern "C" {
uint32_t EJOC_CALL ejoc_speaker_layout_channel_count(const uint32_t speaker_bitfield) {
const auto* layout = ejoc::speaker_tables::find_layout(speaker_bitfield);
return layout ? layout->channel_count : 0;
}
ejoc_speaker_renderer_handle EJOC_CALL ejoc_speaker_renderer_create(
const uint32_t speaker_bitfield) {
const auto* layout = ejoc::speaker_tables::find_layout(speaker_bitfield);
if (!layout) {
return nullptr;
}
return new (std::nothrow) ejoc::speaker::Renderer(layout);
}
void EJOC_CALL ejoc_speaker_renderer_destroy(ejoc_speaker_renderer_handle handle) {
delete static_cast<ejoc::speaker::Renderer*>(handle);
}
int EJOC_CALL ejoc_speaker_renderer_reset(ejoc_speaker_renderer_handle handle) {
if (!handle) {
return -1;
}
return static_cast<ejoc::speaker::Renderer*>(handle)->reset();
}
const char* EJOC_CALL ejoc_speaker_renderer_last_error(ejoc_speaker_renderer_handle handle) {
if (!handle) {
return "speaker renderer handle is null";
}
return static_cast<ejoc::speaker::Renderer*>(handle)->last_error();
}
int EJOC_CALL ejoc_speaker_renderer_process(
ejoc_speaker_renderer_handle handle,
const float* objects16_interleaved,
const uint32_t sample_count,
const uint32_t metadata_count,
const uint32_t* metadata_offsets,
const uint32_t* ramp_durations,
const uint16_t* positions_q15,
const uint8_t* region_indices,
const uint8_t* height_enabled,
const double* object_gains,
double* output_interleaved) {
if (!handle) {
return -1;
}
return static_cast<ejoc::speaker::Renderer*>(handle)->process(
objects16_interleaved, sample_count, metadata_count,
metadata_offsets, ramp_durations, positions_q15,
region_indices, height_enabled, object_gains, output_interleaved);
}
} // extern "C"