/* * libopenmpt_plugin_gui.cpp * ------------------------- * Purpose: libopenmpt plugin GUI * Notes : (currently none) * Authors: OpenMPT Devs * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. */ #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #if !defined(WINVER) && !defined(_WIN32_WINDOWS) #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x0501 // _WIN32_WINNT_WINXP #endif #endif #if !defined(MPT_BUILD_RETRO) #if defined(_MSC_VER) #define MPT_WITH_MFC #endif #else #if defined(_WIN32_WINNT) #if (_WIN32_WINNT >= 0x0501) #if defined(_MSC_VER) #define MPT_WITH_MFC #endif #endif #endif #endif #if defined(MPT_WITH_MFC) #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS // Avoid binary bloat from linking unused MFC controls #endif // MPT_WITH_MFC #ifndef NOMINMAX #define NOMINMAX #endif #if !defined(MPT_WITH_MFC) #include #include #include #include #include #endif #if !defined(MPT_WITH_MFC) #include #endif #if defined(MPT_WITH_MFC) #include #include #endif // MPT_WITH_MFC #if defined(MPT_WITH_MFC) #include "resource.h" #endif // MPT_WITH_MFC #include "libopenmpt_plugin_gui.hpp" namespace libopenmpt { namespace plugin { #if defined(MPT_WITH_MFC) class CSettingsApp : public CWinApp { public: BOOL InitInstance() override { if ( !CWinApp::InitInstance() ) { return FALSE; } DllMainAttach(); return TRUE; } int ExitInstance() override { DllMainDetach(); return CWinApp::ExitInstance(); } }; CSettingsApp theApp; class CSettingsDialog : public CDialog { protected: DECLARE_MESSAGE_MAP() libopenmpt_settings * s; CString m_Title; CComboBox m_ComboBoxSamplerate; CComboBox m_ComboBoxChannels; CSliderCtrl m_SliderCtrlGain; CComboBox m_ComboBoxInterpolation; CButton m_CheckBoxAmigaResampler; CComboBox m_ComboBoxAmigaFilter; CComboBox m_ComboBoxRepeat; CSliderCtrl m_SliderCtrlStereoSeparation; CComboBox m_ComboBoxRamping; public: CSettingsDialog( libopenmpt_settings * s_, CString title, CWnd * parent = nullptr ) : CDialog( IDD_SETTINGS, parent ) , s( s_ ) , m_Title( title ) { return; } protected: void DoDataExchange( CDataExchange * pDX ) override { CDialog::DoDataExchange( pDX ); DDX_Control( pDX, IDC_COMBO_SAMPLERATE, m_ComboBoxSamplerate ); DDX_Control( pDX, IDC_COMBO_CHANNELS, m_ComboBoxChannels ); DDX_Control( pDX, IDC_SLIDER_GAIN, m_SliderCtrlGain ); DDX_Control( pDX, IDC_COMBO_INTERPOLATION, m_ComboBoxInterpolation ); DDX_Control( pDX, IDC_CHECK_AMIGA_RESAMPLER, m_CheckBoxAmigaResampler ); DDX_Control( pDX, IDC_COMBO_AMIGA_FILTER, m_ComboBoxAmigaFilter ); DDX_Control( pDX, IDC_COMBO_REPEAT, m_ComboBoxRepeat ); DDX_Control( pDX, IDC_SLIDER_STEREOSEPARATION, m_SliderCtrlStereoSeparation ); DDX_Control( pDX, IDC_COMBO_RAMPING, m_ComboBoxRamping ); } afx_msg BOOL OnInitDialog() override { CDialog::OnInitDialog(); SetWindowText( m_Title ); EnableToolTips(); bool selected = false; selected = false; if ( !s->no_default_format ) { m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"Default" ), 0 ); } m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"6000" ), 6000 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"8000" ), 8000 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"11025" ), 11025 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"16000" ), 16000 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"22050" ), 22050 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"32000" ), 32000 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"44100" ), 44100 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"48000" ), 48000 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"88200" ), 88200 ); m_ComboBoxSamplerate.SetItemData( m_ComboBoxSamplerate.AddString( L"96000" ), 96000 ); if ( !s->no_default_format && s->samplerate == 0 ) { m_ComboBoxSamplerate.SelectString( 0, L"Default" ); } for ( int index = 0; index < m_ComboBoxSamplerate.GetCount(); ++index ) { if ( static_cast( m_ComboBoxSamplerate.GetItemData( index ) ) == s->samplerate ) { m_ComboBoxSamplerate.SetCurSel( index ); selected = true; } } if ( !selected ) { m_ComboBoxSamplerate.SelectString( 0, L"48000" ); } selected = false; if ( !s->no_default_format ) { m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Default" ), 0 ); } m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Mono" ), 1 ); m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Stereo" ), 2 ); m_ComboBoxChannels.SetItemData( m_ComboBoxChannels.AddString( L"Quad" ), 4 ); if ( !s->no_default_format && s->channels == 0 ) { m_ComboBoxChannels.SelectString( 0, L"Default" ); } for ( int index = 0; index < m_ComboBoxChannels.GetCount(); ++index ) { if ( static_cast( m_ComboBoxChannels.GetItemData( index ) ) == s->channels ) { m_ComboBoxChannels.SetCurSel( index ); selected = true; } } if ( !selected ) { m_ComboBoxChannels.SelectString( 0, L"Stereo" ); } m_SliderCtrlGain.SetRange( -1200, 1200 ); m_SliderCtrlGain.SetTicFreq( 100 ); m_SliderCtrlGain.SetPageSize( 300 ); m_SliderCtrlGain.SetLineSize( 100 ); m_SliderCtrlGain.SetPos( s->mastergain_millibel ); selected = false; m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"Off / 1 Tap (Nearest)" ), 1 ); m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"2 Tap (Linear)" ), 2 ); m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"4 Tap (Cubic)" ), 4 ); m_ComboBoxInterpolation.SetItemData( m_ComboBoxInterpolation.AddString( L"8 Tap (Polyphase FIR)" ), 8 ); for ( int index = 0; index < m_ComboBoxInterpolation.GetCount(); ++index ) { if ( static_cast( m_ComboBoxInterpolation.GetItemData( index ) ) == s->interpolationfilterlength ) { m_ComboBoxInterpolation.SetCurSel( index ); selected = true; } } if ( !selected ) { m_ComboBoxInterpolation.SelectString( 0, L"8 Tap (Polyphase FIR)" ); } m_CheckBoxAmigaResampler.SetCheck( s->use_amiga_resampler ? BST_CHECKED : BST_UNCHECKED ); selected = false; m_ComboBoxAmigaFilter.EnableWindow( s->use_amiga_resampler ? TRUE : FALSE ); m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Default" ), 0 ); m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A500 Filter" ), 0xA500 ); m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"A1200 Filter" ), 0xA1200 ); m_ComboBoxAmigaFilter.SetItemData( m_ComboBoxAmigaFilter.AddString( L"Unfiltered" ), 1 ); for ( int index = 0; index < m_ComboBoxAmigaFilter.GetCount(); ++index ) { if ( static_cast( m_ComboBoxAmigaFilter.GetItemData( index ) ) == s->amiga_filter_type ) { m_ComboBoxAmigaFilter.SetCurSel( index ); selected = true; } } if ( !selected ) { m_ComboBoxAmigaFilter.SelectString( 0, L"Default" ); } selected = false; m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Forever" ), static_cast( -1 ) ); m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Never" ), 0 ); m_ComboBoxRepeat.SetItemData( m_ComboBoxRepeat.AddString( L"Once" ), 1 ); for ( int index = 0; index < m_ComboBoxRepeat.GetCount(); ++index ) { if ( static_cast( m_ComboBoxRepeat.GetItemData( index ) ) == s->repeatcount ) { m_ComboBoxRepeat.SetCurSel( index ); selected = true; } } if ( !selected ) { m_ComboBoxRepeat.SelectString( 0, L"Never" ); } m_SliderCtrlStereoSeparation.SetRange( 0, 200 ); m_SliderCtrlStereoSeparation.SetTicFreq( 100 ); m_SliderCtrlStereoSeparation.SetPageSize( 25 ); m_SliderCtrlStereoSeparation.SetLineSize( 5 ); m_SliderCtrlStereoSeparation.SetPos( s->stereoseparation ); selected = false; m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Default" ), static_cast( -1 ) ); m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"Off" ), 0 ); m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"1 ms" ), 1 ); m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"2 ms" ), 2 ); m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"3 ms" ), 3 ); m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"5 ms" ), 5 ); m_ComboBoxRamping.SetItemData( m_ComboBoxRamping.AddString( L"10 ms" ), 10 ); for ( int index = 0; index < m_ComboBoxRamping.GetCount(); ++index ) { if ( static_cast( m_ComboBoxRamping.GetItemData( index ) ) == s->ramping ) { m_ComboBoxRamping.SetCurSel( index ); selected = true; } } if ( !selected ) { m_ComboBoxRamping.SelectString( 0, L"Default" ); } return TRUE; } void OnOK() override { s->samplerate = m_ComboBoxSamplerate.GetItemData( m_ComboBoxSamplerate.GetCurSel() ); s->channels = m_ComboBoxChannels.GetItemData( m_ComboBoxChannels.GetCurSel() ); s->mastergain_millibel = m_SliderCtrlGain.GetPos(); s->interpolationfilterlength = m_ComboBoxInterpolation.GetItemData( m_ComboBoxInterpolation.GetCurSel() ); s->use_amiga_resampler = ( m_CheckBoxAmigaResampler.GetCheck() != BST_UNCHECKED ) ? 1 : 0; s->amiga_filter_type = m_ComboBoxAmigaFilter.GetItemData( m_ComboBoxAmigaFilter.GetCurSel() ); s->repeatcount = m_ComboBoxRepeat.GetItemData( m_ComboBoxRepeat.GetCurSel() ); s->stereoseparation = m_SliderCtrlStereoSeparation.GetPos(); s->ramping = m_ComboBoxRamping.GetItemData( m_ComboBoxRamping.GetCurSel() ); s->changed(); CDialog::OnOK(); } BOOL OnToolTipText( UINT, NMHDR * pNMHDR, LRESULT * pResult ) { TOOLTIPTEXT * pTTT = reinterpret_cast( pNMHDR ); UINT_PTR nID = pNMHDR->idFrom; if( pTTT->uFlags & TTF_IDISHWND ) { // idFrom is actually the HWND of the tool nID = (UINT_PTR)::GetDlgCtrlID((HWND)nID); } switch ( nID ) { case IDC_SLIDER_GAIN: swprintf( pTTT->szText, _countof(pTTT->szText), L"%.02f dB", m_SliderCtrlGain.GetPos() * 0.01f ); break; case IDC_SLIDER_STEREOSEPARATION: swprintf( pTTT->szText, _countof(pTTT->szText), L"%d %%", m_SliderCtrlStereoSeparation.GetPos()); break; default: return FALSE; } *pResult = 0; return TRUE; } void OnAmigaResamplerChanged() { m_ComboBoxAmigaFilter.EnableWindow( IsDlgButtonChecked( IDC_CHECK_AMIGA_RESAMPLER ) != BST_UNCHECKED ? TRUE : FALSE ); } }; BEGIN_MESSAGE_MAP(CSettingsDialog, CDialog) ON_NOTIFY_EX_RANGE(TTN_NEEDTEXT, 0, 0xFFFF, &CSettingsDialog::OnToolTipText) ON_COMMAND( IDC_CHECK_AMIGA_RESAMPLER, &CSettingsDialog::OnAmigaResamplerChanged ) END_MESSAGE_MAP() class CInfoDialog : public CDialog { protected: CString m_Title; CString m_FileInfo; CEdit m_EditFileInfo; public: CInfoDialog( CString title, CString info, CWnd * parent = NULL ) : CDialog( IDD_FILEINFO, parent ) , m_Title( title ) , m_FileInfo( info ) { return; } protected: void DoDataExchange( CDataExchange * pDX ) override { CDialog::DoDataExchange( pDX ); DDX_Control( pDX, IDC_FILEINFO, m_EditFileInfo ); } afx_msg BOOL OnInitDialog() override { if ( !CDialog::OnInitDialog() ) { return false; } SetWindowText( m_Title ); m_EditFileInfo.SetWindowText( m_FileInfo ); return TRUE; } }; #endif // MPT_WITH_MFC #if defined(MPT_WITH_MFC) void gui_edit_settings( libopenmpt_settings * s, HWND parent, std::wstring title ) { AFX_MANAGE_STATE( AfxGetStaticModuleState() ); CSettingsDialog dlg( s, title.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr ); dlg.DoModal(); } void gui_show_file_info( HWND parent, std::wstring title, std::wstring info ) { AFX_MANAGE_STATE( AfxGetStaticModuleState() ); CInfoDialog dlg( title.c_str(), info.c_str(), parent ? CWnd::FromHandle( parent ) : nullptr); dlg.DoModal(); } #else // !MPT_WITH_MFC static std::basic_string GetTempDirectory() { DWORD size = GetTempPath(0, nullptr); if (size) { std::vector tempPath(size + 1); if (GetTempPath(size + 1, tempPath.data())) { return tempPath.data(); } } return {}; } static std::basic_string GetTempFilename( std::basic_string prefix ) { std::vector buf(MAX_PATH); if (GetTempFileName(GetTempDirectory().c_str(), prefix.c_str(), 0, buf.data()) == 0) { return {}; } return buf.data(); } template static std::basic_string as_string( T x ) { std::basic_ostringstream s; s.imbue(std::locale::classic()); s << x; return s.str(); } void gui_edit_settings( libopenmpt_settings * s, HWND /* parent */ , std::basic_string title ) { std::basic_string filename = GetTempFilename( title ); WritePrivateProfileString( title.c_str(), TEXT("Samplerate_Hz"), as_string( s->samplerate ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("Channels"), as_string( s->channels ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("MasterGain_milliBel"), as_string( s->mastergain_millibel ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("StereoSeparation_Percent"), as_string( s->stereoseparation ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("RepeatCount"), as_string( s->repeatcount ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("InterpolationFilterLength"), as_string( s->interpolationfilterlength ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("UseAmigaResampler"), as_string( s->use_amiga_resampler ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("AmigaFilterType"), as_string( s->amiga_filter_type ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("VolumeRampingStrength"), as_string( s->ramping ).c_str(), filename.c_str() ); WritePrivateProfileString( title.c_str(), TEXT("VisAllowScroll"), as_string( s->vis_allow_scroll ).c_str(), filename.c_str() ); STARTUPINFO startupInfo = {}; startupInfo.cb = sizeof(startupInfo); PROCESS_INFORMATION processInformation = {}; std::basic_string command = std::basic_string(TEXT("notepad.exe")) + TEXT(" ") + filename; std::vector commandBuf{ command.c_str(), command.c_str() + command.length() + 1 }; if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) { MessageBox(NULL, as_string(GetLastError()).c_str(), TEXT("fail"), 0); return; } CloseHandle( processInformation.hThread ); WaitForSingleObject( processInformation.hProcess, INFINITE ); CloseHandle( processInformation.hProcess ); s->samplerate = GetPrivateProfileInt( title.c_str(), TEXT("Samplerate_Hz"), libopenmpt_settings{}.samplerate, filename.c_str() ); s->channels = GetPrivateProfileInt( title.c_str(), TEXT("Channels"), libopenmpt_settings{}.channels, filename.c_str() ); s->mastergain_millibel = GetPrivateProfileInt( title.c_str(), TEXT("MasterGain_milliBel"), libopenmpt_settings{}.mastergain_millibel, filename.c_str() ); s->stereoseparation = GetPrivateProfileInt( title.c_str(), TEXT("StereoSeparation_Percent"), libopenmpt_settings{}.stereoseparation, filename.c_str() ); s->repeatcount = GetPrivateProfileInt( title.c_str(), TEXT("RepeatCount"), libopenmpt_settings{}.repeatcount, filename.c_str() ); s->interpolationfilterlength = GetPrivateProfileInt( title.c_str(), TEXT("InterpolationFilterLength"), libopenmpt_settings{}.interpolationfilterlength, filename.c_str() ); s->use_amiga_resampler = GetPrivateProfileInt( title.c_str(), TEXT("UseAmigaResampler"), libopenmpt_settings{}.use_amiga_resampler, filename.c_str() ); s->amiga_filter_type = GetPrivateProfileInt( title.c_str(), TEXT("AmigaFilterType"), libopenmpt_settings{}.amiga_filter_type, filename.c_str() ); s->ramping = GetPrivateProfileInt( title.c_str(), TEXT("VolumeRampingStrength"), libopenmpt_settings{}.ramping, filename.c_str() ); s->vis_allow_scroll = GetPrivateProfileInt( title.c_str(), TEXT("VisAllowScroll"), libopenmpt_settings{}.vis_allow_scroll, filename.c_str() ); DeleteFile( filename.c_str() ); } void gui_show_file_info( HWND /* parent */ , std::basic_string title, std::basic_string info ) { std::basic_string filename = GetTempFilename( title ); { std::basic_ofstream f( filename.c_str(), std::ios::out ); f << info; } STARTUPINFO startupInfo = {}; startupInfo.cb = sizeof(startupInfo); PROCESS_INFORMATION processInformation = {}; std::basic_string command = std::basic_string(TEXT("notepad.exe")) + TEXT(" ") + filename; std::vector commandBuf{ command.c_str(), command.c_str() + command.length() + 1 }; if ( CreateProcess( NULL, commandBuf.data(), NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInformation ) == FALSE ) { return; } CloseHandle( processInformation.hThread ); WaitForSingleObject( processInformation.hProcess, INFINITE ); CloseHandle( processInformation.hProcess ); DeleteFile( filename.c_str() ); } #endif // MPT_WITH_MFC } // namespace plugin } // namespace libopenmpt