From: Habu Date: Sat, 5 Nov 2022 15:17:46 +0000 (+0900) Subject: [Feature] BGMと効果音の音量設定機能 X-Git-Tag: 3.0.0Alpha71^2~5^2 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=cbdaf3524e9d69aff0fb4f83cae3b1ece7ae70a3;p=hengbandforosx%2Fhengbandosx.git [Feature] BGMと効果音の音量設定機能 BGMと効果音の音量をメニューから設定できる機能を追加する。 それぞれ10%~100%の10%刻みで設定でき、設定内容はINIファイルに保存される。 --- diff --git a/src/ang_eng.rc b/src/ang_eng.rc index 1aba632df..ed2d351fd 100644 --- a/src/ang_eng.rc +++ b/src/ang_eng.rc @@ -127,10 +127,36 @@ ANGBAND MENU MENUITEM SEPARATOR MENUITEM "&Music", 420 + POPUP "Volume" + { + MENUITEM "100%", 460 + MENUITEM "90%", 461 + MENUITEM "80%", 462 + MENUITEM "70%", 463 + MENUITEM "60%", 464 + MENUITEM "50%", 465 + MENUITEM "40%", 466 + MENUITEM "30%", 467 + MENUITEM "20%", 468 + MENUITEM "10%", 469 + } MENUITEM "&Pause music when inactive", 421 MENUITEM "&Open music folder", 422 MENUITEM SEPARATOR MENUITEM "&Sound", 410 + POPUP "Volume" + { + MENUITEM "100%", 470 + MENUITEM "90%", 471 + MENUITEM "80%", 472 + MENUITEM "70%", 473 + MENUITEM "60%", 474 + MENUITEM "50%", 475 + MENUITEM "40%", 476 + MENUITEM "30%", 477 + MENUITEM "20%", 478 + MENUITEM "10%", 479 + } MENUITEM "&Open sound folder", 411 MENUITEM SEPARATOR MENUITEM "&HTML dump", 450 diff --git a/src/ang_jp.rc b/src/ang_jp.rc index 3cc8431af..86e6b9d7a 100644 --- a/src/ang_jp.rc +++ b/src/ang_jp.rc @@ -11,7 +11,7 @@ ANGBAND MENU MENUITEM SEPARATOR MENUITEM "ƒXƒRƒA(&C)", 120 MENUITEM "ƒ€[ƒr[(&M)", 121 - MENUITEM SEPARATOR + MENUITEM SEPARATOR MENUITEM "I—¹(&X)", 130 } @@ -126,10 +126,36 @@ ANGBAND MENU } MENUITEM SEPARATOR MENUITEM "BGM(&M)", 420 + POPUP "‰¹—Ê" + { + MENUITEM "100%", 460 + MENUITEM "90%", 461 + MENUITEM "80%", 462 + MENUITEM "70%", 463 + MENUITEM "60%", 464 + MENUITEM "50%", 465 + MENUITEM "40%", 466 + MENUITEM "30%", 467 + MENUITEM "20%", 468 + MENUITEM "10%", 469 + } MENUITEM "ƒAƒNƒeƒBƒuŽž‚Ì‚ÝBGMÄ¶(&M)", 421 MENUITEM "BGMÝ’èƒtƒHƒ‹ƒ_‚ðŠJ‚­(&O)", 422 MENUITEM SEPARATOR MENUITEM "Œø‰Ê‰¹(&S)", 410 + POPUP "‰¹—Ê" + { + MENUITEM "100%", 470 + MENUITEM "90%", 471 + MENUITEM "80%", 472 + MENUITEM "70%", 473 + MENUITEM "60%", 474 + MENUITEM "50%", 475 + MENUITEM "40%", 476 + MENUITEM "30%", 477 + MENUITEM "20%", 478 + MENUITEM "10%", 479 + } MENUITEM "Œø‰Ê‰¹Ý’èƒtƒHƒ‹ƒ_‚ðŠJ‚­(&P)", 411 MENUITEM SEPARATOR MENUITEM "‰æ–Ê‚ðHTML‚Å•Û‘¶(&H)...", 450 diff --git a/src/game-option/runtime-arguments.cpp b/src/game-option/runtime-arguments.cpp index 7d0461bb1..ec53275bf 100644 --- a/src/game-option/runtime-arguments.cpp +++ b/src/game-option/runtime-arguments.cpp @@ -1,7 +1,9 @@ #include "game-option/runtime-arguments.h" bool arg_sound; /* Command arg -- Request special sounds */ +int arg_sound_volume_table_index; bool arg_music; /* Command arg -- Request special musics */ +int arg_music_volume_table_index; byte arg_graphics; /* Command arg -- Request graphics mode */ bool arg_monochrome; /* Command arg -- Request monochrome mode */ bool arg_force_original; /* Command arg -- Request original keyset */ diff --git a/src/game-option/runtime-arguments.h b/src/game-option/runtime-arguments.h index 4937a32a2..ddc262731 100644 --- a/src/game-option/runtime-arguments.h +++ b/src/game-option/runtime-arguments.h @@ -3,7 +3,9 @@ #include "system/angband.h" extern bool arg_music; +extern int arg_music_volume_table_index; extern bool arg_sound; +extern int arg_sound_volume_table_index; extern byte arg_graphics; extern bool arg_monochrome; extern bool arg_force_original; diff --git a/src/main-win.cpp b/src/main-win.cpp index aca0724b1..f188531ab 100644 --- a/src/main-win.cpp +++ b/src/main-win.cpp @@ -129,6 +129,7 @@ #include "wizard/spoiler-util.h" #include "wizard/wizard-spoiler.h" #include "world/world.h" +#include #include #include #include @@ -405,10 +406,12 @@ static void save_prefs(void) strcpy(buf, arg_sound ? "1" : "0"); WritePrivateProfileStringA("Angband", "Sound", buf, ini_file); + WritePrivateProfileStringA("Angband", "SoundVolumeTableIndex", std::to_string(arg_sound_volume_table_index).data(), ini_file); strcpy(buf, arg_music ? "1" : "0"); WritePrivateProfileStringA("Angband", "Music", buf, ini_file); strcpy(buf, use_pause_music_inactive ? "1" : "0"); + WritePrivateProfileStringA("Angband", "MusicVolumeTableIndex", std::to_string(arg_music_volume_table_index).data(), ini_file); WritePrivateProfileStringA("Angband", "MusicPauseInactive", buf, ini_file); wsprintfA(buf, "%d", current_bg_mode); @@ -507,7 +510,9 @@ static void load_prefs(void) arg_bigtile = (GetPrivateProfileIntA("Angband", "Bigtile", false, ini_file) != 0); use_bigtile = arg_bigtile; arg_sound = (GetPrivateProfileIntA("Angband", "Sound", 0, ini_file) != 0); + arg_sound_volume_table_index = std::clamp(GetPrivateProfileIntA("Angband", "SoundVolumeTableIndex", 0, ini_file), 0, SOUND_VOLUME_TABLE.size() - 1); arg_music = (GetPrivateProfileIntA("Angband", "Music", 0, ini_file) != 0); + arg_music_volume_table_index = std::clamp(GetPrivateProfileIntA("Angband", "MusicVolumeTableIndex", 0, ini_file), 0, main_win_music::VOLUME_TABLE.size() - 1); use_pause_music_inactive = (GetPrivateProfileIntA("Angband", "MusicPauseInactive", 0, ini_file) != 0); current_bg_mode = static_cast(GetPrivateProfileIntA("Angband", "BackGround", 0, ini_file)); GetPrivateProfileStringA("Angband", "BackGroundBitmap", DEFAULT_BG_FILENAME, wallpaper_file, 1023, ini_file); @@ -903,7 +908,7 @@ static errr term_xtra_win_sound(int v) if (!use_sound) { return 1; } - return play_sound(v); + return play_sound(v, SOUND_VOLUME_TABLE[arg_sound_volume_table_index]); } /*! @@ -1522,8 +1527,12 @@ static void setup_menus(void) CheckMenuItem(hm, IDM_OPTIONS_NEW2_GRAPHICS, (arg_graphics == enum2i(graphics_mode::GRAPHICS_HENGBAND) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hm, IDM_OPTIONS_BIGTILE, (arg_bigtile ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hm, IDM_OPTIONS_MUSIC, (arg_music ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuRadioItem(hm, IDM_OPTIONS_MUSIC_VOLUME_100, IDM_OPTIONS_MUSIC_VOLUME_010, + IDM_OPTIONS_MUSIC_VOLUME_100 + arg_music_volume_table_index, MF_BYCOMMAND); CheckMenuItem(hm, IDM_OPTIONS_MUSIC_PAUSE_INACTIVE, (use_pause_music_inactive ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hm, IDM_OPTIONS_SOUND, (arg_sound ? MF_CHECKED : MF_UNCHECKED)); + CheckMenuRadioItem(hm, IDM_OPTIONS_SOUND_VOLUME_100, IDM_OPTIONS_SOUND_VOLUME_010, + IDM_OPTIONS_SOUND_VOLUME_100 + arg_sound_volume_table_index, MF_BYCOMMAND); CheckMenuItem(hm, IDM_OPTIONS_NO_BG, ((current_bg_mode == bg_mode::BG_NONE) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hm, IDM_OPTIONS_BG, ((current_bg_mode == bg_mode::BG_ONE) ? MF_CHECKED : MF_UNCHECKED)); CheckMenuItem(hm, IDM_OPTIONS_PRESET_BG, ((current_bg_mode == bg_mode::BG_PRESET) ? MF_CHECKED : MF_UNCHECKED)); @@ -1870,6 +1879,22 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd) } break; } + case IDM_OPTIONS_MUSIC_VOLUME_100: + case IDM_OPTIONS_MUSIC_VOLUME_090: + case IDM_OPTIONS_MUSIC_VOLUME_080: + case IDM_OPTIONS_MUSIC_VOLUME_070: + case IDM_OPTIONS_MUSIC_VOLUME_060: + case IDM_OPTIONS_MUSIC_VOLUME_050: + case IDM_OPTIONS_MUSIC_VOLUME_040: + case IDM_OPTIONS_MUSIC_VOLUME_030: + case IDM_OPTIONS_MUSIC_VOLUME_020: + case IDM_OPTIONS_MUSIC_VOLUME_010: { + arg_music_volume_table_index = wCmd - IDM_OPTIONS_MUSIC_VOLUME_100; + if (use_music) { + main_win_music::set_music_volume(main_win_music::VOLUME_TABLE[arg_music_volume_table_index]); + } + break; + } case IDM_OPTIONS_MUSIC_PAUSE_INACTIVE: { use_pause_music_inactive = !use_pause_music_inactive; break; @@ -1885,6 +1910,19 @@ static void process_menus(PlayerType *player_ptr, WORD wCmd) change_sound_mode(arg_sound); break; } + case IDM_OPTIONS_SOUND_VOLUME_100: + case IDM_OPTIONS_SOUND_VOLUME_090: + case IDM_OPTIONS_SOUND_VOLUME_080: + case IDM_OPTIONS_SOUND_VOLUME_070: + case IDM_OPTIONS_SOUND_VOLUME_060: + case IDM_OPTIONS_SOUND_VOLUME_050: + case IDM_OPTIONS_SOUND_VOLUME_040: + case IDM_OPTIONS_SOUND_VOLUME_030: + case IDM_OPTIONS_SOUND_VOLUME_020: + case IDM_OPTIONS_SOUND_VOLUME_010: { + arg_sound_volume_table_index = wCmd - IDM_OPTIONS_SOUND_VOLUME_100; + break; + } case IDM_OPTIONS_OPEN_SOUND_DIR: { std::vector buf(MAIN_WIN_MAX_PATH); path_build(&buf[0], MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, "sound.cfg"); @@ -2228,7 +2266,7 @@ LRESULT PASCAL angband_window_procedure(HWND hWnd, UINT uMsg, WPARAM wParam, LPA return 0; } case MM_MCINOTIFY: { - main_win_music::on_mci_notify(wParam, lParam); + main_win_music::on_mci_notify(wParam, lParam, main_win_music::VOLUME_TABLE[arg_music_volume_table_index]); return 0; } diff --git a/src/main-win/main-win-menuitem.h b/src/main-win/main-win-menuitem.h index a360dbdee..79777a718 100644 --- a/src/main-win/main-win-menuitem.h +++ b/src/main-win/main-win-menuitem.h @@ -90,4 +90,26 @@ #define IDM_OPTIONS_PRESET_BG 442 #define IDM_OPTIONS_OPEN_BG 449 +#define IDM_OPTIONS_MUSIC_VOLUME_100 460 +#define IDM_OPTIONS_MUSIC_VOLUME_090 461 +#define IDM_OPTIONS_MUSIC_VOLUME_080 462 +#define IDM_OPTIONS_MUSIC_VOLUME_070 463 +#define IDM_OPTIONS_MUSIC_VOLUME_060 464 +#define IDM_OPTIONS_MUSIC_VOLUME_050 465 +#define IDM_OPTIONS_MUSIC_VOLUME_040 466 +#define IDM_OPTIONS_MUSIC_VOLUME_030 467 +#define IDM_OPTIONS_MUSIC_VOLUME_020 468 +#define IDM_OPTIONS_MUSIC_VOLUME_010 469 + +#define IDM_OPTIONS_SOUND_VOLUME_100 470 +#define IDM_OPTIONS_SOUND_VOLUME_090 471 +#define IDM_OPTIONS_SOUND_VOLUME_080 472 +#define IDM_OPTIONS_SOUND_VOLUME_070 473 +#define IDM_OPTIONS_SOUND_VOLUME_060 474 +#define IDM_OPTIONS_SOUND_VOLUME_050 475 +#define IDM_OPTIONS_SOUND_VOLUME_040 476 +#define IDM_OPTIONS_SOUND_VOLUME_030 477 +#define IDM_OPTIONS_SOUND_VOLUME_020 478 +#define IDM_OPTIONS_SOUND_VOLUME_010 479 + #define IDM_DUMP_SCREEN_HTML 450 diff --git a/src/main-win/main-win-music.cpp b/src/main-win/main-win-music.cpp index e77fc88f0..b68a22bd8 100644 --- a/src/main-win/main-win-music.cpp +++ b/src/main-win/main-win-music.cpp @@ -20,6 +20,9 @@ #include "term/z-term.h" #include "util/angband-files.h" #include "world/world.h" +#include +#include +#include bool use_pause_music_inactive = false; static int current_music_type = TERM_XTRA_MUSIC_MUTE; @@ -243,13 +246,30 @@ errr play_music_scene(int val) return 0; } +void set_music_volume(int volume) +{ + if (current_music_type == TERM_XTRA_MUSIC_MUTE) { + return; + } + + MCI_DGV_SETAUDIO_PARMSW mci_vol{}; + mci_vol.dwItem = MCI_DGV_SETAUDIO_VOLUME; + mci_vol.dwValue = volume; + mciSendCommandW( + mci_open_parms.wDeviceID, + MCI_SETAUDIO, + MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE, + (DWORD)&mci_vol); +} + /* * Notify event */ -void on_mci_notify(WPARAM wFlags, LONG lDevID) +void on_mci_notify(WPARAM wFlags, LONG lDevID, int volume) { if (wFlags == MCI_NOTIFY_SUCCESSFUL) { // play a music (repeat) + set_music_volume(volume); mciSendCommandW(lDevID, MCI_SEEK, MCI_SEEK_TO_START | MCI_WAIT, 0); mciSendCommandW(lDevID, MCI_PLAY, MCI_NOTIFY, (DWORD)&mci_play_parms); } diff --git a/src/main-win/main-win-music.h b/src/main-win/main-win-music.h index 6f05bf8aa..3e09249d0 100644 --- a/src/main-win/main-win-music.h +++ b/src/main-win/main-win-music.h @@ -5,6 +5,7 @@ #include "main/music-definitions-table.h" +#include #include extern bool use_pause_music_inactive; @@ -18,5 +19,9 @@ errr play_music(int type, int val); errr play_music_scene(int val); void pause_music(void); void resume_music(void); -void on_mci_notify(WPARAM wFlags, LONG lDevID); +void set_music_volume(int volume); +void on_mci_notify(WPARAM wFlags, LONG lDevID, int volume); + +/*! 音量 100%,90%,…,10% それぞれに割り当てる実際の値(音量の指定可能範囲:0~1000) */ +constexpr std::array VOLUME_TABLE = { { 1000, 800, 600, 450, 350, 250, 170, 100, 50, 20 } }; } diff --git a/src/main-win/main-win-sound.cpp b/src/main-win/main-win-sound.cpp index 449b3fa8c..8daae3c97 100644 --- a/src/main-win/main-win-sound.cpp +++ b/src/main-win/main-win-sound.cpp @@ -3,6 +3,8 @@ * @brief Windows版固有実装(効果音) */ +#define NOMINMAX + #include "main-win/main-win-sound.h" #include "main-win/main-win-cfg-reader.h" #include "main-win/main-win-define.h" @@ -78,6 +80,51 @@ struct sound_res { std::queue sound_queue; /*! + * @brief PCMデータの振幅を変調する + * + * 引数で与えられたPCMデータの振幅を mult/div 倍に変調する。 + * PCMデータのサンプリングビット数は bits_per_sample 引数で指定する。 + * 変調した値がサンプリングビット数で表現可能な範囲に収まらない場合は表現可能な範囲の最大値/最小値に制限する。 + * サンプリングビット数で有効なのは 8 か 16 のみであり、それ以外の値が指定された場合はなにも行わない。 + * + * @param bits_per_sample PCMデータのサンプリングビット数 (8 or 16) + * @param pcm_buf PCMデータバッファ領域へのポインタ + * @param bufsize PCMデータバッファ領域のサイズ + * @param mult 振幅変調倍率 mult/div の mult + * @param div 振幅変調倍率 mult/div の div + */ +static void modulate_amplitude(int bits_per_sample, BYTE *pcm_buf, size_t bufsize, int mult, int div) +{ + auto modulate = [mult, div](auto sample) { + using sample_t = decltype(sample); + constexpr auto min = std::numeric_limits::min(); + constexpr auto max = std::numeric_limits::max(); + const auto modulated_sample = std::clamp(sample * mult / div, min, max); + return static_cast(modulated_sample); + }; + + switch (bits_per_sample) { + case 8: + for (auto i = 0U; i < bufsize; ++i) { + pcm_buf[i] = modulate(pcm_buf[i]); + } + break; + + case 16: + for (auto i = 0U; i < bufsize; i += 2) { + const auto sample = static_cast((static_cast(pcm_buf[i + 1]) << 8) | static_cast(pcm_buf[i])); + const auto modulated_sample = modulate(sample); + pcm_buf[i + 1] = static_cast(modulated_sample) >> 8; + pcm_buf[i] = static_cast(modulated_sample) & 0xFF; + } + break; + + default: + break; + } +} + +/*! * 効果音の再生と管理キューへの追加. * * @param wf WAVEFORMATEXへのポインタ @@ -86,7 +133,7 @@ std::queue sound_queue; * @retval true 正常に処理された * @retval false 処理エラー */ -static bool add_sound_queue(const WAVEFORMATEX *wf, BYTE *buf, DWORD bufsize) +static bool add_sound_queue(const WAVEFORMATEX *wf, BYTE *buf, DWORD bufsize, int volume) { // 再生完了データをキューから削除する while (!sound_queue.empty()) { @@ -107,6 +154,8 @@ static bool add_sound_queue(const WAVEFORMATEX *wf, BYTE *buf, DWORD bufsize) return false; } + modulate_amplitude(wf->wBitsPerSample, buf, bufsize, volume, SOUND_VOLUME_MAX); + WAVEHDR *wh = &res->wh; wh->lpData = (LPSTR)buf; wh->dwBufferLength = bufsize; @@ -140,7 +189,7 @@ static bool add_sound_queue(const WAVEFORMATEX *wf, BYTE *buf, DWORD bufsize) * @retval true 正常に処理された * @retval false 処理エラー */ -static bool play_sound_impl(char *filename) +static bool play_sound_impl(char *filename, int volume) { wav_reader reader; if (!reader.open(filename)) { @@ -153,7 +202,7 @@ static bool play_sound_impl(char *filename) return false; } - return add_sound_queue(wf, data_buffer, reader.get_data_chunk()->cksize); + return add_sound_queue(wf, data_buffer, reader.get_data_chunk()->cksize, volume); } /*! @@ -204,7 +253,7 @@ void finalize_sound(void) * @retval 1 設定なし * @retval -1 PlaySoundの戻り値が正常終了以外 */ -errr play_sound(int val) +errr play_sound(int val, int volume) { concptr filename = sound_cfg_data->get_rand(TERM_XTRA_SOUND, val); if (!filename) { @@ -214,7 +263,7 @@ errr play_sound(int val) char buf[MAIN_WIN_MAX_PATH]; path_build(buf, MAIN_WIN_MAX_PATH, ANGBAND_DIR_XTRA_SOUND, filename); - if (play_sound_impl(buf)) { + if (play_sound_impl(buf, volume)) { return 0; } diff --git a/src/main-win/main-win-sound.h b/src/main-win/main-win-sound.h index d85701dc5..41e4fa4bb 100644 --- a/src/main-win/main-win-sound.h +++ b/src/main-win/main-win-sound.h @@ -2,10 +2,15 @@ #include "main-win/main-win-cfg-reader.h" #include "system/h-type.h" +#include extern concptr ANGBAND_DIR_XTRA_SOUND; extern CfgData *sound_cfg_data; void load_sound_prefs(void); void finalize_sound(void); -errr play_sound(int val); +errr play_sound(int val, int volume); + +/*! 音量 100%,90%,…,10% それぞれに割り当てる実際の値(効果音の音声データの振幅を volume/SOUND_VOLUME_MAX 倍する) */ +constexpr std::array SOUND_VOLUME_TABLE = { { 1000, 800, 600, 450, 350, 250, 170, 100, 50, 20 } }; +constexpr auto SOUND_VOLUME_MAX = SOUND_VOLUME_TABLE.front();