468 lines
17 KiB
C++
468 lines
17 KiB
C++
/*
|
|
* MPTrack.h
|
|
* ---------
|
|
* Purpose: OpenMPT core application class.
|
|
* Notes : (currently none)
|
|
* Authors: OpenMPT Devs
|
|
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
|
|
*/
|
|
|
|
|
|
#pragma once
|
|
|
|
#include "openmpt/all/BuildSettings.hpp"
|
|
|
|
#include "resource.h" // main symbols
|
|
#include "Settings.h"
|
|
#include "MPTrackUtil.h"
|
|
#include "Reporting.h"
|
|
#include "../soundlib/MIDIMacros.h"
|
|
#include "../soundlib/modcommand.h"
|
|
#include "../common/ComponentManager.h"
|
|
#include "../misc/mptMutex.h"
|
|
#include "../common/mptRandom.h"
|
|
|
|
#include <future>
|
|
|
|
OPENMPT_NAMESPACE_BEGIN
|
|
|
|
class CModDoc;
|
|
class CModDocTemplate;
|
|
class CVstPluginManager;
|
|
namespace SoundDevice
|
|
{
|
|
class Manager;
|
|
} // namespace SoundDevice
|
|
struct AllSoundDeviceComponents;
|
|
class CDLSBank;
|
|
class DebugSettings;
|
|
class TrackerSettings;
|
|
class ComponentManagerSettings;
|
|
namespace mpt
|
|
{
|
|
namespace Wine
|
|
{
|
|
class VersionContext;
|
|
class Context;
|
|
} // namespace Wine
|
|
} // namespace mpt
|
|
class GdiplusRAII;
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// 16-colors DIB
|
|
struct MODPLUGDIB
|
|
{
|
|
BITMAPINFOHEADER bmiHeader;
|
|
RGBQUAD bmiColors[16];
|
|
LPBYTE lpDibBits;
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// Midi Library
|
|
|
|
using MidiLibrary = std::array<mpt::PathString, 128 * 2>; // 128 instruments + 128 percussions
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Dragon Droppings
|
|
|
|
enum DragonDropType
|
|
{
|
|
DRAGONDROP_NOTHING = 0, // |------< Drop Type >-------------|---< dropItem >----|---< dropParam >---|
|
|
DRAGONDROP_DLS, // | Instrument from a DLS bank | DLS Bank # | DLS Instrument |
|
|
DRAGONDROP_SAMPLE, // | Sample from a song | Sample # | NULL |
|
|
DRAGONDROP_INSTRUMENT, // | Instrument from a song | Instrument # | NULL |
|
|
DRAGONDROP_SOUNDFILE, // | File from instrument library | ? | File Name |
|
|
DRAGONDROP_MIDIINSTR, // | File from midi library | Midi Program/Perc | File Name |
|
|
DRAGONDROP_PATTERN, // | Pattern from a song | Pattern # | NULL |
|
|
DRAGONDROP_ORDER, // | Pattern index in a song | Order # | NULL |
|
|
DRAGONDROP_SONG, // | Song file (mod/s3m/xm/it) | 0 | File Name |
|
|
DRAGONDROP_SEQUENCE // | Sequence (a set of orders) | Sequence # | NULL |
|
|
};
|
|
|
|
struct DRAGONDROP
|
|
{
|
|
const CSoundFile *sndFile = nullptr;
|
|
DragonDropType dropType = DRAGONDROP_NOTHING;
|
|
uint32 dropItem = 0;
|
|
LPARAM dropParam = 0;
|
|
|
|
mpt::PathString GetPath() const
|
|
{
|
|
const mpt::PathString *const path = reinterpret_cast<const mpt::PathString *>(dropParam);
|
|
MPT_ASSERT(path);
|
|
return path ? *path : mpt::PathString();
|
|
}
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CTrackApp:
|
|
// See mptrack.cpp for the implementation of this class
|
|
//
|
|
|
|
class CMPTCommandLineInfo;
|
|
|
|
class CTrackApp : public CWinApp
|
|
{
|
|
friend class CMainFrame;
|
|
// static data
|
|
protected:
|
|
static MODTYPE m_nDefaultDocType;
|
|
static MidiLibrary midiLibrary;
|
|
|
|
public:
|
|
static std::vector<std::unique_ptr<CDLSBank>> gpDLSBanks;
|
|
|
|
protected:
|
|
mpt::recursive_mutex_with_lock_count m_GlobalMutex;
|
|
|
|
DWORD m_GuiThreadId = 0;
|
|
|
|
std::future<std::vector<std::unique_ptr<CDLSBank>>> m_scannedDlsBanks;
|
|
std::atomic<bool> m_scannedDlsBanksAvailable = false;
|
|
|
|
std::unique_ptr<mpt::random_device> m_RD;
|
|
std::unique_ptr<mpt::thread_safe_prng<mpt::default_prng>> m_PRNG;
|
|
|
|
std::unique_ptr<GdiplusRAII> m_Gdiplus;
|
|
|
|
std::shared_ptr<mpt::OS::Wine::VersionContext> m_WineVersion;
|
|
|
|
IniFileSettingsBackend *m_pSettingsIniFile;
|
|
SettingsContainer *m_pSettings = nullptr;
|
|
DebugSettings *m_pDebugSettings = nullptr;
|
|
TrackerSettings *m_pTrackerSettings = nullptr;
|
|
IniFileSettingsBackend *m_pSongSettingsIniFile = nullptr;
|
|
SettingsContainer *m_pSongSettings = nullptr;
|
|
ComponentManagerSettings *m_pComponentManagerSettings = nullptr;
|
|
IniFileSettingsContainer *m_pPluginCache = nullptr;
|
|
CModDocTemplate *m_pModTemplate = nullptr;
|
|
CVstPluginManager *m_pPluginManager = nullptr;
|
|
mpt::log::GlobalLogger m_GlobalLogger{};
|
|
std::unique_ptr<AllSoundDeviceComponents> m_pAllSoundDeviceComponents;
|
|
std::unique_ptr<SoundDevice::Manager> m_pSoundDevicesManager;
|
|
|
|
mpt::PathString m_InstallPath; // i.e. "C:\Program Files\OpenMPT\" (installer mode) or "G:\OpenMPT\" (portable mode)
|
|
mpt::PathString m_InstallBinPath; // i.e. "C:\Program Files\OpenMPT\bin\" (multi-arch mode) or InstallPath (legacy mode)
|
|
mpt::PathString m_InstallBinArchPath; // i.e. "C:\Program Files\OpenMPT\bin\amd64\" (multi-arch mode) or InstallPath (legacy mode)
|
|
mpt::PathString m_InstallPkgPath; // i.e. "C:\Program Files\OpenMPT\" (installer mode) or "G:\OpenMPT\" (portable mode)
|
|
|
|
mpt::PathString m_ConfigPath; // InstallPath (portable mode) or "%AppData%\OpenMPT\"
|
|
|
|
mpt::PathString m_szConfigFileName;
|
|
mpt::PathString m_szPluginCacheFileName;
|
|
|
|
std::shared_ptr<mpt::Wine::Context> m_Wine;
|
|
mpt::PathString m_WineWrapperDllName;
|
|
// Default macro configuration
|
|
MIDIMacroConfig m_MidiCfg;
|
|
DWORD m_dwLastPluginIdleCall = 0;
|
|
bool m_bInstallerMode = false;
|
|
bool m_bPortableMode = false;
|
|
bool m_bSourceTreeMode = false;
|
|
|
|
public:
|
|
CTrackApp();
|
|
|
|
CDataRecoveryHandler *GetDataRecoveryHandler() override;
|
|
void AddToRecentFileList(LPCTSTR lpszPathName) override;
|
|
void AddToRecentFileList(const mpt::PathString &path);
|
|
/// Removes item from MRU-list; most recent item has index zero.
|
|
void RemoveMruItem(const size_t item);
|
|
void RemoveMruItem(const mpt::PathString &path);
|
|
|
|
public:
|
|
bool IsMultiArchInstall() const { return m_InstallPath == m_InstallBinArchPath; }
|
|
mpt::PathString GetInstallPath() const { return m_InstallPath; } // i.e. "C:\Program Files\OpenMPT\" (installer mode) or "G:\OpenMPT\" (portable mode)
|
|
mpt::PathString GetInstallBinPath() const { return m_InstallBinPath; } // i.e. "C:\Program Files\OpenMPT\bin\" (multi-arch mode) or InstallPath (legacy mode)
|
|
mpt::PathString GetInstallBinArchPath() const { return m_InstallBinArchPath; } // i.e. "C:\Program Files\OpenMPT\bin\amd64\" (multi-arch mode) or InstallPath (legacy mode)
|
|
mpt::PathString GetInstallPkgPath() const { return m_InstallPkgPath; } // i.e. "C:\Program Files\OpenMPT\" (installer mode) or "G:\OpenMPT\" (portable mode)
|
|
|
|
static MODTYPE GetDefaultDocType() { return m_nDefaultDocType; }
|
|
static void SetDefaultDocType(MODTYPE n) { m_nDefaultDocType = n; }
|
|
static MidiLibrary &GetMidiLibrary() { return midiLibrary; }
|
|
static void ImportMidiConfig(const mpt::PathString &filename, bool hideWarning = false);
|
|
static void ExportMidiConfig(const mpt::PathString &filename);
|
|
static void ImportMidiConfig(SettingsContainer &file, const mpt::PathString &path, bool forgetSettings = false);
|
|
static void ExportMidiConfig(SettingsContainer &file);
|
|
static std::future<std::vector<std::unique_ptr<CDLSBank>>> LoadDefaultDLSBanks();
|
|
static void SaveDefaultDLSBanks();
|
|
static void RemoveDLSBank(UINT nBank);
|
|
static bool AddDLSBank(const mpt::PathString &filename);
|
|
static bool OpenURL(const char *url); // UTF8
|
|
static bool OpenURL(const std::string &url); // UTF8
|
|
static bool OpenURL(const CString &url);
|
|
static bool OpenURL(const mpt::ustring &url);
|
|
static bool OpenURL(const mpt::PathString &lpszURL);
|
|
static bool OpenFile(const mpt::PathString &file) { return OpenURL(file); };
|
|
static bool OpenDirectory(const mpt::PathString &directory) { return OpenURL(directory); };
|
|
|
|
// Retrieve the user-supplied MIDI port name for a MIDI input or output port.
|
|
mpt::ustring GetFriendlyMIDIPortName(const mpt::ustring &deviceName, bool isInputPort, bool addDeviceName = true);
|
|
CString GetFriendlyMIDIPortName(const CString &deviceName, bool isInputPort, bool addDeviceName = true);
|
|
|
|
int GetOpenDocumentCount() const;
|
|
std::vector<CModDoc *> GetOpenDocuments() const;
|
|
|
|
public:
|
|
inline mpt::recursive_mutex_with_lock_count &GetGlobalMutexRef() { return m_GlobalMutex; }
|
|
bool InGuiThread() const { return GetCurrentThreadId() == m_GuiThreadId; }
|
|
mpt::random_device &RandomDevice() { return *m_RD; }
|
|
mpt::thread_safe_prng<mpt::default_prng> &PRNG() { return *m_PRNG; }
|
|
CModDocTemplate *GetModDocTemplate() const { return m_pModTemplate; }
|
|
CVstPluginManager *GetPluginManager() const { return m_pPluginManager; }
|
|
SoundDevice::Manager *GetSoundDevicesManager() const { return m_pSoundDevicesManager.get(); }
|
|
void GetDefaultMidiMacro(MIDIMacroConfig &cfg) const { cfg = m_MidiCfg; }
|
|
void SetDefaultMidiMacro(const MIDIMacroConfig &cfg) { m_MidiCfg = cfg; }
|
|
mpt::PathString GetConfigFileName() const { return m_szConfigFileName; }
|
|
SettingsContainer *GetpSettings()
|
|
{
|
|
return m_pSettings;
|
|
}
|
|
SettingsContainer &GetSettings()
|
|
{
|
|
ASSERT(m_pSettings);
|
|
return *m_pSettings;
|
|
}
|
|
TrackerSettings &GetTrackerSettings()
|
|
{
|
|
ASSERT(m_pTrackerSettings);
|
|
return *m_pTrackerSettings;
|
|
}
|
|
bool IsInstallerMode() const
|
|
{
|
|
return m_bInstallerMode;
|
|
}
|
|
bool IsPortableMode() const
|
|
{
|
|
return m_bPortableMode;
|
|
}
|
|
bool IsSourceTreeMode() const
|
|
{
|
|
return m_bSourceTreeMode;
|
|
}
|
|
|
|
SettingsContainer &GetPluginCache()
|
|
{
|
|
ASSERT(m_pPluginCache);
|
|
return *m_pPluginCache;
|
|
}
|
|
|
|
SettingsContainer &GetSongSettings()
|
|
{
|
|
ASSERT(m_pSongSettings);
|
|
return *m_pSongSettings;
|
|
}
|
|
const mpt::PathString &GetSongSettingsFilename() const
|
|
{
|
|
return m_pSongSettingsIniFile->GetFilename();
|
|
}
|
|
|
|
void SetWineVersion(std::shared_ptr<mpt::OS::Wine::VersionContext> wineVersion)
|
|
{
|
|
MPT_ASSERT_ALWAYS(mpt::OS::Windows::IsWine());
|
|
m_WineVersion = wineVersion;
|
|
}
|
|
std::shared_ptr<mpt::OS::Wine::VersionContext> GetWineVersion() const
|
|
{
|
|
MPT_ASSERT_ALWAYS(mpt::OS::Windows::IsWine());
|
|
MPT_ASSERT_ALWAYS(m_WineVersion); // Verify initialization order. We should not should reach this until after Wine is detected.
|
|
return m_WineVersion;
|
|
}
|
|
|
|
void SetWine(std::shared_ptr<mpt::Wine::Context> wine)
|
|
{
|
|
m_Wine = wine;
|
|
}
|
|
std::shared_ptr<mpt::Wine::Context> GetWine() const
|
|
{
|
|
return m_Wine;
|
|
}
|
|
|
|
void SetWineWrapperDllFilename(mpt::PathString filename)
|
|
{
|
|
m_WineWrapperDllName = filename;
|
|
}
|
|
mpt::PathString GetWineWrapperDllFilename() const
|
|
{
|
|
return m_WineWrapperDllName;
|
|
}
|
|
|
|
/// Returns path to config folder including trailing '\'.
|
|
mpt::PathString GetConfigPath() const { return m_ConfigPath; }
|
|
void SetupPaths(bool overridePortable);
|
|
void CreatePaths();
|
|
|
|
#if !defined(MPT_BUILD_RETRO)
|
|
bool CheckSystemSupport();
|
|
#endif // !MPT_BUILD_RETRO
|
|
|
|
// Relative / absolute paths conversion
|
|
mpt::PathString PathAbsoluteToInstallRelative(const mpt::PathString &path) { return path.AbsolutePathToRelative(GetInstallPath()); }
|
|
mpt::PathString PathInstallRelativeToAbsolute(const mpt::PathString &path) { return path.RelativePathToAbsolute(GetInstallPath()); }
|
|
mpt::PathString PathAbsoluteToInstallBinArchRelative(const mpt::PathString &path) { return path.AbsolutePathToRelative(GetInstallBinArchPath()); }
|
|
mpt::PathString PathInstallBinArchRelativeToAbsolute(const mpt::PathString &path) { return path.RelativePathToAbsolute(GetInstallBinArchPath()); }
|
|
|
|
static void OpenModulesDialog(std::vector<mpt::PathString> &files, const mpt::PathString &overridePath = mpt::PathString());
|
|
|
|
public:
|
|
// Get name of resampling mode. addTaps = true also adds the number of taps the filter uses.
|
|
static CString GetResamplingModeName(ResamplingMode mode, int length, bool addTaps);
|
|
|
|
// Overrides
|
|
public:
|
|
// ClassWizard generated virtual function overrides
|
|
//{{AFX_VIRTUAL(CTrackApp)
|
|
public:
|
|
BOOL InitInstance() override;
|
|
BOOL InitInstanceEarly(CMPTCommandLineInfo &cmdInfo);
|
|
BOOL InitInstanceLate(CMPTCommandLineInfo &cmdInfo);
|
|
BOOL InitInstanceImpl(CMPTCommandLineInfo &cmdInfo);
|
|
int Run() override;
|
|
LRESULT ProcessWndProcException(CException *e, const MSG *pMsg) override;
|
|
int ExitInstance() override;
|
|
int ExitInstanceImpl();
|
|
BOOL OnIdle(LONG lCount) override;
|
|
//}}AFX_VIRTUAL
|
|
|
|
// Implementation
|
|
|
|
//{{AFX_MSG(CTrackApp)
|
|
CModDoc *NewDocument(MODTYPE newType = MOD_TYPE_NONE);
|
|
|
|
afx_msg void OnFileNew() { NewDocument(); }
|
|
afx_msg void OnFileNewMOD() { NewDocument(MOD_TYPE_MOD); }
|
|
afx_msg void OnFileNewS3M() { NewDocument(MOD_TYPE_S3M); }
|
|
afx_msg void OnFileNewXM() { NewDocument(MOD_TYPE_XM); }
|
|
afx_msg void OnFileNewIT() { NewDocument(MOD_TYPE_IT); }
|
|
afx_msg void OnFileNewMPT() { NewDocument(MOD_TYPE_MPT); }
|
|
|
|
afx_msg void OnFileOpen();
|
|
afx_msg void OnAppAbout();
|
|
|
|
afx_msg void OnFileCloseAll();
|
|
afx_msg void OnUpdateAnyDocsOpen(CCmdUI *cmd);
|
|
|
|
//}}AFX_MSG
|
|
DECLARE_MESSAGE_MAP()
|
|
|
|
protected:
|
|
size_t AddScannedDLSBanks();
|
|
|
|
void InitializeDXPlugins();
|
|
void UninitializeDXPlugins();
|
|
|
|
bool MoveConfigFile(const mpt::PathString &fileName, mpt::PathString subDir = {}, mpt::PathString newFileName = {});
|
|
};
|
|
|
|
|
|
extern CTrackApp theApp;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// More Bitmap Helpers
|
|
|
|
class CFastBitmap
|
|
{
|
|
protected:
|
|
static constexpr uint8 BLEND_OFFSET = 0x80;
|
|
|
|
struct MODPLUGFASTDIB
|
|
{
|
|
BITMAPINFOHEADER bmiHeader;
|
|
RGBQUAD bmiColors[256];
|
|
std::vector<uint8> DibBits;
|
|
};
|
|
|
|
MODPLUGFASTDIB m_Dib;
|
|
UINT m_nTextColor, m_nBkColor;
|
|
MODPLUGDIB *m_pTextDib;
|
|
uint8 m_nBlendOffset;
|
|
uint8 m_n4BitPalette[16];
|
|
uint8 m_nXShiftFactor;
|
|
|
|
public:
|
|
CFastBitmap() {}
|
|
|
|
public:
|
|
void Init(MODPLUGDIB *lpTextDib = nullptr);
|
|
void Blit(HDC hdc, int x, int y, int cx, int cy);
|
|
void Blit(HDC hdc, LPCRECT lprc) { Blit(hdc, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top); }
|
|
void SetTextColor(int nText, int nBk = -1)
|
|
{
|
|
m_nTextColor = nText;
|
|
if(nBk >= 0)
|
|
m_nBkColor = nBk;
|
|
}
|
|
void SetTextBkColor(UINT nBk) { m_nBkColor = nBk; }
|
|
void SetColor(UINT nIndex, COLORREF cr);
|
|
void SetAllColors(UINT nBaseIndex, UINT nColors, COLORREF *pcr);
|
|
void TextBlt(int x, int y, int cx, int cy, int srcx, int srcy, MODPLUGDIB *lpdib = nullptr);
|
|
void SetBlendMode(bool enable) { m_nBlendOffset = enable ? BLEND_OFFSET : 0; }
|
|
bool GetBlendMode() const { return m_nBlendOffset != 0; }
|
|
void SetBlendColor(COLORREF cr);
|
|
void SetSize(int x, int y);
|
|
int GetWidth() const { return m_Dib.bmiHeader.biWidth; }
|
|
};
|
|
|
|
|
|
///////////////////////////////////////////////////
|
|
// 4-bit DIB Drawing functions
|
|
void DibBlt(HDC hdc, int x, int y, int sizex, int sizey, int srcx, int srcy, MODPLUGDIB *lpdib);
|
|
MODPLUGDIB *LoadDib(LPCTSTR lpszName);
|
|
RGBQUAD rgb2quad(COLORREF c);
|
|
|
|
// Other bitmap functions
|
|
int DrawTextT(HDC hdc, const wchar_t *lpchText, int cchText, LPRECT lprc, UINT format);
|
|
int DrawTextT(HDC hdc, const char *lpchText, int cchText, LPRECT lprc, UINT format);
|
|
void DrawButtonRect(HDC hdc, const RECT *lpRect, LPCSTR lpszText = nullptr, BOOL bDisabled = FALSE, BOOL bPushed = FALSE, DWORD dwFlags = (DT_CENTER | DT_VCENTER), uint32 topMargin = 0);
|
|
void DrawButtonRect(HDC hdc, const RECT *lpRect, LPCWSTR lpszText = nullptr, BOOL bDisabled = FALSE, BOOL bPushed = FALSE, DWORD dwFlags = (DT_CENTER | DT_VCENTER), uint32 topMargin = 0);
|
|
|
|
// Misc functions
|
|
void ErrorBox(UINT nStringID, CWnd *p = nullptr);
|
|
|
|
// Helper function declarations.
|
|
struct SNDMIXPLUGIN;
|
|
class IMixPlugin;
|
|
void AddPluginNamesToCombobox(CComboBox &CBox, const SNDMIXPLUGIN *plugarray, const bool libraryName = false, const PLUGINDEX updatePlug = PLUGINDEX_INVALID);
|
|
void AddPluginParameternamesToCombobox(CComboBox &CBox, SNDMIXPLUGIN &plugarray);
|
|
void AddPluginParameternamesToCombobox(CComboBox &CBox, IMixPlugin &plug);
|
|
|
|
// Append note names in range [noteStart, noteEnd] to given combobox. Index starts from 0.
|
|
void AppendNotesToControl(CComboBox &combobox, ModCommand::NOTE noteStart, ModCommand::NOTE noteEnd);
|
|
|
|
// Append note names to combo box.
|
|
// If nInstr is given, instrument-specific note names are used instead of default note names.
|
|
// A custom note range may also be specified using the noteStart and noteEnd parameters.
|
|
// If they are left out, only notes that are available in the module type, plus any supported "special notes" are added.
|
|
void AppendNotesToControlEx(CComboBox &combobox, const CSoundFile &sndFile, INSTRUMENTINDEX nInstr = MAX_INSTRUMENTS, ModCommand::NOTE noteStart = 0, ModCommand::NOTE noteEnd = 0);
|
|
|
|
// Get window text (e.g. edit box content) as a CString
|
|
CString GetWindowTextString(const CWnd &wnd);
|
|
|
|
// Get window text (e.g. edit box content) as a unicode string
|
|
mpt::ustring GetWindowTextUnicode(const CWnd &wnd);
|
|
|
|
///////////////////////////////////////////////////
|
|
// Tables
|
|
|
|
extern const TCHAR *szSpecialNoteNamesMPT[];
|
|
extern const TCHAR *szSpecialNoteShortDesc[];
|
|
extern const char *szHexChar;
|
|
|
|
// Defined in load_mid.cpp
|
|
extern const char *szMidiProgramNames[128];
|
|
extern const char *szMidiPercussionNames[61]; // notes 25..85
|
|
extern const char *szMidiGroupNames[17]; // 16 groups + Percussions
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//{{AFX_INSERT_LOCATION}}
|
|
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
|
|
|
|
|
|
OPENMPT_NAMESPACE_END
|