none
waveOpenで開いたwavファイルの再生するとき、開いたファイル毎に音量の調整を行いたい (複数開いたら、ファイル毎に音量を変えて同時再生したい)

    質問

  • VisualStudio2010 MFCでソフトを開発しております。 ソフトのターゲットOSは Win7~10です。

    waveOpenでwavファイルを開いて
    waveOutSetVolumeで音量を調整しています。
    (waveOutSetVolumeの第一引数にはwaveOutOpenで得たWAVOUTハンドラを渡してます)

    これとは別のwavファイルをmciSendCommandで開いて 
    mciSendCommand( ID,, MCI_SETAUDIO, MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE, (DWORD_PTR) &mci_vol);
    で音量を調整しています。

    別々で実行すると問題なくそれぞれ音量が調整されて再生されますが
    同時にやるとwaveOutSetVolumeがアプリケーション内全部に効いて、mciSendCommandで指定した音量がwaveOutSetVolumeで指定した内になるようです。


    waveOutSetVolumeがデバイス全体に影響を及ぼしているようですが、
    waveOpenで開いたファイルの再生だけ音量を変える方法はありますでしょうか?
    (今回はmciを使ってますが、複数のwavファイルを複数のwaveOpenで開いて、ファイル毎に音量を調整して同時再生する事と同じと思っております)

    皆様、ご教授よろしくお願いします。

    この後、waveOutWriteに渡すデータをいじって個別の音量を変える という情報があったのですが、できれば、Waveデータの内部を見たり,変更したり という事は避けたいです。




    2018年5月23日 11:12

回答

  • 挙げられたAPIはいずれもWinmm.dllを使用するかと思います。これらは1991年に発売されたWindows 3.0 Multimedia Extensionsで導入されたMultimedia Audio APIです。当時のPCはとても非力で音声の合成や個別のボリューム調整はできませんでした(実現しようにもCPUが再生に追い付かない)。唯一マスターボリュームがあるのみで、それすらサウンドデバイス依存でした。
    というわけでWaveデータを編集し音量を調整するのはアプリケーションの役目です。

    これらを一新するために再設計されたのがWindows Vistaから登場したCore Audio APIです。Vista以降では前述のMultimedia Audio APIはCore Audio APIの上に互換レイヤーとして載せられています。幸か不幸か、そのことがMultimedia Audio APIのマスターボリュームがCore Audio API上のアプリケーション固有ボリュームへとマッピングされています。
    というわけで引き続きMultimedia Audio APIではファイル毎の音量調整はできません。希望される処理はCore Audio APIを直接扱う必要があります。

    ところでこれらのAPIはあくまでサウンドデバイスとしてのAPIであり実のところマルチメディアとしてのAPIではありません。実はマルチメディア向けにはこれらとは別にMedia Foundationが用意されています。こちらはWindows Media Playerの基盤となっています。
    Source Readerでファイルを読み込み、Sink Writerを使って、Streaming Audio Renderer (Media Sink)に書き込むのかな…? この場合は個別にボリュームを制御できたかと思います。

    2018年5月23日 13:27

すべての返信

  • 挙げられたAPIはいずれもWinmm.dllを使用するかと思います。これらは1991年に発売されたWindows 3.0 Multimedia Extensionsで導入されたMultimedia Audio APIです。当時のPCはとても非力で音声の合成や個別のボリューム調整はできませんでした(実現しようにもCPUが再生に追い付かない)。唯一マスターボリュームがあるのみで、それすらサウンドデバイス依存でした。
    というわけでWaveデータを編集し音量を調整するのはアプリケーションの役目です。

    これらを一新するために再設計されたのがWindows Vistaから登場したCore Audio APIです。Vista以降では前述のMultimedia Audio APIはCore Audio APIの上に互換レイヤーとして載せられています。幸か不幸か、そのことがMultimedia Audio APIのマスターボリュームがCore Audio API上のアプリケーション固有ボリュームへとマッピングされています。
    というわけで引き続きMultimedia Audio APIではファイル毎の音量調整はできません。希望される処理はCore Audio APIを直接扱う必要があります。

    ところでこれらのAPIはあくまでサウンドデバイスとしてのAPIであり実のところマルチメディアとしてのAPIではありません。実はマルチメディア向けにはこれらとは別にMedia Foundationが用意されています。こちらはWindows Media Playerの基盤となっています。
    Source Readerでファイルを読み込み、Sink Writerを使って、Streaming Audio Renderer (Media Sink)に書き込むのかな…? この場合は個別にボリュームを制御できたかと思います。

    2018年5月23日 13:27
  • waveOutSetVolume()はサウンド出力デバイス自体のボリュームを変更するので、アプリケーション全体というよりシステム全体に影響を及ぼすはずです。もしWave系の下位レベルAPIでの再生時に個別のチャンネルの音量を調節したければ、RIFFデータ(波形データ)を直接いじるしかないはずです。

    ちなみに、Wave系APIとMCIを併用している理由は何ですか? 単純にMCIで複数のWAVファイルを開いて再生するという手法を使わない理由は何ですか?

    mciSendString()を使った例を挙げておきます。エラーチェックは省略しています。

    void DoMciTest()
    {
    	const LPCTSTR filePath1 = <ファイルパス文字列1>;
    	const LPCTSTR filePath2 = <ファイルパス文字列2>;
    	const LPCTSTR alias1 = _T("mysound1");
    	const LPCTSTR alias2 = _T("mysound2");
    	const int volume1 = 20;
    	const int volume2 = 100;
    	CString strCmd;
    	MCIERROR errorCode = 0;
    
    	strCmd.Format(_T("open \"%s\" alias %s type mpegvideo"), filePath1, alias1);
    	errorCode = mciSendString(strCmd, nullptr, 0, nullptr);
    	strCmd.Format(_T("open \"%s\" alias %s type mpegvideo"), filePath2, alias2);
    	errorCode = mciSendString(strCmd, nullptr, 0, nullptr);
    
    	strCmd.Format(_T("setaudio %s volume to %d"), alias1, volume1);
    	errorCode = mciSendString(strCmd, nullptr, 0, nullptr);
    	strCmd.Format(_T("setaudio %s volume to %d"), alias2, volume2);
    	errorCode = mciSendString(strCmd, nullptr, 0, nullptr);
    
    	strCmd.Format(_T("play %s"), alias1);
    	errorCode = mciSendString(strCmd, nullptr, 0, nullptr);
    	strCmd.Format(_T("play %s"), alias2);
    	errorCode = mciSendString(strCmd, nullptr, 0, nullptr);
    
    	// TODO: 停止とクローズ。
    }


    また、"waveOpen"とは何者ですか? waveOutOpen()の間違いではないですか?

    誤:WAVOUTハンドラ

    正:HWAVEOUTハンドル

    説明の際は正確に記述するよう心がけてください。

    なお、以前指摘したことを繰り返しますが、C++ではC言語形式のキャスト構文を使うべきではありません。static_cast, dynamic_cast, reinterpret_cast, const_castについて学習してください。APIの使い方を覚える前に、まずC++の基本や定石について学習することを強く推奨します。

    • 編集済み sygh 2018年5月23日 14:25
    2018年5月23日 14:22