<ClCompile Include="..\..\src\main-win\commandline-win.cpp" />\r
<ClCompile Include="..\..\src\main-win\graphics-win.cpp" />\r
<ClCompile Include="..\..\src\main-win\main-win-term.cpp" />\r
+ <ClCompile Include="..\..\src\main-win\wav-reader.cpp" />\r
<ClCompile Include="..\..\src\object-enchant\apply-magic-amulet.cpp" />\r
<ClCompile Include="..\..\src\object-enchant\apply-magic-ring.cpp" />\r
<ClCompile Include="..\..\src\object\object-index-list.cpp" />\r
<ClInclude Include="..\..\src\main-win\commandline-win.h" />\r
<ClInclude Include="..\..\src\main-win\graphics-win.h" />\r
<ClInclude Include="..\..\src\main-win\main-win-term.h" />\r
+ <ClInclude Include="..\..\src\main-win\wav-reader.h" />\r
<ClInclude Include="..\..\src\object-enchant\apply-magic-amulet.h" />\r
<ClInclude Include="..\..\src\object-enchant\apply-magic-ring.h" />\r
<ClInclude Include="..\..\src\object\object-index-list.h" />\r
<ClCompile Include="..\..\src\main-win\main-win-term.cpp">\r
<Filter>main-win</Filter>\r
</ClCompile>\r
+ <ClCompile Include="..\..\src\main-win\wav-reader.cpp">\r
+ <Filter>main-win</Filter>\r
+ </ClCompile>\r
</ItemGroup>\r
<ItemGroup>\r
<ClInclude Include="..\..\src\combat\shoot.h">\r
<ClInclude Include="..\..\src\main-win\main-win-term.h">\r
<Filter>main-win</Filter>\r
</ClInclude>\r
+ <ClInclude Include="..\..\src\main-win\wav-reader.h">\r
+ <Filter>main-win</Filter>\r
+ </ClInclude>\r
</ItemGroup>\r
<ItemGroup>\r
<None Include="..\..\src\wall.bmp" />\r
main-win/main-win-term.cpp main-win/main-win-term.h \
main-win/main-win-tokenizer.cpp main-win/main-win-tokenizer.h \
main-win/main-win-utils.cpp main-win/main-win-utils.h \
+ main-win/wav-reader.cpp main-win/wav-reader.h \
wall.bmp \
stdafx.cpp stdafx.h
DeleteObject(hbrYellow);
finalize_bg();
graphic.finalize();
+ finalize_sound();
UnregisterClassW(AppName, hInstance);
if (hIcon)
#include "main-win/main-win-cfg-reader.h"
#include "main-win/main-win-define.h"
#include "main-win/main-win-file-utils.h"
-#include "main-win/main-win-mmsystem.h"
#include "main-win/main-win-utils.h"
+#include "main-win/wav-reader.h"
#include "util/angband-files.h"
#include "main/sound-definitions-table.h"
+#include <memory>
+
+#include <mmsystem.h>
+
/*
* Directory name
*/
CfgData *sound_cfg_data;
/*!
+ * 効果音データ
+ */
+struct sound_res {
+ sound_res(BYTE* _buf)
+ {
+ buf.reset(_buf);
+ }
+ ~sound_res()
+ {
+ dispose();
+ }
+
+ HWAVEOUT hwo = NULL;
+ /*!
+ * PCMデータバッファ
+ */
+ std::unique_ptr<BYTE[]> buf;
+ WAVEHDR wh = { 0 };
+
+ void dispose()
+ {
+ if (hwo != NULL) {
+ ::waveOutReset(hwo);
+ ::waveOutUnprepareHeader(hwo, &wh, sizeof(WAVEHDR));
+ ::waveOutClose(hwo);
+ hwo = NULL;
+ wh.lpData = nullptr;
+ }
+ }
+};
+/*!
+ * 効果音リソースの管理キュー
+ */
+std::queue<sound_res *> sound_queue;
+
+/*!
+ * 効果音の再生と管理キューへの追加.
+ *
+ * @param wf WAVEFORMATEXへのポインタ
+ * @param buf PCMデータバッファ
+ * @param bufsize バッファサイズ
+ * @retval true 正常に処理された
+ * @retval false 処理エラー
+ */
+static bool add_sound_queue(const WAVEFORMATEX *wf, BYTE *buf, DWORD bufsize)
+{
+ while (!sound_queue.empty()) {
+ auto res = sound_queue.front();
+ if (res->hwo == NULL || (res->wh.dwFlags & WHDR_DONE)) {
+ delete res;
+ sound_queue.pop();
+ continue;
+ }
+ break;
+ }
+
+ auto res = new sound_res(buf);
+ sound_queue.push(res);
+
+ MMRESULT mr = ::waveOutOpen(&res->hwo, WAVE_MAPPER, wf, NULL, NULL, CALLBACK_NULL);
+ if (mr != MMSYSERR_NOERROR) {
+ return false;
+ }
+
+ WAVEHDR *wh = &res->wh;
+ wh->lpData = (LPSTR)buf;
+ wh->dwBufferLength = bufsize;
+ wh->dwFlags = 0;
+
+ ::waveOutPrepareHeader(res->hwo, wh, sizeof(WAVEHDR));
+ ::waveOutWrite(res->hwo, wh, sizeof(WAVEHDR));
+
+ return true;
+}
+
+/*!
+ * 指定ファイルを再生する
+ *
+ * @param buf ファイル名
+ * @retval true 正常に処理された
+ * @retval false 処理エラー
+ */
+static bool play_sound_impl(char *filename)
+{
+ wav_reader reader;
+ if (!reader.open(filename))
+ return false;
+ auto wf = reader.get_waveformat();
+
+ auto data_buffer = reader.read_data();
+ if (data_buffer == nullptr)
+ return false;
+
+ return add_sound_queue(wf, data_buffer, reader.get_data_chunk()->cksize);
+}
+
+/*!
* @brief action-valに対応する[Sound]セクションのキー名を取得する
* @param index "term_xtra()"の第2引数action-valに対応する値
* @param buf 使用しない
}
/*!
+ * @brief 効果音の終了処理
+ */
+void finalize_sound(void)
+{
+ while (!sound_queue.empty()) {
+ auto res = sound_queue.front();
+ delete res;
+ sound_queue.pop();
+ }
+}
+
+/*!
* @brief 指定の効果音を鳴らす。
* @param val see sound_type
* @retval 0 正常終了
char buf[MAIN_WIN_MAX_PATH];
path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, filename);
- if (::PlaySoundW(to_wchar(buf).wc_str(), 0, SND_FILENAME | SND_ASYNC)) {
+ if (play_sound_impl(buf)) {
return 0;
}
+
return -1;
}
extern CfgData *sound_cfg_data;
void load_sound_prefs(void);
+void finalize_sound(void);
errr play_sound(int val);
--- /dev/null
+/*!
+ * @file wav-reader.cpp
+ * @brief Windows版固有実装(WAVファイル読込)
+ */
+
+#include "main-win/wav-reader.h"
+#include "main-win/main-win-utils.h"
+
+bool wav_reader::open(char *filename)
+{
+ close();
+
+ this->hmmio = ::mmioOpenW(to_wchar(filename).wc_str(), NULL, MMIO_READ);
+ if (this->hmmio == NULL)
+ return false;
+
+ MMRESULT mmresult;
+ LONG read_size;
+ LONG readed_size;
+
+ this->riff_chunk.fccType = mmioFOURCC('W', 'A', 'V', 'E');
+ mmresult = ::mmioDescend(this->hmmio, &this->riff_chunk, NULL, MMIO_FINDRIFF);
+ if (mmresult != MMSYSERR_NOERROR)
+ return false;
+
+ this->fmt_chunk.ckid = mmioFOURCC('f', 'm', 't', ' ');
+ mmresult = ::mmioDescend(this->hmmio, &this->fmt_chunk, &this->riff_chunk, MMIO_FINDCHUNK);
+ if (mmresult != MMSYSERR_NOERROR)
+ return false;
+
+ if (this->fmt_chunk.cksize > sizeof(this->waveformatex))
+ return false;
+ read_size = this->fmt_chunk.cksize;
+ readed_size = ::mmioRead(this->hmmio, (HPSTR) & this->waveformatex, read_size);
+ if (readed_size != read_size)
+ return false;
+ if (this->waveformatex.wFormatTag != WAVE_FORMAT_PCM)
+ return false;
+ mmresult = ::mmioAscend(this->hmmio, &this->fmt_chunk, 0);
+ if (mmresult != MMSYSERR_NOERROR)
+ return false;
+
+ this->data_chunk.ckid = mmioFOURCC('d', 'a', 't', 'a');
+ mmresult = ::mmioDescend(this->hmmio, &this->data_chunk, &riff_chunk, MMIO_FINDCHUNK);
+ if (mmresult != MMSYSERR_NOERROR)
+ return false;
+
+ this->buffer.reset(new BYTE[data_chunk.cksize]);
+ read_size = this->data_chunk.cksize;
+ readed_size = ::mmioRead(this->hmmio, (HPSTR)this->buffer.get(), read_size);
+ if (readed_size != read_size) {
+ return false;
+ }
+
+ return true;
+}
+
+BYTE *wav_reader::read_data()
+{
+ return this->buffer.release();
+}
+
+void wav_reader::close()
+{
+ if (this->hmmio != NULL) {
+ ::mmioClose(this->hmmio, 0);
+ this->hmmio = NULL;
+ }
+}
--- /dev/null
+#pragma once
+/*!
+ * @file wav-reader.h
+ * @brief Windows版固有実装(WAVファイル読込)ヘッダ
+ */
+
+#include <memory>
+
+#include <windows.h>
+#include <mmsystem.h>
+
+/*!
+ * WAVファイルの読み込み
+ */
+class wav_reader {
+public:
+ wav_reader()
+ : hmmio(NULL)
+ {
+ }
+ ~wav_reader()
+ {
+ close();
+ }
+
+ /*!
+ * WAVファイルを開く
+ *
+ * @param filename
+ * @retval true 正常に処理された
+ * @retval false 処理エラー
+ */
+ bool open(char *filename);
+ /*!
+ * PCMデータ取得
+ * @details 呼び出し元でdelete[]すること
+ * @return PCMデータ
+ */
+ BYTE* read_data();
+ const WAVEFORMATEX *get_waveformat()
+ {
+ return &waveformatex;
+ }
+ const MMCKINFO *get_data_chunk()
+ {
+ return &data_chunk;
+ }
+ void close();
+
+protected:
+ HMMIO hmmio;
+ MMCKINFO riff_chunk{};
+ MMCKINFO fmt_chunk{};
+ WAVEFORMATEX waveformatex{};
+ MMCKINFO data_chunk{};
+ std::unique_ptr<BYTE[]> buffer;
+};