mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-07-13 15:44:36 +00:00
update openal-soft to 1.24.3
keeping the alt 87514151c4 (diff-73a8dc1ce58605f6c5ea53548454c3bae516ec5132a29c9d7ff7edf9730c75be)
This commit is contained in:
parent
12db0500e8
commit
ba32094b7b
276 changed files with 49304 additions and 8712 deletions
|
|
@ -12,14 +12,14 @@ if(Qt5Widgets_FOUND)
|
|||
verstr.cpp
|
||||
verstr.h
|
||||
${UIS} ${RSCS} ${TRS} ${MOCS})
|
||||
target_link_libraries(alsoft-config PUBLIC Qt5::Widgets PRIVATE alcommon)
|
||||
target_link_libraries(alsoft-config PUBLIC Qt5::Widgets PRIVATE alsoft.common)
|
||||
target_include_directories(alsoft-config PRIVATE "${alsoft-config_BINARY_DIR}"
|
||||
"${OpenAL_BINARY_DIR}")
|
||||
target_compile_definitions(alsoft-config PRIVATE QT_NO_KEYWORDS)
|
||||
set_target_properties(alsoft-config PROPERTIES ${DEFAULT_TARGET_PROPS}
|
||||
RUNTIME_OUTPUT_DIRECTORY ${OpenAL_BINARY_DIR})
|
||||
if(TARGET build_version)
|
||||
add_dependencies(alsoft-config build_version)
|
||||
if(TARGET alsoft.build_version)
|
||||
add_dependencies(alsoft-config alsoft.build_version)
|
||||
endif()
|
||||
|
||||
message(STATUS "Building configuration program")
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
|
||||
#include "config.h"
|
||||
#include "config_backends.h"
|
||||
#include "config_simd.h"
|
||||
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
|
@ -32,48 +34,48 @@ struct BackendNamePair {
|
|||
/* NOLINTEND(*-avoid-c-arrays) */
|
||||
};
|
||||
constexpr std::array backendList{
|
||||
#ifdef HAVE_PIPEWIRE
|
||||
#if HAVE_PIPEWIRE
|
||||
BackendNamePair{ "pipewire", "PipeWire" },
|
||||
#endif
|
||||
#ifdef HAVE_PULSEAUDIO
|
||||
#if HAVE_PULSEAUDIO
|
||||
BackendNamePair{ "pulse", "PulseAudio" },
|
||||
#endif
|
||||
#ifdef HAVE_ALSA
|
||||
BackendNamePair{ "alsa", "ALSA" },
|
||||
#endif
|
||||
#ifdef HAVE_JACK
|
||||
BackendNamePair{ "jack", "JACK" },
|
||||
#endif
|
||||
#ifdef HAVE_COREAUDIO
|
||||
BackendNamePair{ "core", "CoreAudio" },
|
||||
#endif
|
||||
#ifdef HAVE_OSS
|
||||
BackendNamePair{ "oss", "OSS" },
|
||||
#endif
|
||||
#ifdef HAVE_SOLARIS
|
||||
BackendNamePair{ "solaris", "Solaris" },
|
||||
#endif
|
||||
#ifdef HAVE_SNDIO
|
||||
BackendNamePair{ "sndio", "SndIO" },
|
||||
#endif
|
||||
#ifdef HAVE_WASAPI
|
||||
#if HAVE_WASAPI
|
||||
BackendNamePair{ "wasapi", "WASAPI" },
|
||||
#endif
|
||||
#ifdef HAVE_DSOUND
|
||||
#if HAVE_COREAUDIO
|
||||
BackendNamePair{ "core", "CoreAudio" },
|
||||
#endif
|
||||
#if HAVE_OPENSL
|
||||
BackendNamePair{ "opensl", "OpenSL" },
|
||||
#endif
|
||||
#if HAVE_ALSA
|
||||
BackendNamePair{ "alsa", "ALSA" },
|
||||
#endif
|
||||
#if HAVE_SOLARIS
|
||||
BackendNamePair{ "solaris", "Solaris" },
|
||||
#endif
|
||||
#if HAVE_SNDIO
|
||||
BackendNamePair{ "sndio", "SndIO" },
|
||||
#endif
|
||||
#if HAVE_OSS
|
||||
BackendNamePair{ "oss", "OSS" },
|
||||
#endif
|
||||
#if HAVE_DSOUND
|
||||
BackendNamePair{ "dsound", "DirectSound" },
|
||||
#endif
|
||||
#ifdef HAVE_WINMM
|
||||
#if HAVE_WINMM
|
||||
BackendNamePair{ "winmm", "Windows Multimedia" },
|
||||
#endif
|
||||
#ifdef HAVE_PORTAUDIO
|
||||
#if HAVE_PORTAUDIO
|
||||
BackendNamePair{ "port", "PortAudio" },
|
||||
#endif
|
||||
#ifdef HAVE_OPENSL
|
||||
BackendNamePair{ "opensl", "OpenSL" },
|
||||
#if HAVE_JACK
|
||||
BackendNamePair{ "jack", "JACK" },
|
||||
#endif
|
||||
|
||||
BackendNamePair{ "null", "Null Output" },
|
||||
#ifdef HAVE_WAVE
|
||||
#if HAVE_WAVE
|
||||
BackendNamePair{ "wave", "Wave Writer" },
|
||||
#endif
|
||||
};
|
||||
|
|
@ -112,12 +114,14 @@ constexpr std::array resamplerList{
|
|||
NameValuePair{ "Point", "point" },
|
||||
NameValuePair{ "Linear", "linear" },
|
||||
NameValuePair{ "Cubic Spline", "spline" },
|
||||
NameValuePair{ "Default (Cubic Spline)", "" },
|
||||
NameValuePair{ "4-point Gaussian", "gaussian" },
|
||||
NameValuePair{ "Default (4-point Gaussian)", "" },
|
||||
NameValuePair{ "11th order Sinc (fast)", "fast_bsinc12" },
|
||||
NameValuePair{ "11th order Sinc", "bsinc12" },
|
||||
NameValuePair{ "23rd order Sinc (fast)", "fast_bsinc24" },
|
||||
NameValuePair{ "23rd order Sinc", "bsinc24" },
|
||||
NameValuePair{ "47th order Sinc (fast)", "fast_bsinc48" },
|
||||
NameValuePair{ "47th order Sinc", "bsinc48" },
|
||||
};
|
||||
constexpr std::array stereoModeList{
|
||||
NameValuePair{ "Autodetect", "" },
|
||||
|
|
@ -145,19 +149,35 @@ constexpr std::array hrtfModeList{
|
|||
NameValuePair{ "Full", "full" },
|
||||
};
|
||||
|
||||
constexpr auto GetDefaultIndex(const al::span<const NameValuePair> list) -> size_t
|
||||
{
|
||||
for(size_t i{0};i < list.size();++i)
|
||||
{
|
||||
if(!list[i].value[0])
|
||||
return i;
|
||||
}
|
||||
throw std::runtime_error{"Failed to find default entry"};
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
struct CoTaskMemDeleter {
|
||||
void operator()(void *buffer) { CoTaskMemFree(buffer); }
|
||||
};
|
||||
/* NOLINTNEXTLINE(*-avoid-c-arrays) */
|
||||
using WCharBufferPtr = std::unique_ptr<WCHAR[],CoTaskMemDeleter>;
|
||||
#endif
|
||||
|
||||
QString getDefaultConfigName()
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
const char *fname{"alsoft.ini"};
|
||||
auto get_appdata_path = []() noexcept -> QString
|
||||
static constexpr auto get_appdata_path = []() -> QString
|
||||
{
|
||||
QString ret;
|
||||
WCHAR *buffer{};
|
||||
auto buffer = WCharBufferPtr{};
|
||||
if(const HRESULT hr{SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DONT_UNEXPAND,
|
||||
nullptr, &buffer)}; SUCCEEDED(hr))
|
||||
ret = QString::fromWCharArray(buffer);
|
||||
CoTaskMemFree(buffer);
|
||||
return ret;
|
||||
nullptr, al::out_ptr(buffer))}; SUCCEEDED(hr))
|
||||
return QString::fromWCharArray(buffer.get());
|
||||
return QString{};
|
||||
};
|
||||
QString base = get_appdata_path();
|
||||
#else
|
||||
|
|
@ -178,15 +198,13 @@ QString getDefaultConfigName()
|
|||
QString getBaseDataPath()
|
||||
{
|
||||
#ifdef Q_OS_WIN32
|
||||
auto get_appdata_path = []() noexcept -> QString
|
||||
static constexpr auto get_appdata_path = []() -> QString
|
||||
{
|
||||
QString ret;
|
||||
WCHAR *buffer{};
|
||||
auto buffer = WCharBufferPtr{};
|
||||
if(const HRESULT hr{SHGetKnownFolderPath(FOLDERID_RoamingAppData, KF_FLAG_DONT_UNEXPAND,
|
||||
nullptr, &buffer)}; SUCCEEDED(hr))
|
||||
ret = QString::fromWCharArray(buffer);
|
||||
CoTaskMemFree(buffer);
|
||||
return ret;
|
||||
nullptr, al::out_ptr(buffer))}; SUCCEEDED(hr))
|
||||
return QString::fromWCharArray(buffer.get());
|
||||
return QString{};
|
||||
};
|
||||
QString base = get_appdata_path();
|
||||
#else
|
||||
|
|
@ -297,18 +315,18 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}
|
|||
ui->resamplerSlider->setRange(0, resamplerList.size()-1);
|
||||
ui->hrtfmodeSlider->setRange(0, hrtfModeList.size()-1);
|
||||
|
||||
#if !defined(HAVE_NEON) && !defined(HAVE_SSE)
|
||||
#if !HAVE_NEON && !HAVE_SSE
|
||||
ui->cpuExtDisabledLabel->move(ui->cpuExtDisabledLabel->x(), ui->cpuExtDisabledLabel->y() - 60);
|
||||
#else
|
||||
ui->cpuExtDisabledLabel->setVisible(false);
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_NEON
|
||||
#if !HAVE_NEON
|
||||
|
||||
#ifndef HAVE_SSE4_1
|
||||
#ifndef HAVE_SSE3
|
||||
#ifndef HAVE_SSE2
|
||||
#ifndef HAVE_SSE
|
||||
#if !HAVE_SSE4_1
|
||||
#if !HAVE_SSE3
|
||||
#if !HAVE_SSE2
|
||||
#if !HAVE_SSE
|
||||
ui->enableSSECheckBox->setVisible(false);
|
||||
#endif /* !SSE */
|
||||
ui->enableSSE2CheckBox->setVisible(false);
|
||||
|
|
@ -321,10 +339,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}
|
|||
|
||||
#else /* !Neon */
|
||||
|
||||
#ifndef HAVE_SSE4_1
|
||||
#ifndef HAVE_SSE3
|
||||
#ifndef HAVE_SSE2
|
||||
#ifndef HAVE_SSE
|
||||
#if !HAVE_SSE4_1
|
||||
#if !HAVE_SSE3
|
||||
#if !HAVE_SSE2
|
||||
#if !HAVE_SSE
|
||||
ui->enableNeonCheckBox->move(ui->enableNeonCheckBox->x(), ui->enableNeonCheckBox->y() - 30);
|
||||
ui->enableSSECheckBox->setVisible(false);
|
||||
#endif /* !SSE */
|
||||
|
|
@ -337,7 +355,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow{parent}
|
|||
|
||||
#endif
|
||||
|
||||
#ifndef ALSOFT_EAX
|
||||
#if !ALSOFT_EAX
|
||||
ui->enableEaxCheck->setChecked(Qt::Unchecked);
|
||||
ui->enableEaxCheck->setEnabled(false);
|
||||
ui->enableEaxCheck->setVisible(false);
|
||||
|
|
@ -662,14 +680,16 @@ void MainWindow::loadConfig(const QString &fname)
|
|||
ui->srcSendLineEdit->clear();
|
||||
ui->srcSendLineEdit->insert(settings.value(QStringLiteral("sends")).toString());
|
||||
|
||||
QString resampler = settings.value(QStringLiteral("resampler")).toString().trimmed();
|
||||
ui->resamplerSlider->setValue(2);
|
||||
ui->resamplerLabel->setText(std::data(resamplerList[2].name));
|
||||
/* "Cubic" is an alias for the 4-point gaussian resampler. The "sinc4" and
|
||||
auto resampler = settings.value(QStringLiteral("resampler")).toString().trimmed();
|
||||
static constexpr auto defaultResamplerIndex = GetDefaultIndex(resamplerList);
|
||||
ui->resamplerSlider->setValue(defaultResamplerIndex);
|
||||
ui->resamplerLabel->setText(std::data(resamplerList[defaultResamplerIndex].name));
|
||||
/* "Cubic" is an alias for the 4-point spline resampler. The "sinc4" and
|
||||
* "sinc8" resamplers are unsupported, use "gaussian" as a fallback.
|
||||
*/
|
||||
if(resampler == QLatin1String{"cubic"} || resampler == QLatin1String{"sinc4"}
|
||||
|| resampler == QLatin1String{"sinc8"})
|
||||
if(resampler == QLatin1String{"cubic"})
|
||||
resampler = QStringLiteral("spline");
|
||||
else if(resampler == QLatin1String{"sinc4"} || resampler == QLatin1String{"sinc8"})
|
||||
resampler = QStringLiteral("gaussian");
|
||||
/* The "bsinc" resampler name is an alias for "bsinc12". */
|
||||
else if(resampler == QLatin1String{"bsinc"})
|
||||
|
|
@ -762,9 +782,10 @@ void MainWindow::loadConfig(const QString &fname)
|
|||
ui->enableSSE41CheckBox->setChecked(!disabledCpuExts.contains(QStringLiteral("sse4.1"), Qt::CaseInsensitive));
|
||||
ui->enableNeonCheckBox->setChecked(!disabledCpuExts.contains(QStringLiteral("neon"), Qt::CaseInsensitive));
|
||||
|
||||
QString hrtfmode{settings.value(QStringLiteral("hrtf-mode")).toString().trimmed()};
|
||||
ui->hrtfmodeSlider->setValue(2);
|
||||
ui->hrtfmodeLabel->setText(std::data(hrtfModeList[3].name));
|
||||
auto hrtfmode = settings.value(QStringLiteral("hrtf-mode")).toString().trimmed();
|
||||
static constexpr auto defaultHrtfModeIndex = GetDefaultIndex(hrtfModeList);
|
||||
ui->hrtfmodeSlider->setValue(defaultHrtfModeIndex);
|
||||
ui->hrtfmodeLabel->setText(std::data(hrtfModeList[defaultHrtfModeIndex].name));
|
||||
/* The "basic" mode name is no longer supported. Use "ambi2" instead. */
|
||||
if(hrtfmode == QLatin1String{"basic"})
|
||||
hrtfmode = QStringLiteral("ambi2");
|
||||
|
|
@ -1192,11 +1213,7 @@ void MainWindow::updatePeriodSizeSlider()
|
|||
{
|
||||
int pos = ui->periodSizeEdit->text().toInt();
|
||||
if(pos >= 64)
|
||||
{
|
||||
if(pos > 8192)
|
||||
pos = 8192;
|
||||
ui->periodSizeSlider->setSliderPosition(pos);
|
||||
}
|
||||
ui->periodSizeSlider->setSliderPosition(std::min(pos, 8192));
|
||||
enableApplyButton();
|
||||
}
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -32,7 +32,6 @@
|
|||
#include <future>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <numeric>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
|
@ -40,8 +39,8 @@
|
|||
#include <vector>
|
||||
|
||||
#include "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "alnumeric.h"
|
||||
#include "fmt/core.h"
|
||||
#include "makemhr.h"
|
||||
#include "polyphase_resampler.h"
|
||||
#include "sofa-support.h"
|
||||
|
|
@ -62,12 +61,12 @@ using uint = unsigned int;
|
|||
*/
|
||||
auto PrepareLayout(const al::span<const float> xyzs, HrirDataT *hData) -> bool
|
||||
{
|
||||
fprintf(stdout, "Detecting compatible layout...\n");
|
||||
fmt::println("Detecting compatible layout...");
|
||||
|
||||
auto fds = GetCompatibleLayout(xyzs);
|
||||
if(fds.size() > MAX_FD_COUNT)
|
||||
{
|
||||
fprintf(stdout, "Incompatible layout (inumerable radii).\n");
|
||||
fmt::println("Incompatible layout (inumerable radii).");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +91,7 @@ auto PrepareLayout(const al::span<const float> xyzs, HrirDataT *hData) -> bool
|
|||
|
||||
++fi;
|
||||
}
|
||||
fprintf(stdout, "Using %u of %zu IRs.\n", ir_total, xyzs.size()/3);
|
||||
fmt::println("Using {} of {} IRs.", ir_total, xyzs.size()/3);
|
||||
const auto azs = al::span{azCounts}.first<MAX_FD_COUNT>();
|
||||
return PrepareHrirData(al::span{distances}.first(fi), evCounts, azs, hData);
|
||||
}
|
||||
|
|
@ -109,7 +108,7 @@ float GetSampleRate(MYSOFA_HRTF *sofaHrtf)
|
|||
{
|
||||
if(srate_dim)
|
||||
{
|
||||
fprintf(stderr, "Duplicate SampleRate.DIMENSION_LIST\n");
|
||||
fmt::println(stderr, "Duplicate SampleRate.DIMENSION_LIST");
|
||||
return 0.0f;
|
||||
}
|
||||
srate_dim = srate_attrs->value;
|
||||
|
|
@ -118,42 +117,42 @@ float GetSampleRate(MYSOFA_HRTF *sofaHrtf)
|
|||
{
|
||||
if(srate_units)
|
||||
{
|
||||
fprintf(stderr, "Duplicate SampleRate.Units\n");
|
||||
fmt::println(stderr, "Duplicate SampleRate.Units");
|
||||
return 0.0f;
|
||||
}
|
||||
srate_units = srate_attrs->value;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unexpected sample rate attribute: %s = %s\n", srate_attrs->name,
|
||||
fmt::println(stderr, "Unexpected sample rate attribute: {} = {}", srate_attrs->name,
|
||||
srate_attrs->value);
|
||||
srate_attrs = srate_attrs->next;
|
||||
}
|
||||
if(!srate_dim)
|
||||
{
|
||||
fprintf(stderr, "Missing sample rate dimensions\n");
|
||||
fmt::println(stderr, "Missing sample rate dimensions");
|
||||
return 0.0f;
|
||||
}
|
||||
if(srate_dim != "I"sv)
|
||||
{
|
||||
fprintf(stderr, "Unsupported sample rate dimensions: %s\n", srate_dim);
|
||||
fmt::println(stderr, "Unsupported sample rate dimensions: {}", srate_dim);
|
||||
return 0.0f;
|
||||
}
|
||||
if(!srate_units)
|
||||
{
|
||||
fprintf(stderr, "Missing sample rate unit type\n");
|
||||
fmt::println(stderr, "Missing sample rate unit type");
|
||||
return 0.0f;
|
||||
}
|
||||
if(srate_units != "hertz"sv)
|
||||
{
|
||||
fprintf(stderr, "Unsupported sample rate unit type: %s\n", srate_units);
|
||||
fmt::println(stderr, "Unsupported sample rate unit type: {}", srate_units);
|
||||
return 0.0f;
|
||||
}
|
||||
/* I dimensions guarantees 1 element, so just extract it. */
|
||||
const auto values = al::span{srate_array->values, sofaHrtf->I};
|
||||
if(values[0] < float{MIN_RATE} || values[0] > float{MAX_RATE})
|
||||
{
|
||||
fprintf(stderr, "Sample rate out of range: %f (expected %u to %u)", values[0], MIN_RATE,
|
||||
MAX_RATE);
|
||||
fmt::println(stderr, "Sample rate out of range: {:f} (expected {} to {})", values[0],
|
||||
MIN_RATE, MAX_RATE);
|
||||
return 0.0f;
|
||||
}
|
||||
return values[0];
|
||||
|
|
@ -175,19 +174,19 @@ auto PrepareDelay(MYSOFA_HRTF *sofaHrtf) -> std::optional<DelayType>
|
|||
{
|
||||
if(delay_dim)
|
||||
{
|
||||
fprintf(stderr, "Duplicate Delay.DIMENSION_LIST\n");
|
||||
fmt::println(stderr, "Duplicate Delay.DIMENSION_LIST");
|
||||
return std::nullopt;
|
||||
}
|
||||
delay_dim = delay_attrs->value;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unexpected delay attribute: %s = %s\n", delay_attrs->name,
|
||||
fmt::println(stderr, "Unexpected delay attribute: {} = {}", delay_attrs->name,
|
||||
delay_attrs->value ? delay_attrs->value : "<null>");
|
||||
delay_attrs = delay_attrs->next;
|
||||
}
|
||||
if(!delay_dim)
|
||||
{
|
||||
fprintf(stderr, "Missing delay dimensions\n");
|
||||
fmt::println(stderr, "Missing delay dimensions");
|
||||
return DelayType::None;
|
||||
}
|
||||
if(delay_dim == "I,R"sv)
|
||||
|
|
@ -195,7 +194,7 @@ auto PrepareDelay(MYSOFA_HRTF *sofaHrtf) -> std::optional<DelayType>
|
|||
if(delay_dim == "M,R"sv)
|
||||
return DelayType::M_R;
|
||||
|
||||
fprintf(stderr, "Unsupported delay dimensions: %s\n", delay_dim);
|
||||
fmt::println(stderr, "Unsupported delay dimensions: {}", delay_dim);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
|
|
@ -210,24 +209,24 @@ bool CheckIrData(MYSOFA_HRTF *sofaHrtf)
|
|||
{
|
||||
if(ir_dim)
|
||||
{
|
||||
fprintf(stderr, "Duplicate IR.DIMENSION_LIST\n");
|
||||
fmt::println(stderr, "Duplicate IR.DIMENSION_LIST");
|
||||
return false;
|
||||
}
|
||||
ir_dim = ir_attrs->value;
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "Unexpected IR attribute: %s = %s\n", ir_attrs->name,
|
||||
fmt::println(stderr, "Unexpected IR attribute: {} = {}", ir_attrs->name,
|
||||
ir_attrs->value ? ir_attrs->value : "<null>");
|
||||
ir_attrs = ir_attrs->next;
|
||||
}
|
||||
if(!ir_dim)
|
||||
{
|
||||
fprintf(stderr, "Missing IR dimensions\n");
|
||||
fmt::println(stderr, "Missing IR dimensions");
|
||||
return false;
|
||||
}
|
||||
if(ir_dim != "M,R,N"sv)
|
||||
{
|
||||
fprintf(stderr, "Unsupported IR dimensions: %s\n", ir_dim);
|
||||
fmt::println(stderr, "Unsupported IR dimensions: {}", ir_dim);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
@ -315,7 +314,7 @@ bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData, const DelayType dela
|
|||
HrirAzT &azd = field->mEvs[ei].mAzs[ai];
|
||||
if(!azd.mIrs[0].empty())
|
||||
{
|
||||
fprintf(stderr, "\nMultiple measurements near [ a=%f, e=%f, r=%f ].\n",
|
||||
fmt::println(stderr, "\nMultiple measurements near [ a={:f}, e={:f}, r={:f} ].",
|
||||
aer[0], aer[1], aer[2]);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -367,10 +366,10 @@ bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData, const DelayType dela
|
|||
auto load_future = std::async(std::launch::async, load_proc);
|
||||
do {
|
||||
load_status = load_future.wait_for(std::chrono::milliseconds{50});
|
||||
printf("\rLoading HRIRs... %u of %u", loaded_count.load(), sofaHrtf->M);
|
||||
fmt::print("\rLoading HRIRs... {} of {}", loaded_count.load(), sofaHrtf->M);
|
||||
fflush(stdout);
|
||||
} while(load_status != std::future_status::ready);
|
||||
fputc('\n', stdout);
|
||||
fmt::println("");
|
||||
return load_future.get();
|
||||
}
|
||||
|
||||
|
|
@ -382,10 +381,13 @@ bool LoadResponses(MYSOFA_HRTF *sofaHrtf, HrirDataT *hData, const DelayType dela
|
|||
struct MagCalculator {
|
||||
const uint mFftSize{};
|
||||
const uint mIrPoints{};
|
||||
std::vector<al::span<double>> mIrs{};
|
||||
std::vector<al::span<double>> mIrs;
|
||||
std::atomic<size_t> mCurrent{};
|
||||
std::atomic<size_t> mDone{};
|
||||
|
||||
MagCalculator(const uint fftsize, const uint irpoints) : mFftSize{fftsize}, mIrPoints{irpoints}
|
||||
{ }
|
||||
|
||||
void Worker()
|
||||
{
|
||||
auto htemp = std::vector<complex_d>(mFftSize);
|
||||
|
|
@ -422,28 +424,27 @@ bool LoadSofaFile(const std::string_view filename, const uint numThreads, const
|
|||
MySofaHrtfPtr sofaHrtf{mysofa_load(std::string{filename}.c_str(), &err)};
|
||||
if(!sofaHrtf)
|
||||
{
|
||||
fprintf(stdout, "Error: Could not load %.*s: %s\n", al::sizei(filename), filename.data(),
|
||||
SofaErrorStr(err));
|
||||
fmt::println("Error: Could not load {}: {} ({})", filename, SofaErrorStr(err), err);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* NOTE: Some valid SOFA files are failing this check. */
|
||||
err = mysofa_check(sofaHrtf.get());
|
||||
if(err != MYSOFA_OK)
|
||||
fprintf(stderr, "Warning: Supposedly malformed source file '%.*s' (%s).\n",
|
||||
al::sizei(filename), filename.data(), SofaErrorStr(err));
|
||||
fmt::println(stderr, "Warning: Supposedly malformed source file '{}': {} ({})", filename,
|
||||
SofaErrorStr(err), err);
|
||||
|
||||
mysofa_tocartesian(sofaHrtf.get());
|
||||
|
||||
/* Make sure emitter and receiver counts are sane. */
|
||||
if(sofaHrtf->E != 1)
|
||||
{
|
||||
fprintf(stderr, "%u emitters not supported\n", sofaHrtf->E);
|
||||
fmt::println(stderr, "{} emitters not supported", sofaHrtf->E);
|
||||
return false;
|
||||
}
|
||||
if(sofaHrtf->R > 2 || sofaHrtf->R < 1)
|
||||
{
|
||||
fprintf(stderr, "%u receivers not supported\n", sofaHrtf->R);
|
||||
fmt::println(stderr, "{} receivers not supported", sofaHrtf->R);
|
||||
return false;
|
||||
}
|
||||
/* Assume R=2 is a stereo measurement, and R=1 is mono left-ear-only. */
|
||||
|
|
@ -455,12 +456,14 @@ bool LoadSofaFile(const std::string_view filename, const uint numThreads, const
|
|||
/* Check and set the FFT and IR size. */
|
||||
if(sofaHrtf->N > fftSize)
|
||||
{
|
||||
fprintf(stderr, "Sample points exceeds the FFT size.\n");
|
||||
fmt::println(stderr, "Sample points exceeds the FFT size ({} > {}).", sofaHrtf->N,
|
||||
fftSize);
|
||||
return false;
|
||||
}
|
||||
if(sofaHrtf->N < truncSize)
|
||||
{
|
||||
fprintf(stderr, "Sample points is below the truncation size.\n");
|
||||
fmt::println(stderr, "Sample points is below the truncation size ({} < {}).", sofaHrtf->N,
|
||||
truncSize);
|
||||
return false;
|
||||
}
|
||||
hData->mIrPoints = sofaHrtf->N;
|
||||
|
|
@ -502,7 +505,7 @@ bool LoadSofaFile(const std::string_view filename, const uint numThreads, const
|
|||
}
|
||||
if(ei >= hData->mFds[fi].mEvs.size())
|
||||
{
|
||||
fprintf(stderr, "Missing source references [ %d, *, * ].\n", fi);
|
||||
fmt::println(stderr, "Missing source references [ {}, *, * ].", fi);
|
||||
return false;
|
||||
}
|
||||
hData->mFds[fi].mEvStart = ei;
|
||||
|
|
@ -513,7 +516,7 @@ bool LoadSofaFile(const std::string_view filename, const uint numThreads, const
|
|||
HrirAzT &azd = hData->mFds[fi].mEvs[ei].mAzs[ai];
|
||||
if(azd.mIrs[0].empty())
|
||||
{
|
||||
fprintf(stderr, "Missing source reference [ %d, %d, %d ].\n", fi, ei, ai);
|
||||
fmt::println(stderr, "Missing source reference [ {}, {}, {} ].", fi, ei, ai);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -572,10 +575,10 @@ bool LoadSofaFile(const std::string_view filename, const uint numThreads, const
|
|||
auto load_future = std::async(std::launch::async, onset_proc);
|
||||
do {
|
||||
load_status = load_future.wait_for(std::chrono::milliseconds{50});
|
||||
printf("\rCalculating HRIR onsets... %zu of %zu", hrir_done.load(), hrir_total);
|
||||
fmt::print("\rCalculating HRIR onsets... {} of {}", hrir_done.load(), hrir_total);
|
||||
fflush(stdout);
|
||||
} while(load_status != std::future_status::ready);
|
||||
fputc('\n', stdout);
|
||||
fmt::println("");
|
||||
if(!load_future.get())
|
||||
return false;
|
||||
|
||||
|
|
@ -595,16 +598,16 @@ bool LoadSofaFile(const std::string_view filename, const uint numThreads, const
|
|||
std::vector<std::thread> thrds;
|
||||
thrds.reserve(numThreads);
|
||||
for(size_t i{0};i < numThreads;++i)
|
||||
thrds.emplace_back(std::mem_fn(&MagCalculator::Worker), &calculator);
|
||||
thrds.emplace_back(&MagCalculator::Worker, &calculator);
|
||||
size_t count;
|
||||
do {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{50});
|
||||
count = calculator.mDone.load();
|
||||
|
||||
printf("\rCalculating HRIR magnitudes... %zu of %zu", count, calculator.mIrs.size());
|
||||
fmt::print("\rCalculating HRIR magnitudes... {} of {}", count, calculator.mIrs.size());
|
||||
fflush(stdout);
|
||||
} while(count != calculator.mIrs.size());
|
||||
fputc('\n', stdout);
|
||||
fmt::println("");
|
||||
|
||||
for(auto &thrd : thrds)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
|
|
@ -82,7 +81,6 @@
|
|||
#include <numeric>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "alcomplex.h"
|
||||
|
|
@ -90,6 +88,8 @@
|
|||
#include "alnumeric.h"
|
||||
#include "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "filesystem.h"
|
||||
#include "fmt/core.h"
|
||||
#include "loaddef.h"
|
||||
#include "loadsofa.h"
|
||||
|
||||
|
|
@ -283,8 +283,7 @@ auto WriteAscii(const std::string_view out, std::ostream &ostream, const std::st
|
|||
{
|
||||
if(!ostream.write(out.data(), std::streamsize(out.size())) || ostream.bad())
|
||||
{
|
||||
fprintf(stderr, "\nError: Bad write to file '%.*s'.\n", al::sizei(filename),
|
||||
filename.data());
|
||||
fmt::println(stderr, "\nError: Bad write to file '{}'.", filename);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
|
@ -301,8 +300,7 @@ auto WriteBin4(const uint bytes, const uint32_t in, std::ostream &ostream,
|
|||
|
||||
if(!ostream.write(out.data(), std::streamsize(bytes)) || ostream.bad())
|
||||
{
|
||||
fprintf(stderr, "\nError: Bad write to file '%.*s'.\n", al::sizei(filename),
|
||||
filename.data());
|
||||
fmt::println(stderr, "\nError: Bad write to file '{}'.", filename);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
|
@ -315,11 +313,10 @@ auto StoreMhr(const HrirDataT *hData, const std::string_view filename) -> bool
|
|||
const uint n{hData->mIrPoints};
|
||||
uint dither_seed{22222};
|
||||
|
||||
std::ofstream ostream{std::filesystem::u8path(filename)};
|
||||
auto ostream = fs::ofstream{fs::u8path(filename), std::ios::binary};
|
||||
if(!ostream.is_open())
|
||||
{
|
||||
fprintf(stderr, "\nError: Could not open MHR file '%.*s'.\n", al::sizei(filename),
|
||||
filename.data());
|
||||
fmt::println(stderr, "\nError: Could not open MHR file '{}'.", filename);
|
||||
return false;
|
||||
}
|
||||
if(!WriteAscii(GetMHRMarker(), ostream, filename))
|
||||
|
|
@ -913,7 +910,7 @@ void ReconstructHrirs(const HrirDataT *hData, const uint numThreads)
|
|||
std::vector<std::thread> thrds;
|
||||
thrds.reserve(numThreads);
|
||||
for(size_t i{0};i < numThreads;++i)
|
||||
thrds.emplace_back(std::mem_fn(&HrirReconstructor::Worker), &reconstructor);
|
||||
thrds.emplace_back(&HrirReconstructor::Worker, &reconstructor);
|
||||
|
||||
/* Keep track of the number of IRs done, periodically reporting it. */
|
||||
size_t count;
|
||||
|
|
@ -923,10 +920,10 @@ void ReconstructHrirs(const HrirDataT *hData, const uint numThreads)
|
|||
count = reconstructor.mDone.load();
|
||||
size_t pcdone{count * 100 / reconstructor.mIrs.size()};
|
||||
|
||||
printf("\r%3zu%% done (%zu of %zu)", pcdone, count, reconstructor.mIrs.size());
|
||||
fmt::print("\r{:3}% done ({} of {})", pcdone, count, reconstructor.mIrs.size());
|
||||
fflush(stdout);
|
||||
} while(count < reconstructor.mIrs.size());
|
||||
fputc('\n', stdout);
|
||||
fmt::println("");
|
||||
|
||||
for(auto &thrd : thrds)
|
||||
{
|
||||
|
|
@ -1076,7 +1073,7 @@ void CalculateHrtds(const HeadModelT model, const double radius, HrirDataT *hDat
|
|||
}
|
||||
if(maxHrtd > MaxHrtd)
|
||||
{
|
||||
fprintf(stdout, " Scaling for max delay of %f samples to %f\n...\n", maxHrtd, MaxHrtd);
|
||||
fmt::println(" Scaling for max delay of {:f} samples to {:f}\n...", maxHrtd, MaxHrtd);
|
||||
const double scale{MaxHrtd / maxHrtd};
|
||||
for(auto &field : hData->mFds)
|
||||
{
|
||||
|
|
@ -1158,22 +1155,20 @@ bool ProcessDefinition(std::string_view inName, const uint outRate, const Channe
|
|||
{
|
||||
HrirDataT hData;
|
||||
|
||||
fprintf(stdout, "Using %u thread%s.\n", numThreads, (numThreads==1)?"":"s");
|
||||
fmt::println("Using {} thread{}.", numThreads, (numThreads==1)?"":"s");
|
||||
if(inName.empty() || inName == "-"sv)
|
||||
{
|
||||
inName = "stdin"sv;
|
||||
fprintf(stdout, "Reading HRIR definition from %.*s...\n", al::sizei(inName),
|
||||
inName.data());
|
||||
fmt::println("Reading HRIR definition from {}...", inName);
|
||||
if(!LoadDefInput(std::cin, {}, inName, fftSize, truncSize, outRate, chanMode, &hData))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto input = std::make_unique<std::ifstream>(std::filesystem::u8path(inName));
|
||||
auto input = std::make_unique<fs::ifstream>(fs::u8path(inName));
|
||||
if(!input->is_open())
|
||||
{
|
||||
fprintf(stderr, "Error: Could not open input file '%.*s'\n", al::sizei(inName),
|
||||
inName.data());
|
||||
fmt::println(stderr, "Error: Could not open input file '{}'", inName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1181,8 +1176,7 @@ bool ProcessDefinition(std::string_view inName, const uint outRate, const Channe
|
|||
input->read(startbytes.data(), startbytes.size());
|
||||
if(input->gcount() != startbytes.size() || !input->good())
|
||||
{
|
||||
fprintf(stderr, "Error: Could not read input file '%.*s'\n", al::sizei(inName),
|
||||
inName.data());
|
||||
fmt::println(stderr, "Error: Could not read input file '{}'", inName);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1190,15 +1184,13 @@ bool ProcessDefinition(std::string_view inName, const uint outRate, const Channe
|
|||
&& startbytes[3] == 'F')
|
||||
{
|
||||
input = nullptr;
|
||||
fprintf(stdout, "Reading HRTF data from %.*s...\n", al::sizei(inName),
|
||||
inName.data());
|
||||
fmt::println("Reading HRTF data from {}...", inName);
|
||||
if(!LoadSofaFile(inName, numThreads, fftSize, truncSize, outRate, chanMode, &hData))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stdout, "Reading HRIR definition from %.*s...\n", al::sizei(inName),
|
||||
inName.data());
|
||||
fmt::println("Reading HRIR definition from {}...", inName);
|
||||
if(!LoadDefInput(*input, startbytes, inName, fftSize, truncSize, outRate, chanMode,
|
||||
&hData))
|
||||
return false;
|
||||
|
|
@ -1213,69 +1205,69 @@ bool ProcessDefinition(std::string_view inName, const uint outRate, const Channe
|
|||
|
||||
if(hData.mFds.size() > 1)
|
||||
{
|
||||
fprintf(stdout, "Balancing field magnitudes...\n");
|
||||
fmt::println("Balancing field magnitudes...");
|
||||
BalanceFieldMagnitudes(&hData, c, m);
|
||||
}
|
||||
fprintf(stdout, "Calculating diffuse-field average...\n");
|
||||
fmt::println("Calculating diffuse-field average...");
|
||||
CalculateDiffuseFieldAverage(&hData, c, m, surface, limit, dfa);
|
||||
fprintf(stdout, "Performing diffuse-field equalization...\n");
|
||||
fmt::println("Performing diffuse-field equalization...");
|
||||
DiffuseFieldEqualize(c, m, dfa, &hData);
|
||||
}
|
||||
if(hData.mFds.size() > 1)
|
||||
{
|
||||
fprintf(stdout, "Sorting %zu fields...\n", hData.mFds.size());
|
||||
fmt::println("Sorting {} fields...", hData.mFds.size());
|
||||
std::sort(hData.mFds.begin(), hData.mFds.end(),
|
||||
[](const HrirFdT &lhs, const HrirFdT &rhs) noexcept
|
||||
{ return lhs.mDistance < rhs.mDistance; });
|
||||
if(farfield)
|
||||
{
|
||||
fprintf(stdout, "Clearing %zu near field%s...\n", hData.mFds.size()-1,
|
||||
fmt::println("Clearing {} near field{}...", hData.mFds.size()-1,
|
||||
(hData.mFds.size()-1 != 1) ? "s" : "");
|
||||
hData.mFds.erase(hData.mFds.cbegin(), hData.mFds.cend()-1);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "Synthesizing missing elevations...\n");
|
||||
fmt::println("Synthesizing missing elevations...");
|
||||
if(model == HM_Dataset)
|
||||
SynthesizeOnsets(&hData);
|
||||
SynthesizeHrirs(&hData);
|
||||
fprintf(stdout, "Performing minimum phase reconstruction...\n");
|
||||
fmt::println("Performing minimum phase reconstruction...");
|
||||
ReconstructHrirs(&hData, numThreads);
|
||||
fprintf(stdout, "Truncating minimum-phase HRIRs...\n");
|
||||
fmt::println("Truncating minimum-phase HRIRs...");
|
||||
hData.mIrPoints = truncSize;
|
||||
fprintf(stdout, "Normalizing final HRIRs...\n");
|
||||
fmt::println("Normalizing final HRIRs...");
|
||||
NormalizeHrirs(&hData);
|
||||
fprintf(stdout, "Calculating impulse delays...\n");
|
||||
fmt::println("Calculating impulse delays...");
|
||||
CalculateHrtds(model, (radius > DefaultCustomRadius) ? radius : hData.mRadius, &hData);
|
||||
|
||||
const auto rateStr = std::to_string(hData.mIrRate);
|
||||
const auto expName = StrSubst(outName, "%r"sv, rateStr);
|
||||
fprintf(stdout, "Creating MHR data set %s...\n", expName.c_str());
|
||||
fmt::println("Creating MHR data set {}...", expName);
|
||||
return StoreMhr(&hData, expName);
|
||||
}
|
||||
|
||||
void PrintHelp(const std::string_view argv0, FILE *ofile)
|
||||
{
|
||||
fprintf(ofile, "Usage: %.*s [<option>...]\n\n", al::sizei(argv0), argv0.data());
|
||||
fprintf(ofile, "Options:\n");
|
||||
fprintf(ofile, " -r <rate> Change the data set sample rate to the specified value and\n");
|
||||
fprintf(ofile, " resample the HRIRs accordingly.\n");
|
||||
fprintf(ofile, " -m Change the data set to mono, mirroring the left ear for the\n");
|
||||
fprintf(ofile, " right ear.\n");
|
||||
fprintf(ofile, " -a Change the data set to single field, using the farthest field.\n");
|
||||
fprintf(ofile, " -j <threads> Number of threads used to process HRIRs (default: 2).\n");
|
||||
fprintf(ofile, " -f <points> Override the FFT window size (default: %u).\n", DefaultFftSize);
|
||||
fprintf(ofile, " -e {on|off} Toggle diffuse-field equalization (default: %s).\n", (DefaultEqualize ? "on" : "off"));
|
||||
fprintf(ofile, " -s {on|off} Toggle surface-weighted diffuse-field average (default: %s).\n", (DefaultSurface ? "on" : "off"));
|
||||
fprintf(ofile, " -l {<dB>|none} Specify a limit to the magnitude range of the diffuse-field\n");
|
||||
fprintf(ofile, " average (default: %.2f).\n", DefaultLimit);
|
||||
fprintf(ofile, " -w <points> Specify the size of the truncation window that's applied\n");
|
||||
fprintf(ofile, " after minimum-phase reconstruction (default: %u).\n", DefaultTruncSize);
|
||||
fprintf(ofile, " -d {dataset| Specify the model used for calculating the head-delay timing\n");
|
||||
fprintf(ofile, " sphere} values (default: %s).\n", ((HM_Default == HM_Dataset) ? "dataset" : "sphere"));
|
||||
fprintf(ofile, " -c <radius> Use a customized head radius measured to-ear in meters.\n");
|
||||
fprintf(ofile, " -i <filename> Specify an HRIR definition file to use (defaults to stdin).\n");
|
||||
fprintf(ofile, " -o <filename> Specify an output file. Use of '%%r' will be substituted with\n");
|
||||
fprintf(ofile, " the data set sample rate.\n");
|
||||
fmt::println(ofile, "Usage: {} [<option>...]\n", argv0);
|
||||
fmt::println(ofile, "Options:");
|
||||
fmt::println(ofile, " -r <rate> Change the data set sample rate to the specified value and");
|
||||
fmt::println(ofile, " resample the HRIRs accordingly.");
|
||||
fmt::println(ofile, " -m Change the data set to mono, mirroring the left ear for the");
|
||||
fmt::println(ofile, " right ear.");
|
||||
fmt::println(ofile, " -a Change the data set to single field, using the farthest field.");
|
||||
fmt::println(ofile, " -j <threads> Number of threads used to process HRIRs (default: 2).");
|
||||
fmt::println(ofile, " -f <points> Override the FFT window size (default: {}).", DefaultFftSize);
|
||||
fmt::println(ofile, " -e {{on|off}} Toggle diffuse-field equalization (default: {}).", (DefaultEqualize ? "on" : "off"));
|
||||
fmt::println(ofile, " -s {{on|off}} Toggle surface-weighted diffuse-field average (default: {}).", (DefaultSurface ? "on" : "off"));
|
||||
fmt::println(ofile, " -l {{<dB>|none}} Specify a limit to the magnitude range of the diffuse-field");
|
||||
fmt::println(ofile, " average (default: {:.2f}).", DefaultLimit);
|
||||
fmt::println(ofile, " -w <points> Specify the size of the truncation window that's applied");
|
||||
fmt::println(ofile, " after minimum-phase reconstruction (default: {}).", DefaultTruncSize);
|
||||
fmt::println(ofile, " -d {{dataset| Specify the model used for calculating the head-delay timing");
|
||||
fmt::println(ofile, " sphere}} values (default: {}).", ((HM_Default == HM_Dataset) ? "dataset" : "sphere"));
|
||||
fmt::println(ofile, " -c <radius> Use a customized head radius measured to-ear in meters.");
|
||||
fmt::println(ofile, " -i <filename> Specify an HRIR definition file to use (defaults to stdin).");
|
||||
fmt::println(ofile, " -o <filename> Specify an output file. Use of '%r' will be substituted with");
|
||||
fmt::println(ofile, " the data set sample rate.");
|
||||
}
|
||||
|
||||
// Standard command line dispatch.
|
||||
|
|
@ -1283,7 +1275,7 @@ int main(al::span<std::string_view> args)
|
|||
{
|
||||
if(args.size() < 2)
|
||||
{
|
||||
fprintf(stdout, "HRTF Processing and Composition Utility\n\n");
|
||||
fmt::println("HRTF Processing and Composition Utility\n");
|
||||
PrintHelp(args[0], stdout);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
|
@ -1325,7 +1317,7 @@ int main(al::span<std::string_view> args)
|
|||
|
||||
if(args[0][0] != '-' || args[0].size() == 1)
|
||||
{
|
||||
fprintf(stderr, "Invalid argument: %.*s\n", al::sizei(args[0]), args[0].data());
|
||||
fmt::println(stderr, "Invalid argument: {}", args[0]);
|
||||
return -1;
|
||||
}
|
||||
++argplace;
|
||||
|
|
@ -1335,13 +1327,13 @@ int main(al::span<std::string_view> args)
|
|||
const auto listidx = optlist.find(nextopt);
|
||||
if(listidx >= optlist.size())
|
||||
{
|
||||
fprintf(stderr, "Unknown argument: -%c\n", nextopt);
|
||||
fmt::println(stderr, "Unknown argument: -{:c}", nextopt);
|
||||
return -1;
|
||||
}
|
||||
const bool needsarg{listidx+1 < optlist.size() && optlist[listidx+1] == ':'};
|
||||
if(needsarg && (argplace+1 < args[0].size() || args.size() < 2))
|
||||
{
|
||||
fprintf(stderr, "Missing parameter for argument: -%c\n", nextopt);
|
||||
fmt::println(stderr, "Missing parameter for argument: -{:c}", nextopt);
|
||||
return -1;
|
||||
}
|
||||
if(++argplace == args[0].size())
|
||||
|
|
@ -1364,8 +1356,9 @@ int main(al::span<std::string_view> args)
|
|||
outRate = static_cast<uint>(std::stoul(std::string{optarg}, &endpos, 10));
|
||||
if(endpos != optarg.size() || outRate < MIN_RATE || outRate > MAX_RATE)
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected between %u to %u.\n",
|
||||
al::sizei(optarg), optarg.data(), opt, MIN_RATE, MAX_RATE);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected between {} to {}.",
|
||||
optarg, opt, MIN_RATE, MAX_RATE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1382,8 +1375,9 @@ int main(al::span<std::string_view> args)
|
|||
numThreads = static_cast<uint>(std::stoul(std::string{optarg}, &endpos, 10));
|
||||
if(endpos != optarg.size() || numThreads > 64)
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected between %u to %u.\n",
|
||||
al::sizei(optarg), optarg.data(), opt, 0, 64);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected between {} to {}.",
|
||||
optarg, opt, 0, 64);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(numThreads == 0)
|
||||
|
|
@ -1395,8 +1389,9 @@ int main(al::span<std::string_view> args)
|
|||
if(endpos != optarg.size() || (fftSize&(fftSize-1)) || fftSize < MinFftSize
|
||||
|| fftSize > MaxFftSize)
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected a power-of-two between %u to %u.\n",
|
||||
al::sizei(optarg), optarg.data(), opt, MinFftSize, MaxFftSize);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected a power-of-two between {} to {}.",
|
||||
optarg, opt, MinFftSize, MaxFftSize);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1408,8 +1403,9 @@ int main(al::span<std::string_view> args)
|
|||
equalize = false;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected on or off.\n",
|
||||
al::sizei(optarg), optarg.data(), opt);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected on or off.",
|
||||
optarg, opt);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1421,8 +1417,9 @@ int main(al::span<std::string_view> args)
|
|||
surface = false;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected on or off.\n",
|
||||
al::sizei(optarg), optarg.data(), opt);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected on or off.",
|
||||
optarg, opt);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1435,8 +1432,9 @@ int main(al::span<std::string_view> args)
|
|||
limit = std::stod(std::string{optarg}, &endpos);
|
||||
if(endpos != optarg.size() || limit < MinLimit || limit > MaxLimit)
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected between %.0f to %.0f.\n",
|
||||
al::sizei(optarg), optarg.data(), opt, MinLimit, MaxLimit);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected between {:.0f} to {:.0f}.",
|
||||
optarg, opt, MinLimit, MaxLimit);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
|
@ -1446,8 +1444,9 @@ int main(al::span<std::string_view> args)
|
|||
truncSize = static_cast<uint>(std::stoul(std::string{optarg}, &endpos, 10));
|
||||
if(endpos != optarg.size() || truncSize < MinTruncSize || truncSize > MaxTruncSize)
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected between %u to %u.\n",
|
||||
al::sizei(optarg), optarg.data(), opt, MinTruncSize, MaxTruncSize);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected between {} to {}.",
|
||||
optarg, opt, MinTruncSize, MaxTruncSize);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1459,8 +1458,9 @@ int main(al::span<std::string_view> args)
|
|||
model = HM_Sphere;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected dataset or sphere.\n",
|
||||
al::sizei(optarg), optarg.data(), opt);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected dataset or sphere.",
|
||||
optarg, opt);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1469,8 +1469,9 @@ int main(al::span<std::string_view> args)
|
|||
radius = std::stod(std::string{optarg}, &endpos);
|
||||
if(endpos != optarg.size() || radius < MinCustomRadius || radius > MaxCustomRadius)
|
||||
{
|
||||
fprintf(stderr, "\nError: Got unexpected value \"%.*s\" for option -%c, expected between %.2f to %.2f.\n",
|
||||
al::sizei(optarg), optarg.data(), opt, MinCustomRadius, MaxCustomRadius);
|
||||
fmt::println(stderr,
|
||||
"\nError: Got unexpected value \"{}\" for option -{:c}, expected between {:.2f} to {:.2f}.",
|
||||
optarg, opt, MinCustomRadius, MaxCustomRadius);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
|
|
@ -1496,7 +1497,7 @@ int main(al::span<std::string_view> args)
|
|||
const int ret{ProcessDefinition(inName, outRate, chanMode, farfield, numThreads, fftSize,
|
||||
equalize, surface, limit, truncSize, model, radius, outName)};
|
||||
if(!ret) return -1;
|
||||
fprintf(stdout, "Operation completed.\n");
|
||||
fmt::println("Operation completed.");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,43 +12,35 @@
|
|||
|
||||
|
||||
// The maximum path length used when processing filenames.
|
||||
enum { MAX_PATH_LEN = 256u };
|
||||
inline constexpr auto MAX_PATH_LEN = 256u;
|
||||
|
||||
// The limit to the number of 'distances' listed in the data set definition.
|
||||
// Must be less than 256
|
||||
enum { MAX_FD_COUNT = 16u };
|
||||
inline constexpr auto MAX_FD_COUNT = 16u;
|
||||
|
||||
// The limits to the number of 'elevations' listed in the data set definition.
|
||||
// Must be less than 256.
|
||||
enum {
|
||||
MIN_EV_COUNT = 5u,
|
||||
MAX_EV_COUNT = 181u
|
||||
};
|
||||
inline constexpr auto MIN_EV_COUNT = 5u;
|
||||
inline constexpr auto MAX_EV_COUNT = 181u;
|
||||
|
||||
// The limits for each of the 'azimuths' listed in the data set definition.
|
||||
// Must be less than 256.
|
||||
enum {
|
||||
MIN_AZ_COUNT = 1u,
|
||||
MAX_AZ_COUNT = 255u
|
||||
};
|
||||
inline constexpr auto MIN_AZ_COUNT = 1u;
|
||||
inline constexpr auto MAX_AZ_COUNT = 255u;
|
||||
|
||||
// The limits for the 'distance' from source to listener for each field in
|
||||
// the definition file.
|
||||
inline constexpr double MIN_DISTANCE{0.05};
|
||||
inline constexpr double MAX_DISTANCE{2.50};
|
||||
inline constexpr auto MIN_DISTANCE = 0.05;
|
||||
inline constexpr auto MAX_DISTANCE = 2.50;
|
||||
|
||||
// The limits for the sample 'rate' metric in the data set definition and for
|
||||
// resampling.
|
||||
enum {
|
||||
MIN_RATE = 32000u,
|
||||
MAX_RATE = 96000u
|
||||
};
|
||||
inline constexpr auto MIN_RATE = 32000u;
|
||||
inline constexpr auto MAX_RATE = 96000u;
|
||||
|
||||
// The limits for the HRIR 'points' metric in the data set definition.
|
||||
enum {
|
||||
MIN_POINTS = 16u,
|
||||
MAX_POINTS = 8192u
|
||||
};
|
||||
inline constexpr auto MIN_POINTS = 16u;
|
||||
inline constexpr auto MAX_POINTS = 8192u;
|
||||
|
||||
|
||||
using uint = unsigned int;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ static void printList(const char *list, char separator)
|
|||
|
||||
if(!list || *list == '\0')
|
||||
{
|
||||
fprintf(stdout, "\n%s!!! none !!!\n", indent);
|
||||
printf("\n%s!!! none !!!\n", indent);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ static void printList(const char *list, char separator)
|
|||
|
||||
if(len + col + 2 >= MaxWidth)
|
||||
{
|
||||
fprintf(stdout, "\n%s", indent);
|
||||
printf("\n%s", indent);
|
||||
col = strlen(indent);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@
|
|||
|
||||
#include "alnumeric.h"
|
||||
#include "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "fmt/core.h"
|
||||
|
||||
#include "sofa-support.h"
|
||||
|
||||
|
|
@ -39,28 +39,29 @@
|
|||
|
||||
namespace {
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
using uint = unsigned int;
|
||||
|
||||
void PrintSofaAttributes(const char *prefix, MYSOFA_ATTRIBUTE *attribute)
|
||||
void PrintSofaAttributes(const std::string_view prefix, MYSOFA_ATTRIBUTE *attribute)
|
||||
{
|
||||
while(attribute)
|
||||
{
|
||||
fprintf(stdout, "%s.%s: %s\n", prefix, attribute->name, attribute->value);
|
||||
fmt::println("{}.{}: {}", prefix, attribute->name, attribute->value);
|
||||
attribute = attribute->next;
|
||||
}
|
||||
}
|
||||
|
||||
void PrintSofaArray(const char *prefix, MYSOFA_ARRAY *array, bool showValues=true)
|
||||
void PrintSofaArray(const std::string_view prefix, MYSOFA_ARRAY *array, bool showValues=true)
|
||||
{
|
||||
PrintSofaAttributes(prefix, array->attributes);
|
||||
if(showValues)
|
||||
{
|
||||
const auto values = al::span{array->values, array->elements};
|
||||
for(size_t i{0u};i < values.size();++i)
|
||||
fprintf(stdout, "%s[%zu]: %.6f\n", prefix, i, values[i]);
|
||||
fmt::println("{}[{}]: {:.6f}", prefix, i, values[i]);
|
||||
}
|
||||
else
|
||||
fprintf(stdout, "%s[...]: <%u values suppressed>\n", prefix, array->elements);
|
||||
fmt::println("{}[...]: <{} values suppressed>", prefix, array->elements);
|
||||
}
|
||||
|
||||
/* Attempts to produce a compatible layout. Most data sets tend to be
|
||||
|
|
@ -71,12 +72,12 @@ void PrintSofaArray(const char *prefix, MYSOFA_ARRAY *array, bool showValues=tru
|
|||
*/
|
||||
void PrintCompatibleLayout(const al::span<const float> xyzs)
|
||||
{
|
||||
fputc('\n', stdout);
|
||||
fmt::println("");
|
||||
|
||||
auto fds = GetCompatibleLayout(xyzs);
|
||||
if(fds.empty())
|
||||
{
|
||||
fprintf(stdout, "No compatible field layouts in SOFA file.\n");
|
||||
fmt::println("No compatible field layouts in SOFA file.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -87,18 +88,18 @@ void PrintCompatibleLayout(const al::span<const float> xyzs)
|
|||
used_elems += fds[fi].mAzCounts[ei];
|
||||
}
|
||||
|
||||
fprintf(stdout, "Compatible Layout (%u of %zu measurements):\n\ndistance = %.3f", used_elems,
|
||||
fmt::print("Compatible Layout ({} of {} measurements):\n\ndistance = {:.3f}", used_elems,
|
||||
xyzs.size()/3, fds[0].mDistance);
|
||||
for(size_t fi{1u};fi < fds.size();fi++)
|
||||
fprintf(stdout, ", %.3f", fds[fi].mDistance);
|
||||
fmt::print(", {:.3f}", fds[fi].mDistance);
|
||||
|
||||
fprintf(stdout, "\nazimuths = ");
|
||||
fmt::print("\nazimuths = ");
|
||||
for(size_t fi{0u};fi < fds.size();++fi)
|
||||
{
|
||||
for(uint ei{0u};ei < fds[fi].mEvStart;++ei)
|
||||
fprintf(stdout, "%d%s", fds[fi].mAzCounts[fds[fi].mEvCount - 1 - ei], ", ");
|
||||
fmt::print("{}{}", fds[fi].mAzCounts[fds[fi].mEvCount - 1 - ei], ", ");
|
||||
for(uint ei{fds[fi].mEvStart};ei < fds[fi].mEvCount;++ei)
|
||||
fprintf(stdout, "%d%s", fds[fi].mAzCounts[ei],
|
||||
fmt::print("{}{}", fds[fi].mAzCounts[ei],
|
||||
(ei < (fds[fi].mEvCount - 1)) ? ", " :
|
||||
(fi < (fds.size() - 1)) ? ";\n " : "\n");
|
||||
}
|
||||
|
|
@ -111,7 +112,7 @@ void SofaInfo(const std::string &filename)
|
|||
MySofaHrtfPtr sofa{mysofa_load(filename.c_str(), &err)};
|
||||
if(!sofa)
|
||||
{
|
||||
fprintf(stdout, "Error: Could not load source file '%s' (%s).\n", filename.c_str(),
|
||||
fmt::println("Error: Could not load source file '{}' ({}).", filename,
|
||||
SofaErrorStr(err));
|
||||
return;
|
||||
}
|
||||
|
|
@ -119,21 +120,21 @@ void SofaInfo(const std::string &filename)
|
|||
/* NOTE: Some valid SOFA files are failing this check. */
|
||||
err = mysofa_check(sofa.get());
|
||||
if(err != MYSOFA_OK)
|
||||
fprintf(stdout, "Warning: Supposedly malformed source file '%s' (%s).\n", filename.c_str(),
|
||||
fmt::println("Warning: Supposedly malformed source file '{}' ({}).", filename,
|
||||
SofaErrorStr(err));
|
||||
|
||||
mysofa_tocartesian(sofa.get());
|
||||
|
||||
PrintSofaAttributes("Info", sofa->attributes);
|
||||
|
||||
fprintf(stdout, "Measurements: %u\n", sofa->M);
|
||||
fprintf(stdout, "Receivers: %u\n", sofa->R);
|
||||
fprintf(stdout, "Emitters: %u\n", sofa->E);
|
||||
fprintf(stdout, "Samples: %u\n", sofa->N);
|
||||
fmt::println("Measurements: {}", sofa->M);
|
||||
fmt::println("Receivers: {}", sofa->R);
|
||||
fmt::println("Emitters: {}", sofa->E);
|
||||
fmt::println("Samples: {}", sofa->N);
|
||||
|
||||
PrintSofaArray("SampleRate", &sofa->DataSamplingRate);
|
||||
PrintSofaArray("DataDelay", &sofa->DataDelay);
|
||||
PrintSofaArray("SourcePosition", &sofa->SourcePosition, false);
|
||||
PrintSofaArray("SampleRate"sv, &sofa->DataSamplingRate);
|
||||
PrintSofaArray("DataDelay"sv, &sofa->DataDelay);
|
||||
PrintSofaArray("SourcePosition"sv, &sofa->SourcePosition, false);
|
||||
|
||||
PrintCompatibleLayout(al::span{sofa->SourcePosition.values, sofa->M*3_uz});
|
||||
}
|
||||
|
|
@ -142,7 +143,7 @@ int main(al::span<std::string_view> args)
|
|||
{
|
||||
if(args.size() != 2)
|
||||
{
|
||||
fprintf(stdout, "Usage: %.*s <sofa-file>\n", al::sizei(args[0]), args[0].data());
|
||||
fmt::println("Usage: {} <sofa-file>", args[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "fmt/core.h"
|
||||
#include "mysofa.h"
|
||||
|
||||
|
||||
|
|
@ -213,14 +214,14 @@ auto GetCompatibleLayout(const al::span<const float> xyzs) -> std::vector<SofaFi
|
|||
if(step <= 0.0)
|
||||
{
|
||||
if(elevs.empty())
|
||||
fprintf(stdout, "No usable elevations on field distance %f.\n", dist);
|
||||
fmt::println("No usable elevations on field distance {:f}.", dist);
|
||||
else
|
||||
{
|
||||
fprintf(stdout, "Non-uniform elevations on field distance %.3f.\nGot: %+.2f", dist,
|
||||
fmt::print("Non-uniform elevations on field distance {:.3f}.\nGot: {:+.2f}", dist,
|
||||
elevs[0]);
|
||||
for(size_t ei{1u};ei < elevs.size();++ei)
|
||||
fprintf(stdout, ", %+.2f", elevs[ei]);
|
||||
fputc('\n', stdout);
|
||||
fmt::print(", {:+.2f}", elevs[ei]);
|
||||
fmt::println("");
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
|
@ -230,7 +231,7 @@ auto GetCompatibleLayout(const al::span<const float> xyzs) -> std::vector<SofaFi
|
|||
{
|
||||
if(!(elevs[ei] < 0.0))
|
||||
{
|
||||
fprintf(stdout, "Too many missing elevations on field distance %f.\n", dist);
|
||||
fmt::println("Too many missing elevations on field distance {:f}.", dist);
|
||||
return fds;
|
||||
}
|
||||
|
||||
|
|
@ -247,7 +248,7 @@ auto GetCompatibleLayout(const al::span<const float> xyzs) -> std::vector<SofaFi
|
|||
const auto evCount = static_cast<uint>(std::round(180.0 / step)) + 1;
|
||||
if(evCount < 5)
|
||||
{
|
||||
fprintf(stdout, "Too few uniform elevations on field distance %f.\n", dist);
|
||||
fmt::println("Too few uniform elevations on field distance {:f}.", dist);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -267,7 +268,7 @@ auto GetCompatibleLayout(const al::span<const float> xyzs) -> std::vector<SofaFi
|
|||
{
|
||||
if(azims.size() != 1)
|
||||
{
|
||||
fprintf(stdout, "Non-singular poles on field distance %f.\n", dist);
|
||||
fmt::println("Non-singular poles on field distance {:f}.", dist);
|
||||
return fds;
|
||||
}
|
||||
azCounts[ei] = 1;
|
||||
|
|
@ -277,7 +278,7 @@ auto GetCompatibleLayout(const al::span<const float> xyzs) -> std::vector<SofaFi
|
|||
step = GetUniformAzimStep(0.1, azims);
|
||||
if(step <= 0.0)
|
||||
{
|
||||
fprintf(stdout, "Non-uniform azimuths on elevation %f, field distance %f.\n",
|
||||
fmt::println("Non-uniform azimuths on elevation {:f}, field distance {:f}.",
|
||||
ev, dist);
|
||||
return fds;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
#include "almalloc.h"
|
||||
#include "alnumbers.h"
|
||||
#include "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "fmt/core.h"
|
||||
#include "vector.h"
|
||||
#include "opthelpers.h"
|
||||
#include "phase_shifter.h"
|
||||
|
|
@ -352,7 +352,7 @@ int main(al::span<std::string_view> args)
|
|||
{
|
||||
if(args.size() < 2 || args[1] == "-h" || args[1] == "--help")
|
||||
{
|
||||
printf("Usage: %.*s <[options] filename.wav...>\n\n"
|
||||
fmt::println("Usage: {} <[options] filename.wav...>\n\n"
|
||||
" Options:\n"
|
||||
" --general Use the general equations for 2-channel UHJ (default).\n"
|
||||
" --alternative Use the alternative equations for 2-channel UHJ.\n"
|
||||
|
|
@ -360,7 +360,7 @@ int main(al::span<std::string_view> args)
|
|||
"Note: When decoding 2-channel UHJ to an .amb file, the result should not use\n"
|
||||
"the normal B-Format shelf filters! Only 3- and 4-channel UHJ can accurately\n"
|
||||
"reconstruct the original B-Format signal.",
|
||||
al::sizei(args[0]), args[0].data());
|
||||
args[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -383,13 +383,12 @@ int main(al::span<std::string_view> args)
|
|||
SndFilePtr infile{sf_open(std::string{args[fidx]}.c_str(), SFM_READ, &ininfo)};
|
||||
if(!infile)
|
||||
{
|
||||
fprintf(stderr, "Failed to open %.*s\n", al::sizei(args[fidx]), args[fidx].data());
|
||||
fmt::println(stderr, "Failed to open {}", args[fidx]);
|
||||
continue;
|
||||
}
|
||||
if(sf_command(infile.get(), SFC_WAVEX_GET_AMBISONIC, nullptr, 0) == SF_AMBISONIC_B_FORMAT)
|
||||
{
|
||||
fprintf(stderr, "%.*s is already B-Format\n", al::sizei(args[fidx]),
|
||||
args[fidx].data());
|
||||
fmt::println(stderr, "{} is already B-Format", args[fidx]);
|
||||
continue;
|
||||
}
|
||||
uint outchans{};
|
||||
|
|
@ -399,12 +398,10 @@ int main(al::span<std::string_view> args)
|
|||
outchans = static_cast<uint>(ininfo.channels);
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%.*s is not a 2-, 3-, or 4-channel file\n", al::sizei(args[fidx]),
|
||||
args[fidx].data());
|
||||
fmt::println(stderr, "{} is not a 2-, 3-, or 4-channel file", args[fidx]);
|
||||
continue;
|
||||
}
|
||||
printf("Converting %.*s from %d-channel UHJ%s...\n", al::sizei(args[fidx]),
|
||||
args[fidx].data(), ininfo.channels,
|
||||
fmt::println("Converting {} from {}-channel UHJ%s...\n", args[fidx], ininfo.channels,
|
||||
(ininfo.channels == 2) ? use_general ? " (general)" : " (alternative)" : "");
|
||||
|
||||
std::string outname{args[fidx]};
|
||||
|
|
@ -419,7 +416,7 @@ int main(al::span<std::string_view> args)
|
|||
FilePtr outfile{fopen(outname.c_str(), "wb")};
|
||||
if(!outfile)
|
||||
{
|
||||
fprintf(stderr, "Failed to create %s\n", outname.c_str());
|
||||
fmt::println(stderr, "Failed to create {}", outname);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -456,8 +453,8 @@ int main(al::span<std::string_view> args)
|
|||
fwrite32le(0xFFFFFFFF, outfile.get()); // 'data' header len; filled in at close
|
||||
if(ferror(outfile.get()))
|
||||
{
|
||||
fprintf(stderr, "Error writing wave file header: %s (%d)\n",
|
||||
std::generic_category().message(errno).c_str(), errno);
|
||||
fmt::println(stderr, "Error writing wave file header: {} ({})",
|
||||
std::generic_category().message(errno), errno);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -511,8 +508,8 @@ int main(al::span<std::string_view> args)
|
|||
std::size_t wrote{fwrite(outmem.data(), sizeof(byte4)*outchans, got, outfile.get())};
|
||||
if(wrote < got)
|
||||
{
|
||||
fprintf(stderr, "Error writing wave data: %s (%d)\n",
|
||||
std::generic_category().message(errno).c_str(), errno);
|
||||
fmt::println(stderr, "Error writing wave data: {} ({})",
|
||||
std::generic_category().message(errno), errno);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -530,11 +527,11 @@ int main(al::span<std::string_view> args)
|
|||
++num_decoded;
|
||||
}
|
||||
if(num_decoded == 0)
|
||||
fprintf(stderr, "Failed to decode any input files\n");
|
||||
fmt::println(stderr, "Failed to decode any input files");
|
||||
else if(num_decoded < num_files)
|
||||
fprintf(stderr, "Decoded %zu of %zu files\n", num_decoded, num_files);
|
||||
fmt::println(stderr, "Decoded {} of {} files", num_decoded, num_files);
|
||||
else
|
||||
printf("Decoded %zu file%s\n", num_decoded, (num_decoded==1)?"":"s");
|
||||
fmt::println("Decoded {} file{}", num_decoded, (num_decoded==1)?"":"s");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
|
|
@ -38,7 +37,7 @@
|
|||
|
||||
#include "alnumbers.h"
|
||||
#include "alspan.h"
|
||||
#include "alstring.h"
|
||||
#include "fmt/core.h"
|
||||
#include "phase_shifter.h"
|
||||
#include "vector.h"
|
||||
|
||||
|
|
@ -49,6 +48,8 @@
|
|||
|
||||
namespace {
|
||||
|
||||
using namespace std::string_view_literals;
|
||||
|
||||
struct SndFileDeleter {
|
||||
void operator()(SNDFILE *sndfile) { sf_close(sndfile); }
|
||||
};
|
||||
|
|
@ -249,49 +250,63 @@ int main(al::span<std::string_view> args)
|
|||
{
|
||||
if(args.size() < 2 || args[1] == "-h" || args[1] == "--help")
|
||||
{
|
||||
printf("Usage: %.*s <infile...>\n\n", al::sizei(args[0]), args[0].data());
|
||||
fmt::println("Usage: {} <[options] infile...>\n\n"
|
||||
" Options:\n"
|
||||
" -bhj Encode 2-channel UHJ, aka \"BJH\" (default).\n"
|
||||
" -thj Encode 3-channel UHJ, aka \"TJH\".\n"
|
||||
" -phj Encode 4-channel UHJ, aka \"PJH\".\n"
|
||||
"\n"
|
||||
"3-channel UHJ supplements 2-channel UHJ with an extra channel that allows full\n"
|
||||
"reconstruction of first-order 2D ambisonics. 4-channel UHJ supplements 3-channel\n"
|
||||
"UHJ with an extra channel carrying height information, providing for full\n"
|
||||
"reconstruction of first-order 3D ambisonics.\n"
|
||||
"\n"
|
||||
"Note: The third and fourth channels should be ignored if they're not being\n"
|
||||
"decoded. Unlike the first two channels, they are not designed for undecoded\n"
|
||||
"playback, so the resulting files will not play correctly if this isn't handled.",
|
||||
args[0]);
|
||||
return 1;
|
||||
}
|
||||
args = args.subspan(1);
|
||||
|
||||
uint uhjchans{2};
|
||||
size_t num_files{0}, num_encoded{0};
|
||||
for(size_t fidx{1};fidx < args.size();++fidx)
|
||||
auto process_arg = [&uhjchans,&num_files,&num_encoded](std::string_view arg) -> void
|
||||
{
|
||||
if(args[fidx] == "-bhj")
|
||||
if(arg == "-bhj"sv)
|
||||
{
|
||||
uhjchans = 2;
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
if(args[fidx] == "-thj")
|
||||
if(arg == "-thj"sv)
|
||||
{
|
||||
uhjchans = 3;
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
if(args[fidx] == "-phj")
|
||||
if(arg == "-phj"sv)
|
||||
{
|
||||
uhjchans = 4;
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
++num_files;
|
||||
|
||||
std::string outname{args[fidx]};
|
||||
size_t lastslash{outname.find_last_of('/')};
|
||||
auto outname = std::string{arg};
|
||||
const auto lastslash = outname.rfind('/');
|
||||
if(lastslash != std::string::npos)
|
||||
outname.erase(0, lastslash+1);
|
||||
size_t extpos{outname.find_last_of('.')};
|
||||
const auto extpos = outname.rfind('.');
|
||||
if(extpos != std::string::npos)
|
||||
outname.resize(extpos);
|
||||
outname += ".uhj.flac";
|
||||
|
||||
SF_INFO ininfo{};
|
||||
SndFilePtr infile{sf_open(std::string{args[fidx]}.c_str(), SFM_READ, &ininfo)};
|
||||
SndFilePtr infile{sf_open(std::string{arg}.c_str(), SFM_READ, &ininfo)};
|
||||
if(!infile)
|
||||
{
|
||||
fprintf(stderr, "Failed to open %.*s\n", al::sizei(args[fidx]), args[fidx].data());
|
||||
continue;
|
||||
fmt::println(stderr, "Failed to open {}", arg);
|
||||
return;
|
||||
}
|
||||
printf("Converting %.*s to %s...\n", al::sizei(args[fidx]), args[fidx].data(),
|
||||
outname.c_str());
|
||||
fmt::println("Converting {} to {}...", arg, outname);
|
||||
|
||||
/* Work out the channel map, preferably using the actual channel map
|
||||
* from the file/format, but falling back to assuming WFX order.
|
||||
|
|
@ -365,27 +380,51 @@ int main(al::span<std::string_view> args)
|
|||
mapstr += std::to_string(idx);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, " ... %zu channels not supported (map: %s)\n", chanmap.size(),
|
||||
mapstr.c_str());
|
||||
continue;
|
||||
fmt::println(stderr, " ... {} channels not supported (map: {})", chanmap.size(),
|
||||
mapstr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(sf_command(infile.get(), SFC_WAVEX_GET_AMBISONIC, nullptr,
|
||||
0) == SF_AMBISONIC_B_FORMAT)
|
||||
{
|
||||
if(ininfo.channels == 4)
|
||||
{
|
||||
fmt::println(stderr, " ... detected FuMa 3D B-Format");
|
||||
chanmap[0] = SF_CHANNEL_MAP_AMBISONIC_B_W;
|
||||
chanmap[1] = SF_CHANNEL_MAP_AMBISONIC_B_X;
|
||||
chanmap[2] = SF_CHANNEL_MAP_AMBISONIC_B_Y;
|
||||
chanmap[3] = SF_CHANNEL_MAP_AMBISONIC_B_Z;
|
||||
}
|
||||
else if(ininfo.channels == 3)
|
||||
{
|
||||
fmt::println(stderr, " ... detected FuMa 2D B-Format");
|
||||
chanmap[0] = SF_CHANNEL_MAP_AMBISONIC_B_W;
|
||||
chanmap[1] = SF_CHANNEL_MAP_AMBISONIC_B_X;
|
||||
chanmap[2] = SF_CHANNEL_MAP_AMBISONIC_B_Y;
|
||||
}
|
||||
else
|
||||
{
|
||||
fmt::println(stderr, " ... unhandled {}-channel B-Format", ininfo.channels);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if(ininfo.channels == 1)
|
||||
{
|
||||
fprintf(stderr, " ... assuming front-center\n");
|
||||
fmt::println(stderr, " ... assuming front-center");
|
||||
spkrs = MonoMap;
|
||||
chanmap[0] = SF_CHANNEL_MAP_CENTER;
|
||||
}
|
||||
else if(ininfo.channels == 2)
|
||||
{
|
||||
fprintf(stderr, " ... assuming WFX order stereo\n");
|
||||
fmt::println(stderr, " ... assuming WFX order stereo");
|
||||
spkrs = StereoMap;
|
||||
chanmap[0] = SF_CHANNEL_MAP_LEFT;
|
||||
chanmap[1] = SF_CHANNEL_MAP_RIGHT;
|
||||
}
|
||||
else if(ininfo.channels == 6)
|
||||
{
|
||||
fprintf(stderr, " ... assuming WFX order 5.1\n");
|
||||
fmt::println(stderr, " ... assuming WFX order 5.1");
|
||||
spkrs = X51Map;
|
||||
chanmap[0] = SF_CHANNEL_MAP_LEFT;
|
||||
chanmap[1] = SF_CHANNEL_MAP_RIGHT;
|
||||
|
|
@ -396,7 +435,7 @@ int main(al::span<std::string_view> args)
|
|||
}
|
||||
else if(ininfo.channels == 8)
|
||||
{
|
||||
fprintf(stderr, " ... assuming WFX order 7.1\n");
|
||||
fmt::println(stderr, " ... assuming WFX order 7.1");
|
||||
spkrs = X71Map;
|
||||
chanmap[0] = SF_CHANNEL_MAP_LEFT;
|
||||
chanmap[1] = SF_CHANNEL_MAP_RIGHT;
|
||||
|
|
@ -409,8 +448,8 @@ int main(al::span<std::string_view> args)
|
|||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, " ... unmapped %d-channel audio not supported\n", ininfo.channels);
|
||||
continue;
|
||||
fmt::println(stderr, " ... unmapped {}-channel audio not supported", ininfo.channels);
|
||||
return;
|
||||
}
|
||||
|
||||
SF_INFO outinfo{};
|
||||
|
|
@ -421,8 +460,8 @@ int main(al::span<std::string_view> args)
|
|||
SndFilePtr outfile{sf_open(outname.c_str(), SFM_WRITE, &outinfo)};
|
||||
if(!outfile)
|
||||
{
|
||||
fprintf(stderr, " ... failed to create %s\n", outname.c_str());
|
||||
continue;
|
||||
fmt::println(stderr, " ... failed to create {}", outname);
|
||||
return;
|
||||
}
|
||||
|
||||
auto encoder = std::make_unique<UhjEncoder>();
|
||||
|
|
@ -485,7 +524,7 @@ int main(al::span<std::string_view> args)
|
|||
[chanid](const SpeakerPos pos){return pos.mChannelID == chanid;});
|
||||
if(spkr == spkrs.cend())
|
||||
{
|
||||
fprintf(stderr, " ... failed to find channel ID %d\n", chanid);
|
||||
fmt::println(stderr, " ... failed to find channel ID {}", chanid);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -523,19 +562,21 @@ int main(al::span<std::string_view> args)
|
|||
sf_count_t wrote{sf_writef_float(outfile.get(), outmem.data(),
|
||||
static_cast<sf_count_t>(got))};
|
||||
if(wrote < 0)
|
||||
fprintf(stderr, " ... failed to write samples: %d\n", sf_error(outfile.get()));
|
||||
fmt::println(stderr, " ... failed to write samples: {}", sf_error(outfile.get()));
|
||||
else
|
||||
total_wrote += static_cast<size_t>(wrote);
|
||||
}
|
||||
printf(" ... wrote %zu samples (%" PRId64 ").\n", total_wrote, int64_t{ininfo.frames});
|
||||
fmt::println(" ... wrote {} samples ({}).", total_wrote, ininfo.frames);
|
||||
++num_encoded;
|
||||
}
|
||||
};
|
||||
std::for_each(args.begin(), args.end(), process_arg);
|
||||
|
||||
if(num_encoded == 0)
|
||||
fprintf(stderr, "Failed to encode any input files\n");
|
||||
fmt::println(stderr, "Failed to encode any input files");
|
||||
else if(num_encoded < num_files)
|
||||
fprintf(stderr, "Encoded %zu of %zu files\n", num_encoded, num_files);
|
||||
fmt::println(stderr, "Encoded {} of {} files", num_encoded, num_files);
|
||||
else
|
||||
printf("Encoded %s%zu file%s\n", (num_encoded > 1) ? "all " : "", num_encoded,
|
||||
fmt::println("Encoded {}{} file{}", (num_encoded > 1) ? "all " : "", num_encoded,
|
||||
(num_encoded == 1) ? "" : "s");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue