diff --git a/fb2k/foo_input_vgmstream.rc b/fb2k/foo_input_vgmstream.rc index 96edda9a..2bc0b28d 100755 --- a/fb2k/foo_input_vgmstream.rc +++ b/fb2k/foo_input_vgmstream.rc @@ -23,6 +23,7 @@ LANGUAGE LANG_ENGLISH, SUBLANG_NEUTRAL // // Dialog // +//elements: text, id, x, y, width, height [, style [, extended-style]] IDD_CONFIG DIALOGEX 0, 0, 187, 156 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD @@ -40,6 +41,8 @@ BEGIN CONTROL "Loop forever",IDC_LOOP_FOREVER,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,70,77,10 CONTROL "Ignore looping",IDC_IGNORE_LOOP,"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,7,83,77,10 CONTROL "Disable subsongs",IDC_DISABLE_SUBSONGS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,99,87,10 + LTEXT "Downmix",IDC_STATIC,7,115,48,12 + EDITTEXT IDC_DOWNMIX_CHANNELS,52,112,37,14,ES_AUTOHSCROLL END diff --git a/fb2k/foo_prefs.cpp b/fb2k/foo_prefs.cpp index d0cc0c31..72910a06 100755 --- a/fb2k/foo_prefs.cpp +++ b/fb2k/foo_prefs.cpp @@ -20,6 +20,7 @@ static const GUID guid_cfg_LoopCount = { 0xfc8dfd72, 0xfae8, 0x44cc, { 0xbe, 0x9 static const GUID guid_cfg_FadeLength = { 0x61da7ef1, 0x56a5, 0x4368, { 0xae, 0x6, 0xec, 0x6f, 0xd7, 0xe6, 0x15, 0x5d } }; static const GUID guid_cfg_FadeDelay = { 0x73907787, 0xaf49, 0x4659, { 0x96, 0x8e, 0x9f, 0x70, 0xa1, 0x62, 0x49, 0xc4 } }; static const GUID guid_cfg_DisableSubsongs = { 0xa8cdd664, 0xb32b, 0x4a36, { 0x83, 0x07, 0xa0, 0x4c, 0xcd, 0x52, 0xa3, 0x7c } }; +static const GUID guid_cfg_DownmixChannels = { 0x5a0e65dd, 0xeb37, 0x4c67, { 0x9a, 0xb1, 0x3f, 0xb0, 0xc9, 0x7e, 0xb0, 0xe0 } }; static cfg_bool cfg_LoopForever(guid_cfg_LoopForever, DEFAULT_LOOP_FOREVER); static cfg_bool cfg_IgnoreLoop(guid_cfg_IgnoreLoop, DEFAULT_IGNORE_LOOP); @@ -27,6 +28,7 @@ static cfg_string cfg_LoopCount(guid_cfg_LoopCount, DEFAULT_LOOP_COUNT); static cfg_string cfg_FadeLength(guid_cfg_FadeLength, DEFAULT_FADE_SECONDS); static cfg_string cfg_FadeDelay(guid_cfg_FadeDelay, DEFAULT_FADE_DELAY_SECONDS); static cfg_bool cfg_DisableSubsongs(guid_cfg_DisableSubsongs, DEFAULT_DISABLE_SUBSONGS); +static cfg_string cfg_DownmixChannels(guid_cfg_DownmixChannels, DEFAULT_DOWNMIX_CHANNELS); // Needs to be here in rder to access the static config void input_vgmstream::load_settings() @@ -38,6 +40,7 @@ void input_vgmstream::load_settings() loop_forever = cfg_LoopForever; ignore_loop = cfg_IgnoreLoop; disable_subsongs = cfg_DisableSubsongs; + sscanf(cfg_DownmixChannels.get_ptr(),"%d",&downmix_channels); } const char * vgmstream_prefs::get_name() @@ -70,6 +73,8 @@ BOOL vgmstreamPreferences::OnInitDialog(CWindow, LPARAM) CheckDlgButton(IDC_DISABLE_SUBSONGS, cfg_DisableSubsongs?BST_CHECKED:BST_UNCHECKED); + uSetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS, cfg_DownmixChannels); + return TRUE; } @@ -93,6 +98,8 @@ void vgmstreamPreferences::reset() uSetDlgItemText(m_hWnd, IDC_FADE_DELAY_SECONDS, DEFAULT_FADE_DELAY_SECONDS); CheckDlgButton(IDC_DISABLE_SUBSONGS, DEFAULT_DISABLE_SUBSONGS?BST_CHECKED:BST_UNCHECKED); + + uSetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS, DEFAULT_DOWNMIX_CHANNELS); } @@ -107,6 +114,7 @@ void vgmstreamPreferences::apply() double temp_fade_delay_seconds; double temp_loop_count; int consumed; + int temp_downmix_channels; pfc::string buf; buf = uGetDlgItemText(m_hWnd, IDC_FADE_SECONDS); @@ -141,6 +149,18 @@ void vgmstreamPreferences::apply() "Error",MB_OK|MB_ICONERROR); return; } else cfg_FadeDelay = buf.get_ptr(); + + buf = uGetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS); + if (sscanf(buf.get_ptr(),"%d%n",&temp_downmix_channels,&consumed)<1 + || consumed!=strlen(buf.get_ptr()) || + temp_downmix_channels<0) { + uMessageBox(m_hWnd, + "Invalid value for Downmix Channels\n" + "Must be a number greater than or equal to zero", + "Error",MB_OK|MB_ICONERROR); + return; + } else cfg_DownmixChannels = buf.get_ptr(); + } @@ -166,6 +186,9 @@ bool vgmstreamPreferences::HasChanged() if(FadeDelay != uGetDlgItemText(m_hWnd, IDC_FADE_DELAY_SECONDS)) return true; if(LoopCount != uGetDlgItemText(m_hWnd, IDC_LOOP_COUNT)) return true; + pfc::string DownmixChannels(cfg_DownmixChannels); + if(DownmixChannels != uGetDlgItemText(m_hWnd, IDC_DOWNMIX_CHANNELS)) return true; + return FALSE; } diff --git a/fb2k/foo_prefs.h b/fb2k/foo_prefs.h index c5cc6589..77e22662 100755 --- a/fb2k/foo_prefs.h +++ b/fb2k/foo_prefs.h @@ -15,6 +15,7 @@ #define DEFAULT_LOOP_FOREVER false #define DEFAULT_IGNORE_LOOP false #define DEFAULT_DISABLE_SUBSONGS false +#define DEFAULT_DOWNMIX_CHANNELS "8" class vgmstreamPreferences : public CDialogImpl, public preferences_page_instance { public: @@ -42,6 +43,7 @@ public: COMMAND_HANDLER_EX(IDC_FADE_DELAY_SECONDS, EN_CHANGE, OnEditChange) COMMAND_HANDLER_EX(IDC_LOOP_COUNT, EN_CHANGE, OnEditChange) COMMAND_HANDLER_EX(IDC_DISABLE_SUBSONGS, BN_CLICKED, OnEditChange) + COMMAND_HANDLER_EX(IDC_DOWNMIX_CHANNELS, EN_CHANGE, OnEditChange) END_MSG_MAP() private: BOOL OnInitDialog(CWindow, LPARAM); diff --git a/fb2k/foo_vgmstream.cpp b/fb2k/foo_vgmstream.cpp index 12639074..2192f681 100644 --- a/fb2k/foo_vgmstream.cpp +++ b/fb2k/foo_vgmstream.cpp @@ -56,6 +56,7 @@ input_vgmstream::input_vgmstream() { loop_forever = false; ignore_loop = 0; disable_subsongs = false; + downmix_channels = 0; load_settings(); } @@ -228,8 +229,38 @@ bool input_vgmstream::decode_run(audio_chunk & p_chunk,abort_callback & p_abort) } } - bytes = (samples_to_do*vgmstream->channels * sizeof(sample_buffer[0])); - p_chunk.set_data_fixedpoint((char*)sample_buffer, bytes, vgmstream->sample_rate, vgmstream->channels, 16, audio_chunk::g_guess_channel_config(vgmstream->channels)); + /* downmix enabled (foobar refuses to do more than 8 channels) */ + if (downmix_channels > 0 && downmix_channels < vgmstream->channels) { + short temp_buffer[OUTBUF_SIZE]; + int s, ch; + + for (s = 0; s < samples_to_do; s++) { + /* copy channels up to max */ + for (ch = 0; ch < downmix_channels; ch++) { + temp_buffer[s*downmix_channels + ch] = sample_buffer[s*vgmstream->channels + ch]; + } + /* then mix the rest */ + for (ch = downmix_channels; ch < vgmstream->channels; ch++) { + int downmix_ch = ch % downmix_channels; + int new_sample = ((int)temp_buffer[s*downmix_channels + downmix_ch] + (int)sample_buffer[s*vgmstream->channels + ch]); + new_sample = (int)(new_sample * 0.7); /* limit clipping without removing too much loudness... hopefully */ + if (new_sample > 32767) new_sample = 32767; + else if (new_sample < -32768) new_sample = -32768; + temp_buffer[s*downmix_channels + downmix_ch] = (short)new_sample; + } + } + + /* copy back to global buffer... in case of multithreading stuff? */ + memcpy(sample_buffer,temp_buffer, samples_to_do*downmix_channels*sizeof(short)); + + bytes = (samples_to_do*downmix_channels * sizeof(sample_buffer[0])); + p_chunk.set_data_fixedpoint((char*)sample_buffer, bytes, vgmstream->sample_rate, downmix_channels, 16, audio_chunk::g_guess_channel_config(downmix_channels)); + } + else { + bytes = (samples_to_do*vgmstream->channels * sizeof(sample_buffer[0])); + p_chunk.set_data_fixedpoint((char*)sample_buffer, bytes, vgmstream->sample_rate, vgmstream->channels, 16, audio_chunk::g_guess_channel_config(vgmstream->channels)); + } + decode_pos_samples+=samples_to_do; decode_pos_ms=decode_pos_samples*1000LL/vgmstream->sample_rate; @@ -407,7 +438,10 @@ void input_vgmstream::get_subsong_info(t_uint32 p_subsong, pfc::string_base & ti title.set_string(p, e - p); if (!disable_subsongs && infostream && infostream->num_streams > 1) { - sprintf(temp,"#%d",infostream->stream_index); + int info_subsong = infostream->stream_index; + if (info_subsong==0) + info_subsong = 1; + sprintf(temp,"#%d",info_subsong); title += temp; if (infostream->stream_name[0] != '\0') { diff --git a/fb2k/foo_vgmstream.h b/fb2k/foo_vgmstream.h index df347115..ba3eb738 100644 --- a/fb2k/foo_vgmstream.h +++ b/fb2k/foo_vgmstream.h @@ -61,6 +61,7 @@ class input_vgmstream : public input_stubs { bool force_ignore_loop; int ignore_loop; bool disable_subsongs; + int downmix_channels; /* helpers */ VGMSTREAM * init_vgmstream_foo(t_uint32 p_subsong, const char * const filename, abort_callback & p_abort); diff --git a/fb2k/resource.h b/fb2k/resource.h index ec646540..57549610 100755 --- a/fb2k/resource.h +++ b/fb2k/resource.h @@ -14,6 +14,7 @@ #define IDC_THREAD_PRIORITY_TEXT 1007 #define IDC_DEFAULT_BUTTON 1008 #define IDC_DISABLE_SUBSONGS 1009 +#define IDC_DOWNMIX_CHANNELS 1010 // Next default values for new objects //