diff options
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/OPLInstrDlg.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/mptrack/OPLInstrDlg.cpp | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/OPLInstrDlg.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/OPLInstrDlg.cpp new file mode 100644 index 00000000..782dae3c --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/mptrack/OPLInstrDlg.cpp @@ -0,0 +1,277 @@ +/* + * OPLInstrDlg.cpp + * --------------- + * Purpose: Editor for OPL-based synth instruments + * Notes : (currently none) + * Authors: OpenMPT Devs + * The OpenMPT source code is released under the BSD license. Read LICENSE for more details. + */ + +#include "stdafx.h" +#include "OPLInstrDlg.h" +#include "../soundlib/OPL.h" +#include "../soundlib/Sndfile.h" +#include "resource.h" +#include "Mainfrm.h" + +OPENMPT_NAMESPACE_BEGIN + +BEGIN_MESSAGE_MAP(OPLInstrDlg, CDialog) + ON_WM_HSCROLL() + ON_MESSAGE(WM_MOD_DRAGONDROPPING, &OPLInstrDlg::OnDragonDropping) + ON_COMMAND(IDC_CHECK1, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK2, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK3, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK4, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK5, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK6, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK7, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK8, &OPLInstrDlg::ParamsChanged) + ON_COMMAND(IDC_CHECK9, &OPLInstrDlg::ParamsChanged) + ON_CBN_SELCHANGE(IDC_COMBO1, &OPLInstrDlg::ParamsChanged) + ON_CBN_SELCHANGE(IDC_COMBO2, &OPLInstrDlg::ParamsChanged) + ON_NOTIFY_EX(TTN_NEEDTEXT, 0, &OPLInstrDlg::OnToolTip) +END_MESSAGE_MAP() + + +void OPLInstrDlg::DoDataExchange(CDataExchange *pDX) +{ + CDialog::DoDataExchange(pDX); + DDX_Control(pDX, IDC_CHECK1, m_additive); + DDX_Control(pDX, IDC_SLIDER1, m_feedback); + + for(int op = 0; op < 2; op++) + { + const int slider = op * 7; + const int check = op * 4; + DDX_Control(pDX, IDC_SLIDER2 + slider, m_attackRate[op]); + DDX_Control(pDX, IDC_SLIDER3 + slider, m_decayRate[op]); + DDX_Control(pDX, IDC_SLIDER4 + slider, m_sustainLevel[op]); + DDX_Control(pDX, IDC_SLIDER5 + slider, m_releaseRate[op]); + DDX_Control(pDX, IDC_CHECK2 + check, m_sustain[op]); + DDX_Control(pDX, IDC_SLIDER6 + slider, m_volume[op]); + DDX_Control(pDX, IDC_CHECK3 + check, m_scaleEnv[op]); + DDX_Control(pDX, IDC_SLIDER7 + slider, m_levelScaling[op]); + DDX_Control(pDX, IDC_SLIDER8 + slider, m_freqMultiplier[op]); + DDX_Control(pDX, IDC_COMBO1 + op, m_waveform[op]); + DDX_Control(pDX, IDC_CHECK4 + check, m_vibrato[op]); + DDX_Control(pDX, IDC_CHECK5 + check, m_tremolo[op]); + } +} + + +OPLInstrDlg::OPLInstrDlg(CWnd &parent, const CSoundFile &sndFile) + : m_parent(parent) + , m_sndFile(sndFile) +{ + Create(IDD_OPL_PARAMS, &parent); + CRect rect; + GetClientRect(rect); + m_windowSize = rect.BottomRight(); +} + + +OPLInstrDlg::~OPLInstrDlg() +{ + DestroyWindow(); +} + + +BOOL OPLInstrDlg::OnInitDialog() +{ + CDialog::OnInitDialog(); + EnableToolTips(); + m_feedback.SetRange(0, 7); + for(int op = 0; op < 2; op++) + { + m_attackRate[op].SetRange(0, 15); + m_decayRate[op].SetRange(0, 15); + m_sustainLevel[op].SetRange(0, 15); + m_releaseRate[op].SetRange(0, 15); + m_volume[op].SetRange(0, 63); + m_volume[op].SetTicFreq(4); + m_levelScaling[op].SetRange(0, 3); + m_freqMultiplier[op].SetRange(0, 15); + } + + return TRUE; +} + + +BOOL OPLInstrDlg::PreTranslateMessage(MSG *pMsg) +{ + if(pMsg) + { + // Forward key presses and drag&drop support to parent editor + if(pMsg->message == WM_SYSKEYUP || pMsg->message == WM_KEYUP || + pMsg->message == WM_SYSKEYDOWN || pMsg->message == WM_KEYDOWN || + pMsg->message == WM_DROPFILES) + { + if(pMsg->hwnd == m_hWnd) + { + pMsg->hwnd = m_parent.m_hWnd; + } + if(m_parent.PreTranslateMessage(pMsg)) + { + return TRUE; + } + } else if(pMsg->message == WM_CHAR) + { + // Avoid Windows sounds on note key repeats + if(HIWORD(pMsg->lParam) & 0x4000) + return TRUE; + } + } + return CDialog::PreTranslateMessage(pMsg); +} + + +LRESULT OPLInstrDlg::OnDragonDropping(WPARAM wParam, LPARAM lParam) +{ + return m_parent.SendMessage(WM_MOD_DRAGONDROPPING, wParam, lParam); +} + + +// Swap OPL Key Scale Level bits for a "human-readable" value. +static uint8 KeyScaleLevel(uint8 kslVolume) +{ + static constexpr uint8 KSLFix[4] = { 0x00, 0x80, 0x40, 0xC0 }; + return KSLFix[kslVolume >> 6]; +} + + +void OPLInstrDlg::SetPatch(OPLPatch &patch) +{ + SetRedraw(FALSE); + + m_additive.SetCheck((patch[10] & OPL::CONNECTION_BIT) ? BST_CHECKED : BST_UNCHECKED); + m_feedback.SetPos((patch[10] & OPL::FEEDBACK_MASK) >> 1); + for(int op = 0; op < 2; op++) + { + m_attackRate[op].SetPos(15 - (patch[4 + op] >> 4)); + m_decayRate[op].SetPos(15 - (patch[4 + op] & 0x0F)); + m_sustainLevel[op].SetPos(15 - (patch[6 + op] >> 4)); + m_releaseRate[op].SetPos(15 - (patch[6 + op] & 0x0F)); + m_volume[op].SetPos(63 - (patch[2 + op] & OPL::TOTAL_LEVEL_MASK)); + m_levelScaling[op].SetPos(KeyScaleLevel(patch[2 + op]) >> 6); + m_freqMultiplier[op].SetPos(patch[0 + op] & OPL::MULTIPLE_MASK); + + m_sustain[op].SetCheck((patch[0 + op] & OPL::SUSTAIN_ON) ? BST_CHECKED : BST_UNCHECKED); + m_scaleEnv[op].SetCheck((patch[0 + op] & OPL::KSR) ? BST_CHECKED : BST_UNCHECKED); + m_vibrato[op].SetCheck((patch[0 + op] & OPL::VIBRATO_ON) ? BST_CHECKED : BST_UNCHECKED); + m_tremolo[op].SetCheck((patch[0 + op] & OPL::TREMOLO_ON) ? BST_CHECKED : BST_UNCHECKED); + + const auto waveform = patch[8 + op]; + const int numWaveforms = (m_sndFile.GetType() == MOD_TYPE_S3M && waveform < 4) ? 4 : 8; + if(numWaveforms != m_waveform[op].GetCount()) + { + m_waveform[op].ResetContent(); + static constexpr const TCHAR *waveformNames[] = + { + _T("Sine"), _T("Half Sine"), _T("Absolute Sine"), _T("Pulse Sine"), + _T("Sine (Even Periods)"), _T("Absolute Sine (Even Periods)"), _T("Square"), _T("Derived Square") + }; + for(int i = 0; i < numWaveforms; i++) + { + m_waveform[op].AddString(waveformNames[i]); + } + } + m_waveform[op].SetCurSel(waveform); + } + SetRedraw(TRUE); + m_patch = &patch; +} + + +void OPLInstrDlg::ParamsChanged() +{ + OPLPatch patch{{}}; + if(m_additive.GetCheck() != BST_UNCHECKED) patch[10] |= OPL::CONNECTION_BIT; + patch[10] |= static_cast<uint8>(m_feedback.GetPos() << 1); + for(int op = 0; op < 2; op++) + { + patch[op] = static_cast<uint8>(m_freqMultiplier[op].GetPos()); + if(m_sustain[op].GetCheck() != BST_UNCHECKED) patch[op] |= OPL::SUSTAIN_ON; + if(m_scaleEnv[op].GetCheck() != BST_UNCHECKED) patch[op] |= OPL::KSR; + if(m_vibrato[op].GetCheck() != BST_UNCHECKED) patch[op] |= OPL::VIBRATO_ON; + if(m_tremolo[op].GetCheck() != BST_UNCHECKED) patch[op] |= OPL::TREMOLO_ON; + patch[2 + op] = static_cast<uint8>((63 - m_volume[op].GetPos()) | KeyScaleLevel(static_cast<uint8>(m_levelScaling[op].GetPos() << 6))); + patch[4 + op] = static_cast<uint8>(((15 - m_attackRate[op].GetPos()) << 4) | (15 - m_decayRate[op].GetPos())); + patch[6 + op] = static_cast<uint8>(((15 - m_sustainLevel[op].GetPos()) << 4) | (15 - m_releaseRate[op].GetPos())); + patch[8 + op] = static_cast<uint8>(m_waveform[op].GetCurSel()); + } + + if(*m_patch != patch) + { + m_parent.SendMessage(WM_MOD_VIEWMSG, VIEWMSG_PREPAREUNDO); + *m_patch = patch; + m_parent.SendMessage(WM_MOD_VIEWMSG, VIEWMSG_SETMODIFIED, SampleHint().Data().AsLPARAM()); + } +} + + +BOOL OPLInstrDlg::OnToolTip(UINT /*id*/, NMHDR *pNMHDR, LRESULT* /*pResult*/) +{ + TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR; + UINT_PTR nID = pNMHDR->idFrom; + if(pTTT->uFlags & TTF_IDISHWND) + { + // idFrom is actually the HWND of the tool + nID = ::GetDlgCtrlID((HWND)nID); + } + + static constexpr const char *feedback[] = {"disabled", "\xCF\x80/16", "\xCF\x80/8", "\xCF\x80/4", "\xCF\x80/2", "\xCF\x80", "2\xCF\x80", "4\xCF\x80"}; + static constexpr const TCHAR *ksl[] = {_T("disabled"), _T("1.5 dB / octave"), _T("3 dB / octave"), _T("6 dB / octave")}; + + mpt::tstring text; + const CWnd *wnd = GetDlgItem(static_cast<int>(nID)); + const CSliderCtrl *slider = static_cast<const CSliderCtrl *>(wnd); + switch(nID) + { + case IDC_SLIDER1: + // Feedback + text = mpt::ToWin(mpt::Charset::UTF8, feedback[slider->GetPos() & 7]); + break; + + case IDC_SLIDER2: + case IDC_SLIDER3: + case IDC_SLIDER5: + case IDC_SLIDER9: + case IDC_SLIDER10: + case IDC_SLIDER12: + // Attack / Decay / Release + text = _T("faster < ") + mpt::tfmt::val(slider->GetPos()) + _T(" > slower"); + break; + case IDC_SLIDER4: + case IDC_SLIDER11: + // Sustain Level + { + const int pos = slider->GetPos(); + text = mpt::tfmt::val((pos == 0) ? -93 : ((-15 + pos) * 3)) + _T(" dB"); + } + break; + case IDC_SLIDER6: + case IDC_SLIDER13: + // Volume Level + text = mpt::tfmt::fix((-63 + slider->GetPos()) * 0.75, 2) + _T(" dB"); + break; + case IDC_SLIDER7: + case IDC_SLIDER14: + // Key Scale Level + text = ksl[slider->GetPos() & 3]; + break; + case IDC_SLIDER8: + case IDC_SLIDER15: + // Frequency Multiplier + if(slider->GetPos() == 0) + text = _T("0.5"); + else + text = mpt::tfmt::val(slider->GetPos()); + break; + } + + mpt::String::WriteWinBuf(pTTT->szText) = text.c_str(); + return TRUE; +} + +OPENMPT_NAMESPACE_END |