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:
@@ -22,45 +22,37 @@ int wmain(int argc, wchar_t** argv)
|
||||
const double freq = (argc > 2) ? _wtof(argv[2]) : 440.0;
|
||||
|
||||
coop::tone::ToneFormat tf;
|
||||
if (argc > 3)
|
||||
{
|
||||
if (argc > 3) {
|
||||
tf.rate = static_cast<unsigned>(_wtoi(argv[3]));
|
||||
}
|
||||
if (argc > 4)
|
||||
{
|
||||
if (argc > 4) {
|
||||
tf.channels = static_cast<unsigned>(_wtoi(argv[4]));
|
||||
}
|
||||
if (argc > 5)
|
||||
{
|
||||
if (argc > 5) {
|
||||
tf.bits = static_cast<unsigned>(_wtoi(argv[5]));
|
||||
}
|
||||
tf.is_float = (argc > 6) ? (_wcsicmp(argv[6], L"float") == 0) : (tf.bits == 32); // 32-bit -> float default
|
||||
|
||||
if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED)))
|
||||
{
|
||||
if (FAILED(CoInitializeEx(nullptr, COINIT_MULTITHREADED))) {
|
||||
std::fprintf(stderr, "CoInitializeEx failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rc = 1;
|
||||
coop::tone::ToneSource tone;
|
||||
if (tone.open(tf, freq))
|
||||
{
|
||||
if (tone.open(tf, freq)) {
|
||||
const coop::tone::ToneFormat& f = tone.format();
|
||||
std::printf("TONE_RENDERING pid=%lu %.0fHz %uHz %uch %ubit %s\n", GetCurrentProcessId(), freq, f.rate,
|
||||
f.channels, f.bits, f.is_float ? "float" : "pcm");
|
||||
std::fflush(stdout);
|
||||
|
||||
const DWORD end_tick = GetTickCount() + static_cast<DWORD>(seconds * 1000.0);
|
||||
while (GetTickCount() < end_tick)
|
||||
{
|
||||
while (GetTickCount() < end_tick) {
|
||||
tone.render_step(200);
|
||||
}
|
||||
tone.close();
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
std::fprintf(stderr, "TONE_OPEN_FAILED (endpoint or format unavailable)\n");
|
||||
}
|
||||
|
||||
|
||||
@@ -13,52 +13,42 @@
|
||||
#include <mmdeviceapi.h>
|
||||
#include <mmreg.h>
|
||||
|
||||
namespace coop::tone
|
||||
{
|
||||
namespace coop::tone {
|
||||
|
||||
inline constexpr double kTwoPi = 6.283185307179586;
|
||||
|
||||
// A field left 0 resolves to the device mix format's value (so {} = play at the device
|
||||
// format). `is_float` only applies when `bits` is set (16 -> PCM, 32 -> float by default).
|
||||
struct ToneFormat
|
||||
{
|
||||
struct ToneFormat {
|
||||
unsigned rate = 0;
|
||||
unsigned channels = 0;
|
||||
unsigned bits = 0;
|
||||
bool is_float = false;
|
||||
};
|
||||
|
||||
class ToneSource
|
||||
{
|
||||
public:
|
||||
~ToneSource()
|
||||
{
|
||||
close();
|
||||
}
|
||||
class ToneSource {
|
||||
public:
|
||||
~ToneSource() { close(); }
|
||||
|
||||
// Open + start a render client at `want` (0 fields resolve to the device mix format,
|
||||
// AUTOCONVERTPCM lets a non-device format be rendered). Returns false if the endpoint
|
||||
// or that specific format isn't available (the caller treats that as a per-format skip).
|
||||
bool open(const ToneFormat& want, double freq_hz = 440.0)
|
||||
{
|
||||
if (FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL,
|
||||
__uuidof(IMMDeviceEnumerator), reinterpret_cast<void**>(&enum_))))
|
||||
{
|
||||
if (FAILED(CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator),
|
||||
reinterpret_cast<void**>(&enum_)))) {
|
||||
return false;
|
||||
}
|
||||
if (FAILED(enum_->GetDefaultAudioEndpoint(eRender, eConsole, &endpoint_)))
|
||||
{
|
||||
if (FAILED(enum_->GetDefaultAudioEndpoint(eRender, eConsole, &endpoint_))) {
|
||||
return false;
|
||||
}
|
||||
if (FAILED(endpoint_->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr,
|
||||
reinterpret_cast<void**>(&client_))))
|
||||
{
|
||||
if (FAILED(
|
||||
endpoint_->Activate(__uuidof(IAudioClient), CLSCTX_ALL, nullptr, reinterpret_cast<void**>(&client_)))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WAVEFORMATEX* mix = nullptr;
|
||||
if (FAILED(client_->GetMixFormat(&mix)) || mix == nullptr)
|
||||
{
|
||||
if (FAILED(client_->GetMixFormat(&mix)) || mix == nullptr) {
|
||||
return false;
|
||||
}
|
||||
resolve_format(want, mix);
|
||||
@@ -72,15 +62,13 @@ public:
|
||||
constexpr REFERENCE_TIME kBuffer = 30 * 10000; // 30 ms
|
||||
// AUTOCONVERTPCM makes a shared-mode client render a non-device format (the audio
|
||||
// engine resamples to the endpoint), exactly like the games that need rate detection.
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM |
|
||||
AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||
if (FAILED(client_->Initialize(AUDCLNT_SHAREMODE_SHARED, flags, kBuffer, 0, fmt, nullptr)))
|
||||
{
|
||||
const DWORD flags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
|
||||
| AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY;
|
||||
if (FAILED(client_->Initialize(AUDCLNT_SHAREMODE_SHARED, flags, kBuffer, 0, fmt, nullptr))) {
|
||||
return false;
|
||||
}
|
||||
client_->SetEventHandle(event_);
|
||||
if (FAILED(client_->GetService(__uuidof(IAudioRenderClient), reinterpret_cast<void**>(&render_))))
|
||||
{
|
||||
if (FAILED(client_->GetService(__uuidof(IAudioRenderClient), reinterpret_cast<void**>(&render_)))) {
|
||||
return false;
|
||||
}
|
||||
client_->GetBufferSize(&buffer_frames_);
|
||||
@@ -90,8 +78,7 @@ public:
|
||||
// so a downstream test can *recover* the channel count by correlation (identical channels
|
||||
// are ambiguous: 2ch@R looks like 1ch@2R). Off by default -> the usual single-tone source.
|
||||
char d[2] = {};
|
||||
if (GetEnvironmentVariableA("COOP_TONE_DISTINCT_CH", d, sizeof(d)) > 0 && d[0] == '1')
|
||||
{
|
||||
if (GetEnvironmentVariableA("COOP_TONE_DISTINCT_CH", d, sizeof(d)) > 0 && d[0] == '1') {
|
||||
distinct_ = true;
|
||||
}
|
||||
write(buffer_frames_); // pre-roll
|
||||
@@ -103,54 +90,43 @@ public:
|
||||
// timeout/error (the caller keeps looping on its own wall clock).
|
||||
bool render_step(DWORD timeout_ms)
|
||||
{
|
||||
if (render_ == nullptr)
|
||||
{
|
||||
if (render_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (WaitForSingleObject(event_, timeout_ms) != WAIT_OBJECT_0)
|
||||
{
|
||||
if (WaitForSingleObject(event_, timeout_ms) != WAIT_OBJECT_0) {
|
||||
return false;
|
||||
}
|
||||
UINT32 padding = 0;
|
||||
if (FAILED(client_->GetCurrentPadding(&padding)))
|
||||
{
|
||||
if (FAILED(client_->GetCurrentPadding(&padding))) {
|
||||
return false;
|
||||
}
|
||||
write(buffer_frames_ - padding);
|
||||
return true;
|
||||
}
|
||||
|
||||
const ToneFormat& format() const
|
||||
{
|
||||
return fmt_;
|
||||
}
|
||||
bool is_open() const
|
||||
{
|
||||
return render_ != nullptr;
|
||||
}
|
||||
const ToneFormat& format() const { return fmt_; }
|
||||
bool is_open() const { return render_ != nullptr; }
|
||||
|
||||
void close()
|
||||
{
|
||||
if (client_)
|
||||
{
|
||||
if (client_) {
|
||||
client_->Stop();
|
||||
}
|
||||
rel(render_);
|
||||
rel(client_);
|
||||
rel(endpoint_);
|
||||
rel(enum_);
|
||||
if (event_)
|
||||
{
|
||||
if (event_) {
|
||||
CloseHandle(event_);
|
||||
event_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T> static void rel(T*& p)
|
||||
private:
|
||||
template <typename T>
|
||||
static void rel(T*& p)
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
if (p) {
|
||||
p->Release();
|
||||
p = nullptr;
|
||||
}
|
||||
@@ -160,18 +136,15 @@ private:
|
||||
{
|
||||
fmt_.rate = want.rate ? want.rate : mix->nSamplesPerSec;
|
||||
fmt_.channels = want.channels ? want.channels : mix->nChannels;
|
||||
if (want.bits)
|
||||
{
|
||||
if (want.bits) {
|
||||
fmt_.bits = want.bits;
|
||||
fmt_.is_float = want.is_float;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
fmt_.bits = mix->wBitsPerSample;
|
||||
fmt_.is_float =
|
||||
mix->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
|
||||
(mix->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
|
||||
reinterpret_cast<const WAVEFORMATEXTENSIBLE*>(mix)->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
|
||||
fmt_.is_float = mix->wFormatTag == WAVE_FORMAT_IEEE_FLOAT
|
||||
|| (mix->wFormatTag == WAVE_FORMAT_EXTENSIBLE
|
||||
&& reinterpret_cast<const WAVEFORMATEXTENSIBLE*>(mix)->SubFormat
|
||||
== KSDATAFORMAT_SUBTYPE_IEEE_FLOAT);
|
||||
}
|
||||
float_ = fmt_.is_float;
|
||||
}
|
||||
@@ -184,13 +157,11 @@ private:
|
||||
wfx.Format.wBitsPerSample = static_cast<WORD>(fmt_.bits);
|
||||
wfx.Format.nBlockAlign = block;
|
||||
wfx.Format.nAvgBytesPerSec = block * fmt_.rate;
|
||||
if (fmt_.channels > 2 || fmt_.bits > 16)
|
||||
{
|
||||
if (fmt_.channels > 2 || fmt_.bits > 16) {
|
||||
wfx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
|
||||
wfx.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
|
||||
wfx.Samples.wValidBitsPerSample = static_cast<WORD>(fmt_.bits);
|
||||
switch (fmt_.channels)
|
||||
{
|
||||
switch (fmt_.channels) {
|
||||
case 6:
|
||||
wfx.dwChannelMask = 0x3F;
|
||||
break;
|
||||
@@ -202,9 +173,7 @@ private:
|
||||
break;
|
||||
}
|
||||
wfx.SubFormat = float_ ? KSDATAFORMAT_SUBTYPE_IEEE_FLOAT : KSDATAFORMAT_SUBTYPE_PCM;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
wfx.Format.wFormatTag = float_ ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
|
||||
wfx.Format.cbSize = 0;
|
||||
}
|
||||
@@ -213,37 +182,28 @@ private:
|
||||
void write(UINT32 frames)
|
||||
{
|
||||
BYTE* data = nullptr;
|
||||
if (frames == 0 || render_ == nullptr || FAILED(render_->GetBuffer(frames, &data)))
|
||||
{
|
||||
if (frames == 0 || render_ == nullptr || FAILED(render_->GetBuffer(frames, &data))) {
|
||||
return;
|
||||
}
|
||||
for (UINT32 i = 0; i < frames; ++i)
|
||||
{
|
||||
for (UINT32 i = 0; i < frames; ++i) {
|
||||
const double s = std::sin(phase_) * 0.25; // -12 dB, gentle
|
||||
phase_ += step_;
|
||||
if (phase_ > kTwoPi)
|
||||
{
|
||||
if (phase_ > kTwoPi) {
|
||||
phase_ -= kTwoPi;
|
||||
}
|
||||
for (unsigned c = 0; c < fmt_.channels; ++c)
|
||||
{
|
||||
for (unsigned c = 0; c < fmt_.channels; ++c) {
|
||||
double sc = s;
|
||||
if (distinct_ && c < 8)
|
||||
{
|
||||
if (distinct_ && c < 8) {
|
||||
// Each channel at its own frequency scale -> genuinely different content.
|
||||
sc = std::sin(phase_c_[c]) * 0.25;
|
||||
phase_c_[c] += step_ * (1.0 + 0.37 * static_cast<double>(c));
|
||||
if (phase_c_[c] > kTwoPi)
|
||||
{
|
||||
if (phase_c_[c] > kTwoPi) {
|
||||
phase_c_[c] -= kTwoPi;
|
||||
}
|
||||
}
|
||||
if (float_)
|
||||
{
|
||||
if (float_) {
|
||||
reinterpret_cast<float*>(data)[i * fmt_.channels + c] = static_cast<float>(sc);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
reinterpret_cast<INT16*>(data)[i * fmt_.channels + c] = static_cast<INT16>(sc * 32767.0);
|
||||
}
|
||||
}
|
||||
@@ -261,8 +221,8 @@ private:
|
||||
bool float_ = false;
|
||||
double phase_ = 0.0;
|
||||
double step_ = 0.0;
|
||||
bool distinct_ = false; // per-channel distinct content (recoverable channel count)
|
||||
double phase_c_[8] = {}; // per-channel phase when distinct_
|
||||
bool distinct_ = false; // per-channel distinct content (recoverable channel count)
|
||||
double phase_c_[8] = {}; // per-channel phase when distinct_
|
||||
};
|
||||
|
||||
} // namespace coop::tone
|
||||
|
||||
Reference in New Issue
Block a user