diff --git a/include/eac3joc_core.h b/include/eac3joc_core.h index 53e8bd4..a227d15 100644 --- a/include/eac3joc_core.h +++ b/include/eac3joc_core.h @@ -64,6 +64,15 @@ 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); +/* +Enables or disables the Ls/Rs band-0 21-tap DC compensation. The caller derives +it from the JOC downmix configuration: only configurations 3 and 4 enable the +filter. When disabled, band 0 keeps the common per-band processing (surround +delay plus -j rotation) instead of being overwritten by the FIR. The delay line +and DC history advance either way, so the flag may change between frames. +Defaults to enabled when never called. +*/ +EJOC_API int EJOC_CALL ejoc_renderer_set_dc_filter(ejoc_renderer_handle handle, uint32_t enabled); 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); diff --git a/src/joc_core/eac3joc_core.cpp b/src/joc_core/eac3joc_core.cpp index 9ea832d..3b79a24 100644 --- a/src/joc_core/eac3joc_core.cpp +++ b/src/joc_core/eac3joc_core.cpp @@ -125,6 +125,10 @@ public: return error_[0] ? error_ : ""; } + void set_dc_filter(const bool enabled) noexcept { + dc_filter_enabled_ = enabled; + } + int process( const float* bed5, const float* lfe, @@ -305,16 +309,18 @@ private: 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; + if (dc_filter_enabled_) { + 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}; } - 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]; @@ -641,6 +647,8 @@ private: float analysis_phase_; alignas(64) Complex surround_delay_[2][10][64]; alignas(64) Complex surround_history_[2][20]; + // band-0 的 21-tap DC 补偿开关;仅 downmix 配置 3/4 由调用方置位。 + bool dc_filter_enabled_ = true; alignas(64) double lfe_delay_[kLfeDelay]; alignas(64) double matrix_previous_[15][5][64]; alignas(64) double synthesis_state_[15][640]; @@ -696,6 +704,14 @@ int EJOC_CALL ejoc_renderer_set_threads(ejoc_renderer_handle handle, uint32_t to return static_cast(handle)->set_threads(total_threads); } +int EJOC_CALL ejoc_renderer_set_dc_filter(ejoc_renderer_handle handle, uint32_t enabled) { + if (!handle) { + return -1; + } + static_cast(handle)->set_dc_filter(enabled != 0); + return 0; +} + uint32_t EJOC_CALL ejoc_renderer_thread_count(ejoc_renderer_handle handle) { if (!handle) { return 0; diff --git a/src/joc_core/objects16.cpp b/src/joc_core/objects16.cpp index 1fb2ef3..62b45a3 100644 --- a/src/joc_core/objects16.cpp +++ b/src/joc_core/objects16.cpp @@ -52,6 +52,15 @@ Status rebuild_objects16(ejoc_renderer_handle handle, const joc_frame_params& pa } out16->assign(static_cast(JOC_OUTPUT_CHANNELS) * JOC_FRAME_SAMPLES, 0.0f); + // band-0 的 21-tap DC 补偿只在 downmix 配置 3/4 下启用,其余配置 band 0 + // 走与其他 band 相同的处理。 + const bool dc_filter = params.dmx_config_idx == 3 || params.dmx_config_idx == 4; + if (ejoc_renderer_set_dc_filter(handle, dc_filter ? 1u : 0u) != 0) { + if (error != nullptr) { + *error = "ejoc_renderer_set_dc_filter failed"; + } + return Status::fail(JOC_ERR_RENDER_FAILED, stage::kDsp, "ejoc_renderer_set_dc_filter failed"); + } const int result = ejoc_renderer_process( handle, bed5_planar, lfe, params.present_mask, n_bands, n_dpoints, slope_idx, offset_ts, dq.data(), params.clipgain, 0.0625f, gain, out16->data());