Apply clang-format across the whole tree
Run clang-format (the repo's .clang-format: LLVM base, 120 cols, tabs, Allman functions) over every source file so the tree is formatter-clean. Whitespace only -- no behavior change; full x64 + x86 suites pass. Also set SortIncludes: false in .clang-format. Windows include order is load-bearing (windows.h must precede tlhelp32.h / mmreg.h / xinput.h / dinput.h; winsock2.h must precede windows.h), and the default alphabetical sort reorders tlhelp32.h ahead of windows.h -- a build break. Leaving order alone keeps the manual, correct grouping.
This commit is contained in:
@@ -24,8 +24,7 @@
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace coop
|
||||
{
|
||||
namespace coop {
|
||||
|
||||
// The standard sample rates a shared-mode WASAPI stream realistically uses. Candidates are this
|
||||
// set; a non-standard true rate is out of scope (and would show as low-confidence either way).
|
||||
@@ -35,30 +34,25 @@ inline const std::vector<unsigned>& standard_audio_rates()
|
||||
return rates;
|
||||
}
|
||||
|
||||
struct RateCorrelation
|
||||
{
|
||||
bool ok = false; // a confident pick was made (winner clears the threshold AND beats the runner-up)
|
||||
unsigned rate = 0; // best candidate rate (Hz)
|
||||
double score = 0.0; // alignment score of the winner, in [0,1] (1 = perfect)
|
||||
struct RateCorrelation {
|
||||
bool ok = false; // a confident pick was made (winner clears the threshold AND beats the runner-up)
|
||||
unsigned rate = 0; // best candidate rate (Hz)
|
||||
double score = 0.0; // alignment score of the winner, in [0,1] (1 = perfect)
|
||||
double runner_up = 0.0; // score of the second-best candidate (for separation)
|
||||
};
|
||||
|
||||
namespace correlate_detail
|
||||
{
|
||||
namespace correlate_detail {
|
||||
|
||||
// Average interleaved float frames down to a single mono channel.
|
||||
inline void downmix(const float* interleaved, std::size_t frames, unsigned channels, std::vector<float>& out)
|
||||
{
|
||||
out.resize(frames);
|
||||
if (channels == 0)
|
||||
{
|
||||
if (channels == 0) {
|
||||
channels = 1;
|
||||
}
|
||||
for (std::size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < frames; ++i) {
|
||||
float sum = 0.0f;
|
||||
for (unsigned c = 0; c < channels; ++c)
|
||||
{
|
||||
for (unsigned c = 0; c < channels; ++c) {
|
||||
sum += interleaved[i * channels + c];
|
||||
}
|
||||
out[i] = sum / static_cast<float>(channels);
|
||||
@@ -66,24 +60,20 @@ inline void downmix(const float* interleaved, std::size_t frames, unsigned chann
|
||||
}
|
||||
|
||||
// Linear-resample a mono signal from src_rate to dst_rate.
|
||||
inline void resample_linear(const std::vector<float>& in, unsigned src_rate, unsigned dst_rate,
|
||||
std::vector<float>& out)
|
||||
inline void resample_linear(const std::vector<float>& in, unsigned src_rate, unsigned dst_rate, std::vector<float>& out)
|
||||
{
|
||||
if (src_rate == 0 || dst_rate == 0 || in.empty())
|
||||
{
|
||||
if (src_rate == 0 || dst_rate == 0 || in.empty()) {
|
||||
out.clear();
|
||||
return;
|
||||
}
|
||||
if (src_rate == dst_rate)
|
||||
{
|
||||
if (src_rate == dst_rate) {
|
||||
out = in;
|
||||
return;
|
||||
}
|
||||
const double step = static_cast<double>(src_rate) / static_cast<double>(dst_rate);
|
||||
const std::size_t out_n = static_cast<std::size_t>(static_cast<double>(in.size()) / step);
|
||||
out.resize(out_n);
|
||||
for (std::size_t i = 0; i < out_n; ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < out_n; ++i) {
|
||||
const double pos = static_cast<double>(i) * step;
|
||||
const std::size_t j = static_cast<std::size_t>(pos);
|
||||
const double frac = pos - static_cast<double>(j);
|
||||
@@ -97,29 +87,24 @@ inline void resample_linear(const std::vector<float>& in, unsigned src_rate, uns
|
||||
// alignment search (the envelope/content alignment doesn't need full bandwidth).
|
||||
inline void decimate(const std::vector<float>& in, unsigned rate, unsigned corr_rate, std::vector<float>& out)
|
||||
{
|
||||
if (rate <= corr_rate || in.empty())
|
||||
{
|
||||
if (rate <= corr_rate || in.empty()) {
|
||||
out = in;
|
||||
return;
|
||||
}
|
||||
const double factor = static_cast<double>(rate) / static_cast<double>(corr_rate);
|
||||
const std::size_t out_n = static_cast<std::size_t>(static_cast<double>(in.size()) / factor);
|
||||
out.resize(out_n);
|
||||
for (std::size_t i = 0; i < out_n; ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < out_n; ++i) {
|
||||
const std::size_t lo = static_cast<std::size_t>(static_cast<double>(i) * factor);
|
||||
std::size_t hi = static_cast<std::size_t>(static_cast<double>(i + 1) * factor);
|
||||
if (hi <= lo)
|
||||
{
|
||||
if (hi <= lo) {
|
||||
hi = lo + 1;
|
||||
}
|
||||
if (hi > in.size())
|
||||
{
|
||||
if (hi > in.size()) {
|
||||
hi = in.size();
|
||||
}
|
||||
float sum = 0.0f;
|
||||
for (std::size_t k = lo; k < hi; ++k)
|
||||
{
|
||||
for (std::size_t k = lo; k < hi; ++k) {
|
||||
sum += in[k];
|
||||
}
|
||||
out[i] = sum / static_cast<float>(hi - lo);
|
||||
@@ -133,29 +118,24 @@ inline double ncc(const std::vector<float>& a, const std::vector<float>& b, long
|
||||
{
|
||||
double sa = 0.0, sb = 0.0;
|
||||
std::size_t n = 0;
|
||||
for (std::size_t i = start; i < start + len && i < a.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = start; i < start + len && i < a.size(); ++i) {
|
||||
const long bi = static_cast<long>(i) + lag;
|
||||
if (bi < 0 || static_cast<std::size_t>(bi) >= b.size())
|
||||
{
|
||||
if (bi < 0 || static_cast<std::size_t>(bi) >= b.size()) {
|
||||
continue;
|
||||
}
|
||||
sa += a[i];
|
||||
sb += b[bi];
|
||||
++n;
|
||||
}
|
||||
if (n < 8)
|
||||
{
|
||||
if (n < 8) {
|
||||
return 0.0;
|
||||
}
|
||||
const double ma = sa / static_cast<double>(n);
|
||||
const double mb = sb / static_cast<double>(n);
|
||||
double num = 0.0, da = 0.0, db = 0.0;
|
||||
for (std::size_t i = start; i < start + len && i < a.size(); ++i)
|
||||
{
|
||||
for (std::size_t i = start; i < start + len && i < a.size(); ++i) {
|
||||
const long bi = static_cast<long>(i) + lag;
|
||||
if (bi < 0 || static_cast<std::size_t>(bi) >= b.size())
|
||||
{
|
||||
if (bi < 0 || static_cast<std::size_t>(bi) >= b.size()) {
|
||||
continue;
|
||||
}
|
||||
const double xa = a[i] - ma;
|
||||
@@ -164,8 +144,7 @@ inline double ncc(const std::vector<float>& a, const std::vector<float>& b, long
|
||||
da += xa * xa;
|
||||
db += xb * xb;
|
||||
}
|
||||
if (da < 1e-9 || db < 1e-9)
|
||||
{
|
||||
if (da < 1e-9 || db < 1e-9) {
|
||||
return 0.0;
|
||||
}
|
||||
return num / std::sqrt(da * db);
|
||||
@@ -188,11 +167,9 @@ inline double aligned_score(const std::vector<float>& a, const std::vector<float
|
||||
const std::size_t mid_len = n / 2;
|
||||
double best = -2.0;
|
||||
long best_lag = 0;
|
||||
for (long lag = -max_lag; lag <= max_lag; ++lag)
|
||||
{
|
||||
for (long lag = -max_lag; lag <= max_lag; ++lag) {
|
||||
const double c = ncc(a, b, lag, mid_start, mid_len);
|
||||
if (c > best)
|
||||
{
|
||||
if (c > best) {
|
||||
best = c;
|
||||
best_lag = lag;
|
||||
}
|
||||
@@ -218,8 +195,7 @@ inline RateCorrelation correlate_rate(const std::vector<float>& hook_mono, const
|
||||
{
|
||||
using namespace correlate_detail;
|
||||
RateCorrelation result;
|
||||
if (hook_mono.empty() || loop_mono.empty() || device_rate == 0)
|
||||
{
|
||||
if (hook_mono.empty() || loop_mono.empty() || device_rate == 0) {
|
||||
return result;
|
||||
}
|
||||
constexpr unsigned kCorrRate = 8000; // alignment search rate (Nyquist 4 kHz -- plenty for content)
|
||||
@@ -230,19 +206,15 @@ inline RateCorrelation correlate_rate(const std::vector<float>& hook_mono, const
|
||||
double best = -1.0, second = -1.0;
|
||||
unsigned best_rate = 0;
|
||||
std::vector<float> resampled, hook_ds;
|
||||
for (unsigned cand : candidates)
|
||||
{
|
||||
for (unsigned cand : candidates) {
|
||||
resample_linear(hook_mono, cand, device_rate, resampled); // treat hook as sampled at `cand`
|
||||
decimate(resampled, device_rate, kCorrRate, hook_ds);
|
||||
const double s = aligned_score(hook_ds, loop_ds, kCorrRate);
|
||||
if (s > best)
|
||||
{
|
||||
if (s > best) {
|
||||
second = best;
|
||||
best = s;
|
||||
best_rate = cand;
|
||||
}
|
||||
else if (s > second)
|
||||
{
|
||||
} else if (s > second) {
|
||||
second = s;
|
||||
}
|
||||
}
|
||||
@@ -250,7 +222,8 @@ inline RateCorrelation correlate_rate(const std::vector<float>& hook_mono, const
|
||||
result.rate = best_rate;
|
||||
result.score = best < 0.0 ? 0.0 : best;
|
||||
result.runner_up = second < 0.0 ? 0.0 : second;
|
||||
result.ok = result.score >= min_score && (result.runner_up <= 1e-6 || result.score >= result.runner_up * separation);
|
||||
result.ok =
|
||||
result.score >= min_score && (result.runner_up <= 1e-6 || result.score >= result.runner_up * separation);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -266,8 +239,7 @@ inline RateCorrelation correlate_rate(const std::vector<float>& hook_mono, const
|
||||
inline constexpr unsigned kWaveFormatPcm = 1; // WAVE_FORMAT_PCM
|
||||
inline constexpr unsigned kWaveFormatFloat = 3; // WAVE_FORMAT_IEEE_FLOAT
|
||||
|
||||
struct LayoutCandidate
|
||||
{
|
||||
struct LayoutCandidate {
|
||||
unsigned channels;
|
||||
unsigned bits;
|
||||
unsigned tag; // kWaveFormatPcm / kWaveFormatFloat
|
||||
@@ -278,16 +250,14 @@ struct LayoutCandidate
|
||||
inline const std::vector<LayoutCandidate>& standard_audio_layouts()
|
||||
{
|
||||
static const std::vector<LayoutCandidate> v = {
|
||||
{2, 32, kWaveFormatFloat}, {1, 32, kWaveFormatFloat}, {6, 32, kWaveFormatFloat},
|
||||
{8, 32, kWaveFormatFloat}, {4, 32, kWaveFormatFloat}, {2, 16, kWaveFormatPcm},
|
||||
{1, 16, kWaveFormatPcm}, {6, 16, kWaveFormatPcm}, {8, 16, kWaveFormatPcm},
|
||||
{4, 16, kWaveFormatPcm},
|
||||
{2, 32, kWaveFormatFloat}, {1, 32, kWaveFormatFloat}, {6, 32, kWaveFormatFloat}, {8, 32, kWaveFormatFloat},
|
||||
{4, 32, kWaveFormatFloat}, {2, 16, kWaveFormatPcm}, {1, 16, kWaveFormatPcm}, {6, 16, kWaveFormatPcm},
|
||||
{8, 16, kWaveFormatPcm}, {4, 16, kWaveFormatPcm},
|
||||
};
|
||||
return v;
|
||||
}
|
||||
|
||||
struct FormatCorrelation
|
||||
{
|
||||
struct FormatCorrelation {
|
||||
bool ok = false;
|
||||
unsigned rate = 0;
|
||||
unsigned channels = 0;
|
||||
@@ -302,15 +272,13 @@ struct FormatCorrelation
|
||||
// padding is stale staging-buffer bytes, so the host must extract the real `count*real_block` bytes
|
||||
// per buffer (and concatenate) before de-interleaving -- otherwise the padding scrambles the audio.
|
||||
// This carries that self-describing capture: `bytes` holds counts[i]*stride bytes per chunk.
|
||||
struct ChunkedCapture
|
||||
{
|
||||
struct ChunkedCapture {
|
||||
unsigned stride = 0; // bytes per frame as pushed (the guessed/device block_align)
|
||||
std::vector<std::uint32_t> counts; // real frame count of each chunk
|
||||
std::vector<std::uint8_t> bytes; // concatenated, counts[i]*stride bytes per chunk
|
||||
};
|
||||
|
||||
namespace correlate_detail
|
||||
{
|
||||
namespace correlate_detail {
|
||||
// De-interleave raw bytes under (channels/bits/tag) and average to mono float.
|
||||
inline void decode_layout(const std::uint8_t* bytes, std::size_t n, const LayoutCandidate& fmt,
|
||||
std::vector<float>& mono)
|
||||
@@ -318,33 +286,25 @@ inline void decode_layout(const std::uint8_t* bytes, std::size_t n, const Layout
|
||||
mono.clear();
|
||||
const unsigned ch = fmt.channels == 0 ? 1 : fmt.channels;
|
||||
const unsigned bps = fmt.bits / 8;
|
||||
if (bps == 0)
|
||||
{
|
||||
if (bps == 0) {
|
||||
return;
|
||||
}
|
||||
const std::size_t frame = static_cast<std::size_t>(ch) * bps;
|
||||
const std::size_t frames = n / frame;
|
||||
mono.resize(frames);
|
||||
const bool is_float = fmt.tag == kWaveFormatFloat;
|
||||
for (std::size_t i = 0; i < frames; ++i)
|
||||
{
|
||||
for (std::size_t i = 0; i < frames; ++i) {
|
||||
double sum = 0.0;
|
||||
for (unsigned c = 0; c < ch; ++c)
|
||||
{
|
||||
for (unsigned c = 0; c < ch; ++c) {
|
||||
const std::uint8_t* p = bytes + i * frame + static_cast<std::size_t>(c) * bps;
|
||||
float s = 0.0f;
|
||||
if (is_float && fmt.bits == 32)
|
||||
{
|
||||
if (is_float && fmt.bits == 32) {
|
||||
std::memcpy(&s, p, 4);
|
||||
}
|
||||
else if (fmt.bits == 16)
|
||||
{
|
||||
} else if (fmt.bits == 16) {
|
||||
std::int16_t v;
|
||||
std::memcpy(&v, p, 2);
|
||||
s = v / 32768.0f;
|
||||
}
|
||||
else if (fmt.bits == 32)
|
||||
{
|
||||
} else if (fmt.bits == 32) {
|
||||
std::int32_t v;
|
||||
std::memcpy(&v, p, 4);
|
||||
s = static_cast<float>(v / 2147483648.0);
|
||||
@@ -372,58 +332,50 @@ inline FormatCorrelation correlate_format(const ChunkedCapture& hook, const std:
|
||||
double min_margin = 0.04)
|
||||
{
|
||||
FormatCorrelation result;
|
||||
if (hook.stride == 0 || hook.counts.empty() || loop_mono.empty() || device_rate == 0)
|
||||
{
|
||||
if (hook.stride == 0 || hook.counts.empty() || loop_mono.empty() || device_rate == 0) {
|
||||
return result;
|
||||
}
|
||||
double best = -1.0, second = -1.0;
|
||||
std::vector<std::uint8_t> clean;
|
||||
std::vector<float> hook_mono;
|
||||
for (const LayoutCandidate& layout : layouts)
|
||||
{
|
||||
for (const LayoutCandidate& layout : layouts) {
|
||||
const unsigned real_block = layout.channels * (layout.bits / 8);
|
||||
if (real_block == 0 || real_block > hook.stride)
|
||||
{
|
||||
if (real_block == 0 || real_block > hook.stride) {
|
||||
continue; // can't extract a frame larger than what was pushed (the guess is the max)
|
||||
}
|
||||
// Pull the real count*real_block bytes out of each padded chunk and concatenate -> contiguous
|
||||
// audio for this candidate layout (the padding, which is stale staging bytes, is dropped).
|
||||
clean.clear();
|
||||
std::size_t off = 0;
|
||||
for (std::uint32_t count : hook.counts)
|
||||
{
|
||||
for (std::uint32_t count : hook.counts) {
|
||||
const std::size_t chunk_bytes = static_cast<std::size_t>(count) * hook.stride;
|
||||
const std::size_t take = static_cast<std::size_t>(count) * real_block;
|
||||
if (off + chunk_bytes <= hook.bytes.size())
|
||||
{
|
||||
if (off + chunk_bytes <= hook.bytes.size()) {
|
||||
clean.insert(clean.end(), hook.bytes.begin() + off, hook.bytes.begin() + off + take);
|
||||
}
|
||||
off += chunk_bytes;
|
||||
}
|
||||
correlate_detail::decode_layout(clean.data(), clean.size(), layout, hook_mono);
|
||||
if (hook_mono.size() < device_rate / 5)
|
||||
{
|
||||
if (hook_mono.size() < device_rate / 5) {
|
||||
continue; // this layout yields too little audio to judge
|
||||
}
|
||||
const RateCorrelation rc = correlate_rate(hook_mono, loop_mono, device_rate, rates, /*min_score=*/0.0,
|
||||
/*separation=*/1.0);
|
||||
if (rc.score > best)
|
||||
{
|
||||
/*separation=*/1.0);
|
||||
if (rc.score > best) {
|
||||
second = best;
|
||||
best = rc.score;
|
||||
result.rate = rc.rate;
|
||||
result.channels = layout.channels;
|
||||
result.bits = layout.bits;
|
||||
result.tag = layout.tag;
|
||||
}
|
||||
else if (rc.score > second)
|
||||
{
|
||||
} else if (rc.score > second) {
|
||||
second = rc.score;
|
||||
}
|
||||
}
|
||||
result.score = best < 0.0 ? 0.0 : best;
|
||||
result.runner_up = second < 0.0 ? 0.0 : second;
|
||||
result.ok = result.score >= min_score && (result.runner_up <= 1e-6 || result.score - result.runner_up >= min_margin);
|
||||
result.ok =
|
||||
result.score >= min_score && (result.runner_up <= 1e-6 || result.score - result.runner_up >= min_margin);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user