Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d8118684f | |||
| bb464b2c03 | |||
| 71bec4bda3 |
@@ -68,6 +68,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 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_reset(ejoc_renderer_handle handle);
|
||||||
EJOC_API int EJOC_CALL ejoc_renderer_set_threads(ejoc_renderer_handle handle, uint32_t total_threads);
|
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 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 const char* EJOC_CALL ejoc_renderer_last_error(ejoc_renderer_handle handle);
|
||||||
|
|
||||||
|
|||||||
@@ -125,6 +125,10 @@ public:
|
|||||||
return error_[0] ? error_ : "";
|
return error_[0] ? error_ : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_dc_filter(const bool enabled) noexcept {
|
||||||
|
dc_filter_enabled_ = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
int process(
|
int process(
|
||||||
const float* bed5,
|
const float* bed5,
|
||||||
const float* lfe,
|
const float* lfe,
|
||||||
@@ -305,6 +309,7 @@ private:
|
|||||||
for (int i = 0; i < 4; ++i) {
|
for (int i = 0; i < 4; ++i) {
|
||||||
dc_buffer[20 + i] = current[i][0];
|
dc_buffer[20 + i] = current[i][0];
|
||||||
}
|
}
|
||||||
|
if (dc_filter_enabled_) {
|
||||||
for (int slot = 0; slot < 4; ++slot) {
|
for (int slot = 0; slot < 4; ++slot) {
|
||||||
Complex sum{0.0, 0.0};
|
Complex sum{0.0, 0.0};
|
||||||
for (int tap = 0; tap < 21; ++tap) {
|
for (int tap = 0; tap < 21; ++tap) {
|
||||||
@@ -316,6 +321,7 @@ private:
|
|||||||
}
|
}
|
||||||
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) {
|
for (int i = 0; i < 20; ++i) {
|
||||||
surround_history_[surround][i] = dc_buffer[i + 4];
|
surround_history_[surround][i] = dc_buffer[i + 4];
|
||||||
}
|
}
|
||||||
@@ -641,6 +647,8 @@ private:
|
|||||||
float analysis_phase_;
|
float analysis_phase_;
|
||||||
alignas(64) Complex surround_delay_[2][10][64];
|
alignas(64) Complex surround_delay_[2][10][64];
|
||||||
alignas(64) Complex surround_history_[2][20];
|
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 lfe_delay_[kLfeDelay];
|
||||||
alignas(64) double matrix_previous_[15][5][64];
|
alignas(64) double matrix_previous_[15][5][64];
|
||||||
alignas(64) double synthesis_state_[15][640];
|
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<ejoc::Renderer*>(handle)->set_threads(total_threads);
|
return static_cast<ejoc::Renderer*>(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<ejoc::Renderer*>(handle)->set_dc_filter(enabled != 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t EJOC_CALL ejoc_renderer_thread_count(ejoc_renderer_handle handle) {
|
uint32_t EJOC_CALL ejoc_renderer_thread_count(ejoc_renderer_handle handle) {
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -52,6 +52,15 @@ Status rebuild_objects16(ejoc_renderer_handle handle, const joc_frame_params& pa
|
|||||||
}
|
}
|
||||||
|
|
||||||
out16->assign(static_cast<std::size_t>(JOC_OUTPUT_CHANNELS) * JOC_FRAME_SAMPLES, 0.0f);
|
out16->assign(static_cast<std::size_t>(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(
|
const int result = ejoc_renderer_process(
|
||||||
handle, bed5_planar, lfe, params.present_mask, n_bands, n_dpoints, slope_idx, offset_ts,
|
handle, bed5_planar, lfe, params.present_mask, n_bands, n_dpoints, slope_idx, offset_ts,
|
||||||
dq.data(), params.clipgain, 0.0625f, gain, out16->data());
|
dq.data(), params.clipgain, 0.0625f, gain, out16->data());
|
||||||
|
|||||||
+17
-2
@@ -200,15 +200,24 @@ Result scan_mp4(const Window& file, std::size_t max_bytes) {
|
|||||||
Result result;
|
Result result;
|
||||||
result.kind = Kind::kMp4;
|
result.kind = Kind::kMp4;
|
||||||
|
|
||||||
// moov is usually at the start for streamed files and at the end otherwise.
|
// moov is usually at the start for streamed files and at the end otherwise. The
|
||||||
|
// walk reads box headers where they lie and steps over mdat in one go, so the
|
||||||
|
// whole file is walked from the top: a fixed prefix window cannot reach a moov
|
||||||
|
// that is larger than the window, which is what an MP4 with its cover art stored
|
||||||
|
// as a video track produces (a 4.9 MB moov against a 4 MiB window). The tail
|
||||||
|
// range stays as a fallback for a file whose leading boxes do not parse.
|
||||||
struct Range {
|
struct Range {
|
||||||
std::uint64_t begin;
|
std::uint64_t begin;
|
||||||
std::uint64_t end;
|
std::uint64_t end;
|
||||||
};
|
};
|
||||||
std::vector<Range> ranges{{0, (std::min<std::uint64_t>)(file.size(), max_bytes)}};
|
std::vector<Range> ranges{{0, file.size()}};
|
||||||
if (file.size() > max_bytes) {
|
if (file.size() > max_bytes) {
|
||||||
ranges.push_back({file.size() - max_bytes, file.size()});
|
ranges.push_back({file.size() - max_bytes, file.size()});
|
||||||
}
|
}
|
||||||
|
// An oversized moov is a file this probe cannot describe, and walking it would be
|
||||||
|
// unbounded work; it is reported instead of entered.
|
||||||
|
constexpr std::uint64_t kMaxMoovBytes = 64ull * 1024ull * 1024ull;
|
||||||
|
bool oversized_moov = false;
|
||||||
|
|
||||||
unsigned audio_seen = 0;
|
unsigned audio_seen = 0;
|
||||||
bool found_any_audio = false;
|
bool found_any_audio = false;
|
||||||
@@ -218,6 +227,10 @@ Result scan_mp4(const Window& file, std::size_t max_bytes) {
|
|||||||
[&](const std::string& type, std::uint64_t payload, std::uint64_t box_end,
|
[&](const std::string& type, std::uint64_t payload, std::uint64_t box_end,
|
||||||
std::size_t) {
|
std::size_t) {
|
||||||
if (type != "moov") return true;
|
if (type != "moov") return true;
|
||||||
|
if (box_end - payload > kMaxMoovBytes) {
|
||||||
|
oversized_moov = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
walk_boxes(file, payload, box_end, 1,
|
walk_boxes(file, payload, box_end, 1,
|
||||||
[&](const std::string& inner, std::uint64_t inner_payload,
|
[&](const std::string& inner, std::uint64_t inner_payload,
|
||||||
std::uint64_t inner_end, std::size_t) {
|
std::uint64_t inner_end, std::size_t) {
|
||||||
@@ -273,6 +286,8 @@ Result scan_mp4(const Window& file, std::size_t max_bytes) {
|
|||||||
result.detail = "mp4: first audio track is " +
|
result.detail = "mp4: first audio track is " +
|
||||||
(first_audio_format.empty() ? std::string("unknown")
|
(first_audio_format.empty() ? std::string("unknown")
|
||||||
: first_audio_format);
|
: first_audio_format);
|
||||||
|
} else if (oversized_moov) {
|
||||||
|
result.detail = "mp4: moov is larger than the scan limit";
|
||||||
} else {
|
} else {
|
||||||
result.detail = "mp4: no audio track found in the scanned window";
|
result.detail = "mp4: no audio track found in the scanned window";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,6 +30,32 @@ constexpr std::size_t kBedReadBytes = 48u * 1024u;
|
|||||||
constexpr std::size_t kBedPipeBytes = 1u << 20;
|
constexpr std::size_t kBedPipeBytes = 1u << 20;
|
||||||
constexpr std::size_t kFrameSamples = JOC_FRAME_SAMPLES;
|
constexpr std::size_t kFrameSamples = JOC_FRAME_SAMPLES;
|
||||||
|
|
||||||
|
// The decoded bed has to stay on the E-AC-3 frame grid that the JOC matrix and the
|
||||||
|
// OAMD are indexed by. An mp4/mov edit list trims the decoded audio instead, which
|
||||||
|
// takes the bed off that grid by however much the list removes -- a Dolby Atmos
|
||||||
|
// download loses 2432 samples (1.58 frames) -- and every frame's matrix would then be
|
||||||
|
// applied to audio tens of milliseconds away from it, so a subset of the objects comes
|
||||||
|
// out attenuated. The demuxer's own option drops the trim; the option exists only on
|
||||||
|
// the mov/mp4 demuxer, so it is passed for that family alone.
|
||||||
|
bool has_mov_timeline(const std::string& path) {
|
||||||
|
static const char* const kExtensions[] = {".mp4", ".m4a", ".m4b", ".m4v",
|
||||||
|
".mov", ".3gp", ".3g2", ".mj2"};
|
||||||
|
std::string lowered = path;
|
||||||
|
for (char& character : lowered) {
|
||||||
|
if (character >= 'A' && character <= 'Z') {
|
||||||
|
character = static_cast<char>(character - 'A' + 'a');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const char* extension : kExtensions) {
|
||||||
|
const std::size_t length = std::strlen(extension);
|
||||||
|
if (lowered.size() >= length &&
|
||||||
|
lowered.compare(lowered.size() - length, length, extension) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Kernel entry points.
|
// Kernel entry points.
|
||||||
//
|
//
|
||||||
@@ -685,6 +711,7 @@ bool Engine::Impl::start_bed(std::uint64_t source_sample, std::string* error) {
|
|||||||
// at the start of the file, which is a low-level, noise-like difference from a
|
// at the start of the file, which is a low-level, noise-like difference from a
|
||||||
// play-through rather than a misalignment: the position stays exact.
|
// play-through rather than a misalignment: the position stays exact.
|
||||||
std::wstring input_arguments = L"-drc_scale 0 -target_level 0";
|
std::wstring input_arguments = L"-drc_scale 0 -target_level 0";
|
||||||
|
if (has_mov_timeline(input_path)) input_arguments += L" -ignore_editlist 1";
|
||||||
const std::wstring offset = seek_time(source_sample);
|
const std::wstring offset = seek_time(source_sample);
|
||||||
if (!offset.empty()) input_arguments += L" -ss " + offset;
|
if (!offset.empty()) input_arguments += L" -ss " + offset;
|
||||||
std::wstring bed_arguments = L"-map 0:a:";
|
std::wstring bed_arguments = L"-map 0:a:";
|
||||||
|
|||||||
+1
-1
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
// Kept in one place: the string reported to foobar2000 and written to the log
|
// Kept in one place: the string reported to foobar2000 and written to the log
|
||||||
// must not drift apart.
|
// must not drift apart.
|
||||||
#define JOC_VERSION "0.2.0"
|
#define JOC_VERSION "0.2.2"
|
||||||
|
|
||||||
DECLARE_COMPONENT_VERSION("JOC decoder (E-AC-3 JOC)", JOC_VERSION,
|
DECLARE_COMPONENT_VERSION("JOC decoder (E-AC-3 JOC)", JOC_VERSION,
|
||||||
"Plays E-AC-3 JOC (Dolby Atmos) files: the JOC objects are "
|
"Plays E-AC-3 JOC (Dolby Atmos) files: the JOC objects are "
|
||||||
|
|||||||
+21
-15
@@ -189,6 +189,7 @@ private:
|
|||||||
}
|
}
|
||||||
if (pick_file(m_hwnd, path, title, filter)) {
|
if (pick_file(m_hwnd, path, title, filter)) {
|
||||||
set_text(GetDlgItem(m_hwnd, IDC_EDIT_HRTF), path);
|
set_text(GetDlgItem(m_hwnd, IDC_EDIT_HRTF), path);
|
||||||
|
update_status();
|
||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
@@ -219,6 +220,10 @@ private:
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (code == EN_CHANGE || code == CBN_SELCHANGE) {
|
if (code == EN_CHANGE || code == CBN_SELCHANGE) {
|
||||||
|
if (id == IDC_EDIT_HRTF || id == IDC_COMBO_LAYOUT ||
|
||||||
|
id == IDC_EDIT_GAIN) {
|
||||||
|
update_status();
|
||||||
|
}
|
||||||
notify();
|
notify();
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -338,35 +343,36 @@ private:
|
|||||||
void update_enabled_state() { update_status(); }
|
void update_enabled_state() { update_status(); }
|
||||||
|
|
||||||
void update_status() {
|
void update_status() {
|
||||||
const joc_settings::Values values = joc_settings::read();
|
const joc_settings::Values values = read_controls();
|
||||||
std::string status;
|
std::string output_status;
|
||||||
if (values.output != 0) {
|
if (values.output != 0) {
|
||||||
char text[96] = {};
|
char text[96] = {};
|
||||||
const unsigned channels = joc_decode::speaker_channels(values.speaker_layout);
|
const unsigned channels = joc_decode::speaker_channels(values.speaker_layout);
|
||||||
std::snprintf(text, sizeof(text), "扬声器布局 %s(%u 声道)",
|
std::snprintf(text, sizeof(text), "扬声器布局 %s(%u 声道)",
|
||||||
values.speaker_layout.c_str(), channels);
|
values.speaker_layout.c_str(), channels);
|
||||||
status = text;
|
output_status = text;
|
||||||
} else {
|
}
|
||||||
// Show what will actually be read, so an empty box is not a mystery.
|
set_text(GetDlgItem(m_hwnd, IDC_LABEL_OUTPUT_STATUS), output_status);
|
||||||
|
|
||||||
joc_decode::Settings effective = joc_settings::current();
|
joc_decode::Settings effective = joc_settings::current();
|
||||||
effective.hrtf_source =
|
effective.hrtf_source =
|
||||||
static_cast<joc_decode::HrtfSource>(values.hrtf_source);
|
static_cast<joc_decode::HrtfSource>(values.hrtf_source);
|
||||||
effective.hrtf_file = values.hrtf_file;
|
effective.hrtf_file = values.hrtf_file;
|
||||||
const std::string file = joc_decode::resolve_hrtf_file(effective);
|
const std::string file = joc_decode::resolve_hrtf_file(effective);
|
||||||
status = std::string(joc_settings::hrtf_source_name(values.hrtf_source)) + ":" +
|
std::string hrtf_status =
|
||||||
(file.empty() ? std::string("无法确定默认路径")
|
std::string(joc_settings::hrtf_source_name(values.hrtf_source)) + ":";
|
||||||
: (values.hrtf_file.empty() ? "默认 " + file : file));
|
if (values.hrtf_file.empty()) hrtf_status += "默认";
|
||||||
}
|
hrtf_status += "\n" +
|
||||||
// Say what is actually in effect, including the parts that do not apply
|
(file.empty() ? std::string("无法确定默认路径") : file);
|
||||||
// to the selected output mode, so nothing has to be greyed out.
|
set_text(GetDlgItem(m_hwnd, IDC_LABEL_STATUS), hrtf_status);
|
||||||
|
|
||||||
char gain[96] = {};
|
char gain[96] = {};
|
||||||
if (values.gain_enabled) {
|
if (values.gain_enabled) {
|
||||||
std::snprintf(gain, sizeof(gain), "\n增益开 %.2f dB", values.gain_db);
|
std::snprintf(gain, sizeof(gain), "增益开 %.2f dB", values.gain_db);
|
||||||
} else {
|
} else {
|
||||||
std::snprintf(gain, sizeof(gain), "\n增益关(输出不衰减)");
|
std::snprintf(gain, sizeof(gain), "增益关(输出不衰减)");
|
||||||
}
|
}
|
||||||
status += gain;
|
set_text(GetDlgItem(m_hwnd, IDC_LABEL_GAIN_STATUS), gain);
|
||||||
set_text(GetDlgItem(m_hwnd, IDC_LABEL_STATUS), status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool changed() const {
|
bool changed() const {
|
||||||
|
|||||||
+23
-21
@@ -7,11 +7,11 @@
|
|||||||
// sample page uses (SDK\foobar2000\foo_sample\foo_sample.rc). A CAPTION statement
|
// sample page uses (SDK\foobar2000\foo_sample\foo_sample.rc). A CAPTION statement
|
||||||
// implies WS_CAPTION, which would draw a second frame inside the host's and shift
|
// implies WS_CAPTION, which would draw a second frame inside the host's and shift
|
||||||
// every control down by the caption height -- visible but not clickable.
|
// every control down by the caption height -- visible but not clickable.
|
||||||
IDD_JOC_PREFS DIALOGEX 0, 0, 330, 226
|
IDD_JOC_PREFS DIALOGEX 0, 0, 330, 273
|
||||||
STYLE DS_SETFONT | WS_CHILD
|
STYLE DS_SETFONT | WS_CHILD
|
||||||
FONT 8, "Microsoft Sans Serif", 400, 0, 0x0
|
FONT 8, "Microsoft Sans Serif", 400, 0, 0x0
|
||||||
BEGIN
|
BEGIN
|
||||||
GROUPBOX "输出", IDC_GROUP_OUTPUT, 7, 5, 316, 64
|
GROUPBOX "输出", IDC_GROUP_OUTPUT, 7, 5, 316, 61
|
||||||
CONTROL "双耳(HRTF)", IDC_RADIO_BINAURAL, "Button",
|
CONTROL "双耳(HRTF)", IDC_RADIO_BINAURAL, "Button",
|
||||||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 16, 20, 72, 10
|
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 16, 20, 72, 10
|
||||||
CONTROL "扬声器布局", IDC_RADIO_SPEAKER, "Button",
|
CONTROL "扬声器布局", IDC_RADIO_SPEAKER, "Button",
|
||||||
@@ -22,31 +22,33 @@ BEGIN
|
|||||||
LTEXT "双耳模式", IDC_LABEL_MODE, 172, 22, 42, 10
|
LTEXT "双耳模式", IDC_LABEL_MODE, 172, 22, 42, 10
|
||||||
COMBOBOX IDC_COMBO_MODE, 216, 19, 96, 90,
|
COMBOBOX IDC_COMBO_MODE, 216, 19, 96, 90,
|
||||||
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||||
LTEXT "房间尾音(秒)", IDC_LABEL_TAIL, 172, 41, 46, 10
|
LTEXT "房间尾音(秒)", IDC_LABEL_TAIL, 172, 41, 62, 10
|
||||||
EDITTEXT IDC_EDIT_TAIL, 220, 38, 40, 13, ES_AUTOHSCROLL
|
EDITTEXT IDC_EDIT_TAIL, 238, 38, 40, 13, ES_AUTOHSCROLL
|
||||||
|
LTEXT "", IDC_LABEL_OUTPUT_STATUS, 16, 52, 300, 10
|
||||||
|
|
||||||
GROUPBOX "HRTF", IDC_GROUP_HRTF, 7, 74, 316, 84
|
GROUPBOX "HRTF", IDC_GROUP_HRTF, 7, 71, 316, 100
|
||||||
CONTROL "SOFA 文件", IDC_RADIO_HRTF_SOFA, "Button",
|
CONTROL "SOFA 文件", IDC_RADIO_HRTF_SOFA, "Button",
|
||||||
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 16, 89, 56, 10
|
BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP, 16, 86, 56, 10
|
||||||
CONTROL "Rosella 个性化模型", IDC_RADIO_HRTF_ROSELLA, "Button",
|
CONTROL "Rosella 个性化模型", IDC_RADIO_HRTF_ROSELLA, "Button",
|
||||||
BS_AUTORADIOBUTTON | WS_TABSTOP, 78, 89, 78, 10
|
BS_AUTORADIOBUTTON | WS_TABSTOP, 78, 86, 78, 10
|
||||||
LTEXT "HRTF 文件(留空=默认位置)", IDC_LABEL_HRTF, 16, 106, 92, 10
|
LTEXT "HRTF 文件(留空=默认位置)", IDC_LABEL_HRTF, 16, 105, 106, 10
|
||||||
EDITTEXT IDC_EDIT_HRTF, 110, 103, 164, 13, ES_AUTOHSCROLL
|
EDITTEXT IDC_EDIT_HRTF, 126, 102, 148, 13, ES_AUTOHSCROLL
|
||||||
PUSHBUTTON "浏览…", IDC_BROWSE_HRTF, 279, 103, 38, 13
|
PUSHBUTTON "浏览…", IDC_BROWSE_HRTF, 279, 102, 38, 13
|
||||||
LTEXT "留空时读组件目录下 HRTF\\binaural.sofa 或 binaural.personalized_headphone;SOFA 由渲染器内部编译,滤波组表已编入库中。",
|
LTEXT "留空时读组件目录下 HRTF\\binaural.sofa 或 binaural.personalized_headphone;SOFA 由渲染器内部编译,滤波组表已编入库中。",
|
||||||
IDC_LABEL_HRTF_HINT, 16, 122, 300, 30
|
IDC_LABEL_HRTF_HINT, 16, 121, 300, 20
|
||||||
|
LTEXT "", IDC_LABEL_STATUS, 16, 145, 300, 20
|
||||||
|
|
||||||
GROUPBOX "增益", IDC_GROUP_GAIN, 7, 162, 152, 56
|
GROUPBOX "增益", IDC_GROUP_GAIN, 7, 176, 316, 48
|
||||||
CONTROL "应用增益", IDC_CHECK_GAIN, "Button",
|
CONTROL "应用增益", IDC_CHECK_GAIN, "Button",
|
||||||
BS_AUTOCHECKBOX | WS_TABSTOP, 16, 178, 58, 10
|
BS_AUTOCHECKBOX | WS_TABSTOP, 16, 192, 58, 10
|
||||||
LTEXT "dB", IDC_LABEL_GAIN, 80, 178, 12, 10
|
LTEXT "dB", IDC_LABEL_GAIN, 80, 192, 12, 10
|
||||||
EDITTEXT IDC_EDIT_GAIN, 96, 175, 40, 13, ES_AUTOHSCROLL
|
EDITTEXT IDC_EDIT_GAIN, 96, 189, 40, 13, ES_AUTOHSCROLL
|
||||||
|
LTEXT "", IDC_LABEL_GAIN_STATUS, 145, 192, 171, 10
|
||||||
LTEXT "双耳渲染后可能超过 0 dBFS,可用负值衰减。",
|
LTEXT "双耳渲染后可能超过 0 dBFS,可用负值衰减。",
|
||||||
IDC_LABEL_GAIN_HINT, 16, 194, 134, 20
|
IDC_LABEL_GAIN_HINT, 16, 208, 300, 10
|
||||||
|
|
||||||
GROUPBOX "其它", IDC_GROUP_MISC, 165, 162, 158, 56
|
GROUPBOX "其它", IDC_GROUP_MISC, 7, 229, 316, 38
|
||||||
LTEXT "ffmpeg.exe", IDC_LABEL_FFMPEG, 173, 178, 44, 10
|
LTEXT "ffmpeg.exe", IDC_LABEL_FFMPEG, 16, 245, 44, 10
|
||||||
EDITTEXT IDC_EDIT_FFMPEG, 216, 175, 62, 13, ES_AUTOHSCROLL
|
EDITTEXT IDC_EDIT_FFMPEG, 64, 242, 210, 13, ES_AUTOHSCROLL
|
||||||
PUSHBUTTON "浏览…", IDC_BROWSE_FFMPEG, 282, 175, 35, 13
|
PUSHBUTTON "浏览…", IDC_BROWSE_FFMPEG, 279, 242, 38, 13
|
||||||
LTEXT "", IDC_LABEL_STATUS, 173, 194, 144, 20
|
|
||||||
END
|
END
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#define IDC_COMBO_MODE 2016
|
#define IDC_COMBO_MODE 2016
|
||||||
#define IDC_LABEL_TAIL 2017
|
#define IDC_LABEL_TAIL 2017
|
||||||
#define IDC_EDIT_TAIL 2018
|
#define IDC_EDIT_TAIL 2018
|
||||||
|
#define IDC_LABEL_OUTPUT_STATUS 2019
|
||||||
|
|
||||||
#define IDC_GROUP_HRTF 2020
|
#define IDC_GROUP_HRTF 2020
|
||||||
#define IDC_RADIO_HRTF_SOFA 2021
|
#define IDC_RADIO_HRTF_SOFA 2021
|
||||||
@@ -26,6 +27,7 @@
|
|||||||
#define IDC_LABEL_GAIN 2032
|
#define IDC_LABEL_GAIN 2032
|
||||||
#define IDC_EDIT_GAIN 2033
|
#define IDC_EDIT_GAIN 2033
|
||||||
#define IDC_LABEL_GAIN_HINT 2034
|
#define IDC_LABEL_GAIN_HINT 2034
|
||||||
|
#define IDC_LABEL_GAIN_STATUS 2035
|
||||||
|
|
||||||
#define IDC_GROUP_MISC 2040
|
#define IDC_GROUP_MISC 2040
|
||||||
#define IDC_LABEL_FFMPEG 2041
|
#define IDC_LABEL_FFMPEG 2041
|
||||||
|
|||||||
Reference in New Issue
Block a user