Copilot君あるいはGemini君ごめんなさい 誤解でしたよ(笑)
の続報です。記事の冒頭で、
Copilot君による”完全コード”とかもいくらでも出てきますけど、ことごとく動きませんでした。なんとも時間の無駄でしたね。かって筆者は、システム音のレベルの表示プログラムは、このWASAPIを使って書いていました。
と書きましたけど、誤解でした。ヒントは、capture->playbackのコマンドラインプログラムは動作していたという事実でした。要するに、
// Get the mix format
hr = pAudioClient->GetMixFormat(&pwfx);
if (FAILED(hr)) {
std::cerr << "GetMixFormat failed. HR=" << std::hex << hr << "\n";
goto cleanup;
}
ここで得た
WAVEFORMATEX* pwfx;
の内容に合わせて、level値(瞬時値ともいふ)を取り出さないとダメだということですね。以下のコマンドラインプログラムを動かすと、
#include <windows.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <iostream>
/*
WAVEFORMATEX構造体
typedef struct {
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX;
*/
int main() {
HRESULT hr;
CoInitialize(NULL);
IMMDeviceEnumerator* pEnumerator = nullptr;
IMMDevice* pDevice = nullptr;
IAudioClient* pAudioClient = nullptr;
WAVEFORMATEX* pwfx = nullptr;
// Create device enumerator
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
if (FAILED(hr)) {
std::cerr << "Failed to create device enumerator. HR=" << std::hex << hr << "\n";
goto cleanup;
}
// Get default audio capture device
hr = pEnumerator->GetDefaultAudioEndpoint(eCapture, eConsole, &pDevice);
if (FAILED(hr)) {
std::cerr << "Failed to get default capture device. HR=" << std::hex << hr << "\n";
goto cleanup;
}
// Activate IAudioClient
hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
if (FAILED(hr)) {
std::cerr << "Failed to activate IAudioClient. HR=" << std::hex << hr << "\n";
goto cleanup;
}
// Get the mix format
hr = pAudioClient->GetMixFormat(&pwfx);
if (FAILED(hr)) {
std::cerr << "GetMixFormat failed. HR=" << std::hex << hr << "\n";
goto cleanup;
}
// Print format info
//std::cout << "FormatTag: " << pwfx->wFormatTag << "\n";
/*
if( pwfx->wFormatTag == WAVE_FORMAT_PCM )
std::cout << "WAVE_FORMAT_PCM" << "\n";
else
std::cout << "NOT WAVE_FORMAT_PCM" << "\n";
*/
switch( pwfx->wFormatTag ){
case WAVE_FORMAT_PCM :
std::cout << "WAVE_FORMAT_PCM" << "\n";
break;
case WAVE_FORMAT_IEEE_FLOAT :
std::cout << "WAVE_FORMAT_IEEE_FLOAT" << "\n";
break;
case WAVE_FORMAT_DRM :
std::cout << "WAVE_FORMAT_DRM" << "\n";
break;
case WAVE_FORMAT_ALAW :
std::cout << "WAVE_FORMAT_ALAW" << "\n";
break;
case WAVE_FORMAT_MULAW :
std::cout << "WAVE_FORMAT_MULAW" << "\n";
break;
case WAVE_FORMAT_ADPCM :
std::cout << "WAVE_FORMAT_ADPCM" << "\n";
break;
case WAVE_FORMAT_EXTENSIBLE :
std::cout << "WAVE_FORMAT_EXTENSIBLE" << "\n";
break;
default :
std::cout << "Unknown Format" << "\n";
break;
}
std::cout << "Sample rate: " << pwfx->nSamplesPerSec << "\n";
std::cout << "Channels: " << pwfx->nChannels << "\n";
std::cout << "Bits per sample: " << pwfx->wBitsPerSample << "\n";
cleanup:
if (pwfx) CoTaskMemFree(pwfx);
if (pAudioClient) pAudioClient->Release();
if (pDevice) pDevice->Release();
if (pEnumerator) pEnumerator->Release();
CoUninitialize();
return 0;
}
これをbcc32cでコンパイルしてから、対象のマシンで動かすと、上記コードが”getformat.cpp”とすると、

ということで、16bit-pcmではありません。floatで扱うのが妥当らしいので、
pCaptureClient->GetBuffer(&pData, &numFramesAvailable, &flags, NULL, NULL);
if (numFramesAvailable > 0) {
// 16-bit PCM (フォーマットに応じて切り替え)
float* pFloatData = reinterpret_cast<float*>(pData);
size_t totalSamples = numFramesAvailable * pwfx->nChannels;
//short *samples = (short*)pData;
//double sum = 0;
float sum = 0.0f;
//int sampleCount = numFramesAvailable;
for (size_t i = 0; i < totalSamples; ++i) {
sum += pFloatData[i] * pFloatData[i];
}
float rms = std::sqrt(sum / totalSamples);
// デシベル換算 (必要に応じて)
float db = 20.0f * std::log10(rms + 1e-5f);
// UIスレッドでメーターを更新...
Label1->Caption = FloatToStr(db);
ProgressBar1->Position = rms*100;
pCaptureClient->ReleaseBuffer(numFramesAvailable);
}
というcapture loopを使わないと齟齬を来すというわけでした。コメントアウトした方では正しい値が得られておらず、動作してないように見えたということですね。Copilot君にうかがう時に、一言”float”と言うワードを足せば良かったようですね。
というか最初時点で積極的に16-bit PCMのフォーマットを使うようにすれば良かったわけですね。



コメント