#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 (::PlaySoundA(buf, 0, SND_FILENAME | SND_ASYNC)) {
+ if (play_sound_impl(buf)) {
return 0;
}
+
return -1;
}