任天堂おしゃべりフラワーのしゃべりを網羅する?

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のフォーマットを使うようにすれば良かったわけですね。

コメント