スマホアプリやUWPがトレンドの中、C++習得のために時代遅れ感のあるWindows
デスクトップアプリをコツコツとコーディングしています。
DS8.h
► スポイラーを表示
//***********************************************************
// DS8.h for Windows application 2017.11.03 by V30
//***********************************************************
#pragma once
#include
#include
#include
#include
#pragma comment(lib, "dsound.lib")
//DS8名前空間
namespace DS8
{
using namespace Microsoft::WRL;
using namespace std;
//DSデバイスインスタンス構造体
struct DSDEVICEINSTANCE
{
LPGUID guid; //GUID
LPCTSTR desc; //Description
LPCTSTR module; //Module
//既定コンストラクタ
DSDEVICEINSTANCE();
//コンストラクタ
DSDEVICEINSTANCE(LPGUID guid, LPCTSTR desc, LPCTSTR module);
};
//DS8デバイスインターフェイス作成
HRESULT CreateDS8Device(const HWND &window, const DSDEVICEINSTANCE &deviceinstance, ComPtr &ds8device);
ComPtr CreateDS8Device(const HWND &window, const DSDEVICEINSTANCE &deviceinstance);
HRESULT CreateDS8Device(const HWND &window, LPCGUID guid, ComPtr &ds8device);
ComPtr CreateDS8Device(const HWND &window, LPCGUID guid);
//DS8デバイスインターフェイス配列作成
size_t CreateDS8Device(const HWND &window, const vector &deviceinstance, vector> &ds8device);
vector> CreateDS8Device(const HWND &window, const vector &deviceinstance);
size_t CreateDS8Device(const HWND &window, vector> &ds8device);
vector> CreateDS8Device(const HWND &window);
//DS8セカンダリバッファインターフェイス作成
HRESULT CreateDS8Buffer8(const ComPtr &ds8device, const DSBUFFERDESC &dsbdesc, ComPtr &buffer);
ComPtr CreateDS8Buffer8(const ComPtr &ds8device, const DSBUFFERDESC &dsbdesc);
HRESULT CreateDS8Buffer8(const ComPtr &ds8device, const WAVEFORMATEX &waveformatex, const DWORD &buffersize, const BOOL &glovalfocus, ComPtr &buffer);
ComPtr CreateDS8Buffer8(const ComPtr &ds8device, const WAVEFORMATEX &waveformatex, const DWORD &buffersize, const BOOL &glovalfocus);
//DS8デバイスインスタンス列挙
size_t EnumDS8Device(vector &deviceinstance);
vector EnumDS8Device();
//DS8デバイスインスタンス列挙コールバック
BOOL CALLBACK DS8DeviceEnumCallback(LPGUID guid, LPCTSTR desc, LPCTSTR module, LPVOID context);
//DS8バッファ波形データロード
HRESULT LoadWaveDataIntoDS8Buffer8(const ComPtr &buffer, const DWORD &bufferoffset, const BYTE *wavedata, const DWORD &length);
HRESULT LoadWaveDataIntoDS8Buffer8(const ComPtr &buffer, const DWORD &bufferoffset, const unique_ptr &wavedata, const DWORD &length);
}
► スポイラーを表示
#include
namespace DS8
{
//DSデバイスインスタンス構造体
DSDEVICEINSTANCE::DSDEVICEINSTANCE() :
guid (nullptr), //GUID
desc (nullptr), //Description
module (nullptr) //Module
{}
DSDEVICEINSTANCE::DSDEVICEINSTANCE(LPGUID guid, LPCTSTR desc, LPCTSTR module) :
guid (guid), //GUID
desc (desc), //Description
module (module) //Module
{}
//DS8デバイスインターフェイス作成
HRESULT CreateDS8Device(const HWND &window, const DSDEVICEINSTANCE &deviceinstance, ComPtr &ds8device)
{
ComPtr ds8; //DS8デバイス
HRESULT hr(DirectSoundCreate8(deviceinstance.guid, &ds8, NULL)); //DS8デバイス作成
if SUCCEEDED(hr) hr = ds8device->SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
if SUCCEEDED(hr) ds8device.Swap(ds8); //引数とスワップ
return hr; //結果返還
}
ComPtr CreateDS8Device(const HWND &window, const DSDEVICEINSTANCE &deviceinstance)
{
ComPtr ds8; //DS8デバイス
HRESULT hr(DirectSoundCreate8(deviceinstance.guid, &ds8, NULL)); //DS8デバイス作成
if SUCCEEDED(hr) hr = ds8->SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
return ds8; //結果返還
}
HRESULT CreateDS8Device(const HWND &window, LPCGUID guid, ComPtr &ds8device)
{
ComPtr ds8; //DS8デバイス
HRESULT hr(DirectSoundCreate8(guid, &ds8, NULL)); //DS8デバイス作成
if SUCCEEDED(hr) hr = ds8device->SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
if SUCCEEDED(hr) ds8device.Swap(ds8); //引数とスワップ
return hr; //結果返還
}
ComPtr CreateDS8Device(const HWND &window, LPCGUID guid)
{
ComPtr ds8; //DS8デバイス
HRESULT hr(DirectSoundCreate8(guid, &ds8, NULL)); //DS8デバイス作成
if SUCCEEDED(hr) hr = ds8->SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
return ds8; //結果返還
}
//DS8デバイスインターフェイス配列作成
size_t CreateDS8Device(const HWND &window, const vector &deviceinstance, vector> &ds8device)
{
ComPtr ds8; //DS8デバイス
vector> devices; //DS8デバイス配列
HRESULT hr(E_FAIL); //結果
for (size_t i(0); i SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
if SUCCEEDED(hr) devices.push_back(ds8); //要素追加
}
ds8device.swap(devices); //データスワップ
return ds8device.size(); //デバイス作成数返還
}
vector> CreateDS8Device(const HWND &window, const vector &deviceinstance)
{
ComPtr ds8; //DS8デバイス
vector> devices; //DS8デバイス配列
HRESULT hr(E_FAIL); //結果
for (size_t i(0); i SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
if SUCCEEDED(hr) devices.push_back(ds8); //要素追加
}
return devices; //DS8デバイス配列返還
}
size_t CreateDS8Device(const HWND &window, vector> &ds8device)
{
vector enumdevice; //DS8列挙デバイス
ComPtr ds8; //DS8デバイス
vector> devices; //DS8デバイス配列
HRESULT hr(E_FAIL); //結果
for (size_t i(0); i SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
if SUCCEEDED(hr) devices.push_back(ds8); //要素追加
}
ds8device.swap(devices); //データスワップ
return ds8device.size(); //デバイス作成数返還
}
vector> CreateDS8Device(const HWND &window)
{
vector enumdevice; //DS8列挙デバイス
ComPtr ds8; //DS8デバイス
vector> devices; //DS8デバイス配列
HRESULT hr(E_FAIL); //結果
for (size_t i(0); i SetCooperativeLevel(window, DSSCL_PRIORITY); //協調レベル設定
if SUCCEEDED(hr) devices.push_back(ds8); //要素追加
}
return devices; //DS8デバイス配列返還
}
//DS8セカンダリバッファインターフェイス作成
HRESULT CreateDS8Buffer8(const ComPtr &ds8device, const DSBUFFERDESC &dsbdesc, ComPtr &buffer)
{
if (!ds8device.Get() || dsbdesc.dwBufferBytes DSBSIZE_MAX) return E_FAIL; //引数チェック
ComPtr primery; //プライマリバッファ
ComPtr secondary; //セカンダリバッファ
HRESULT hr(ds8device->CreateSoundBuffer(&dsbdesc, &primery, NULL)); //プライマリバッファ作成
if SUCCEEDED(hr) hr = primery->QueryInterface(IID_IDirectSoundBuffer8, &secondary); //セカンダリバッファ作成
if SUCCEEDED(hr) buffer.Swap(secondary); //引数とスワップ
return hr; //結果返還
}
ComPtr CreateDS8Buffer8(const ComPtr &ds8device, const DSBUFFERDESC &dsbdesc)
{
if (!ds8device.Get() || dsbdesc.dwBufferBytes DSBSIZE_MAX) return nullptr; //引数チェック
ComPtr primery; //プライマリバッファ
ComPtr secondary; //セカンダリバッファ
HRESULT hr(ds8device->CreateSoundBuffer(&dsbdesc, &primery, NULL)); //プライマリバッファ作成
if SUCCEEDED(hr) hr = primery->QueryInterface(IID_IDirectSoundBuffer8, &secondary); //セカンダリバッファ作成
return secondary; //結果返還
}
HRESULT CreateDS8Buffer8(const ComPtr &ds8device, const WAVEFORMATEX &waveformatex, const DWORD &buffersize, const BOOL &glovalfocus, ComPtr &buffer)
{
if (!ds8device.Get() || buffersize DSBSIZE_MAX) return E_FAIL; //引数チェック
ComPtr primery; //プライマリバッファ
ComPtr secondary; //セカンダリバッファ
DSBUFFERDESC dsbdesc = { 0 }; //バッファ説明
WAVEFORMATEX format (waveformatex); //WAVEFORMATEX構造体データ
//DSバッファプロパティ設定
dsbdesc.dwSize = sizeof(DSBUFFERDESC); //プロパティサイズ
dsbdesc.dwBufferBytes = buffersize; //バッファサイズ
dsbdesc.dwFlags |= DSBCAPS_CTRLFREQUENCY; //周波数制御
dsbdesc.dwFlags |= DSBCAPS_CTRLPAN; //パン制御
dsbdesc.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY; //カーソル位置通知制御
dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; //音量制御
dsbdesc.dwFlags |= DSBCAPS_GETCURRENTPOSITION2; //エミュレートバッファ時のカーソル位置正確取得
dsbdesc.dwFlags |= DSBCAPS_LOCDEFER; //ソフト・ハード自動リソース割り当て
dsbdesc.lpwfxFormat = &format; //WAVEFORMATEX構造体ポインタ
if (glovalfocus) dsbdesc.dwFlags |= DSBCAPS_GLOBALFOCUS; //グローバル再生フォーカス
HRESULT hr(ds8device->CreateSoundBuffer(&dsbdesc, &primery, NULL)); //プライマリバッファ作成
if SUCCEEDED(hr) hr = primery->QueryInterface(IID_IDirectSoundBuffer8, &secondary); //セカンダリバッファ作成
if SUCCEEDED(hr) buffer.Swap(secondary); //引数とスワップ
return hr; //結果返還
}
ComPtr CreateDS8Buffer8(const ComPtr &ds8device, const WAVEFORMATEX &waveformatex, const DWORD &buffersize, const BOOL &glovalfocus)
{
if (!ds8device.Get() || buffersize DSBSIZE_MAX) return nullptr; //引数チェック
ComPtr primery; //プライマリバッファ
ComPtr secondary; //セカンダリバッファ
DSBUFFERDESC dsbdesc = { 0 }; //バッファ説明
WAVEFORMATEX format (waveformatex); //WAVEFORMATEX構造体データ
//DSバッファプロパティ設定
dsbdesc.dwSize = sizeof(DSBUFFERDESC); //プロパティサイズ
dsbdesc.dwBufferBytes = buffersize; //バッファサイズ
dsbdesc.dwFlags |= DSBCAPS_CTRLFREQUENCY; //周波数制御
dsbdesc.dwFlags |= DSBCAPS_CTRLPAN; //パン制御
dsbdesc.dwFlags |= DSBCAPS_CTRLPOSITIONNOTIFY; //カーソル位置通知制御
dsbdesc.dwFlags |= DSBCAPS_CTRLVOLUME; //音量制御
dsbdesc.dwFlags |= DSBCAPS_GETCURRENTPOSITION2; //エミュレートバッファ時のカーソル位置正確取得
dsbdesc.dwFlags |= DSBCAPS_LOCDEFER; //ソフト・ハード自動リソース割り当て
dsbdesc.lpwfxFormat = &format; //WAVEFORMATEX構造体ポインタ
if (glovalfocus) dsbdesc.dwFlags |= DSBCAPS_GLOBALFOCUS; //グローバル再生フォーカス
HRESULT hr(ds8device->CreateSoundBuffer(&dsbdesc, &primery, NULL)); //プライマリバッファ作成
if SUCCEEDED(hr) hr = primery->QueryInterface(IID_IDirectSoundBuffer8, &secondary); //セカンダリバッファ作成
return secondary; //結果返還
}
//DS8デバイスインスタンス列挙
size_t EnumDS8Device(vector &deviceinstance)
{
vector instance; //DS8デバイスインスタンス配列
DirectSoundEnumerate(DS8DeviceEnumCallback, (LPVOID)&instance); //DS8デバイスインスタンス列挙コールバック
if (instance.size()) deviceinstance.swap(instance); //引数とスワップ
return instance.size(); //列挙サイズ返還
}
vector EnumDS8Device()
{
vector deviceinstance; //DS8デバイスインスタンス
DirectSoundEnumerate(DS8DeviceEnumCallback, (LPVOID)&deviceinstance); //DS8デバイスインスタンス列挙コールバック
return deviceinstance; //DS8デバイスインスタンス返還
}
//DS8デバイスインスタンス列挙コールバック
BOOL CALLBACK DS8DeviceEnumCallback(LPGUID guid, LPCTSTR desc, LPCTSTR module, LPVOID context)
{
((vector*)context)->push_back(DSDEVICEINSTANCE(guid, desc, module)); //列挙デバイス保存
return TRUE; //デバイス列挙継続
}
//DS8バッファ波形データロード
HRESULT LoadWaveDataIntoDS8Buffer8(const ComPtr &buffer, const DWORD &bufferoffset, const BYTE *wavedata, const DWORD &length)
{
if (!buffer.Get() || !wavedata || !length) return E_FAIL; //引数エラーチェック
DWORD length1 (0); //波形データ書き込みサイズ1
DWORD length2 (0); //波形データ書き込みサイズ2
LPVOID offset1 (nullptr); //波形データ書き込み位置1
LPVOID offset2 (nullptr); //波形データ書き込み位置2
HRESULT hr(buffer->Lock(bufferoffset, length, &offset1, &length1, &offset2, &length2, NULL)); //ロック
if (hr == DSERR_BUFFERLOST)
{
hr = buffer->Restore(); //復元
if SUCCEEDED(hr) hr = buffer->Lock(bufferoffset, length, &offset1, &length1, &offset2, &length2, NULL); //ロック
}
if SUCCEEDED(hr)
{
if (offset1) memcpy(offset1, wavedata , length1); //波形データ書き込み1
if (offset2) memcpy(offset2, wavedata + length1, length2); //波形データ書き込み2
hr = buffer->Unlock(offset1, length1, offset2, length2); //ロック解除
}
return hr; //結果返還
}
HRESULT LoadWaveDataIntoDS8Buffer8(const ComPtr &buffer, const DWORD &bufferoffset, const unique_ptr &wavedata, const DWORD &length)
{
if (!buffer.Get() || !wavedata || !length) return E_FAIL; //引数エラーチェック
DWORD length1 (0); //波形データ書き込みサイズ1
DWORD length2 (0); //波形データ書き込みサイズ2
LPVOID offset1 (nullptr); //波形データ書き込み位置1
LPVOID offset2 (nullptr); //波形データ書き込み位置2
HRESULT hr(buffer->Lock(bufferoffset, length, &offset1, &length1, &offset2, &length2, NULL)); //ロック
if (hr == DSERR_BUFFERLOST)
{
hr = buffer->Restore(); //復元
if SUCCEEDED(hr) hr = buffer->Lock(bufferoffset, length, &offset1, &length1, &offset2, &length2, NULL); //ロック
}
if SUCCEEDED(hr)
{
if (offset1) memcpy(offset1, wavedata.get() , length1); //波形データ書き込み1
if (offset2) memcpy(offset2, wavedata.get() + length1, length2); //波形データ書き込み2
hr = buffer->Unlock(offset1, length1, offset2, length2); //ロック解除
}
return hr; //結果返還
}
}
ライブラリの部品なので、インクルードヘッダが足りなくてこのままでは動かないかも知れません。
特別間違ったコードは書いていないと思いますが、ご指摘があればありがたいです。
既存の構造体があるかも知れませんが、DSDEVICEINSTANCE構造体はサウンドデバイス列挙用に
作りました。
moduleは変数名としてNGワードっぽいですね。VSコンパイラは問題なく動くので、ずっと気付
かずに今まで生きてきました。これからも気づかないフリはダメかな?
関数は、2段ずつ同じような内容の物が並んでいます。ComPtrを返すものは最近付け加えました。
その際、元々COMの QueryInterface メソッドや ComPtr::As メソッド等で書いていた
内容を operator= ではなく、より直接的な ComPtr::Swap に変更しました。
AsもSwapも実質変わらない気がしますが、2関数の内容の整合性を保ちたいと思いました。
今気が付きましたが、波形データロード関数は、引数lengthの上限をチェックしていませんね。
呼び出し側でlengthの値を間違える事はないハズですが、堅牢ではありませんね。
バッファサイズをMaxにして判定すれば良いだけですね。
IDirectSoundBuffer8::Lockメソッドが上手く処理してくれるなら、このまま放置OKなのかな?
あと、unique_ptr型の他に、配列サイズの取得が明瞭な vector型などでもOKな
気がします。
そういやfstreamからはunique_ptr型変数を作って間接的に波形データを転送しています
が、直接転送もできそうな気がしてきました。まだまだ勉強不足だなぁ。。。
それにしても、実際はサウンドプレイヤークラスを作って同様の関数をメンバ宣言しているから、
このファイル達、実質不要の産物ですわ。
でも、DirectSound8利用クラス作成時のコピペ用に取っておきます。
また何か思い付いたら書きます。