update openal-soft to 1.24.3

keeping the alt 87514151c4 (diff-73a8dc1ce58605f6c5ea53548454c3bae516ec5132a29c9d7ff7edf9730c75be)
This commit is contained in:
AzaezelX 2025-09-03 11:09:27 -05:00
parent 12db0500e8
commit ba32094b7b
276 changed files with 49304 additions and 8712 deletions

View file

@ -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")

View file

@ -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

View file

@ -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)
{

View file

@ -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;
}

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}