476 lines
18 KiB
C
476 lines
18 KiB
C
|
/*
|
||
|
* ModDoc.h
|
||
|
* --------
|
||
|
* Purpose: Converting between various module formats.
|
||
|
* 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 "Sndfile.h"
|
||
|
#include "../common/misc_util.h"
|
||
|
#include "Undo.h"
|
||
|
#include "Notification.h"
|
||
|
#include "UpdateHints.h"
|
||
|
#include <time.h>
|
||
|
|
||
|
OPENMPT_NAMESPACE_BEGIN
|
||
|
|
||
|
class EncoderFactoryBase;
|
||
|
class CChildFrame;
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////
|
||
|
// Split Keyboard Settings (pattern editor)
|
||
|
|
||
|
struct SplitKeyboardSettings
|
||
|
{
|
||
|
enum
|
||
|
{
|
||
|
splitOctaveRange = 9,
|
||
|
};
|
||
|
|
||
|
bool IsSplitActive() const { return (octaveLink && (octaveModifier != 0)) || (splitInstrument != 0) || (splitVolume != 0); }
|
||
|
|
||
|
int octaveModifier = 0; // determines by how many octaves the notes should be transposed up or down
|
||
|
ModCommand::NOTE splitNote = NOTE_MIDDLEC - 1;
|
||
|
ModCommand::INSTR splitInstrument = 0;
|
||
|
ModCommand::VOL splitVolume = 0;
|
||
|
bool octaveLink = false; // apply octaveModifier
|
||
|
};
|
||
|
|
||
|
enum InputTargetContext : int8;
|
||
|
|
||
|
|
||
|
struct LogEntry
|
||
|
{
|
||
|
LogLevel level;
|
||
|
mpt::ustring message;
|
||
|
LogEntry() : level(LogInformation) {}
|
||
|
LogEntry(LogLevel l, const mpt::ustring &m) : level(l), message(m) {}
|
||
|
};
|
||
|
|
||
|
|
||
|
enum LogMode
|
||
|
{
|
||
|
LogModeInstantReporting,
|
||
|
LogModeGather,
|
||
|
};
|
||
|
|
||
|
|
||
|
class ScopedLogCapturer
|
||
|
{
|
||
|
private:
|
||
|
CModDoc &m_modDoc;
|
||
|
LogMode m_oldLogMode;
|
||
|
CString m_title;
|
||
|
CWnd *m_pParent;
|
||
|
bool m_showLog;
|
||
|
public:
|
||
|
ScopedLogCapturer(CModDoc &modDoc, const CString &title = {}, CWnd *parent = nullptr, bool showLog = true);
|
||
|
~ScopedLogCapturer();
|
||
|
void ShowLog(bool force = false);
|
||
|
void ShowLog(const CString &preamble, bool force = false);
|
||
|
[[deprecated]] void ShowLog(const std::string &preamble, bool force = false);
|
||
|
void ShowLog(const mpt::ustring &preamble, bool force = false);
|
||
|
};
|
||
|
|
||
|
|
||
|
struct PlayNoteParam
|
||
|
{
|
||
|
std::bitset<128> *m_notesPlaying = nullptr;
|
||
|
SmpLength m_loopStart = 0, m_loopEnd = 0, m_sampleOffset = 0;
|
||
|
int32 m_volume = -1;
|
||
|
SAMPLEINDEX m_sample = 0;
|
||
|
INSTRUMENTINDEX m_instr = 0;
|
||
|
CHANNELINDEX m_currentChannel = CHANNELINDEX_INVALID;
|
||
|
ModCommand::NOTE m_note;
|
||
|
|
||
|
PlayNoteParam(ModCommand::NOTE note) : m_note(note) { }
|
||
|
|
||
|
PlayNoteParam& LoopStart(SmpLength loopStart) { m_loopStart = loopStart; return *this; }
|
||
|
PlayNoteParam& LoopEnd(SmpLength loopEnd) { m_loopEnd = loopEnd; return *this; }
|
||
|
PlayNoteParam& Offset(SmpLength sampleOffset) { m_sampleOffset = sampleOffset; return *this; }
|
||
|
|
||
|
PlayNoteParam& Volume(int32 volume) { m_volume = volume; return *this; }
|
||
|
PlayNoteParam& Sample(SAMPLEINDEX sample) { m_sample = sample; return *this; }
|
||
|
PlayNoteParam& Instrument(INSTRUMENTINDEX instr) { m_instr = instr; return *this; }
|
||
|
PlayNoteParam& Channel(CHANNELINDEX channel) { m_currentChannel = channel; return *this; }
|
||
|
|
||
|
PlayNoteParam& CheckNNA(std::bitset<128> ¬esPlaying) { m_notesPlaying = ¬esPlaying; return *this; }
|
||
|
};
|
||
|
|
||
|
|
||
|
enum class RecordGroup : uint8
|
||
|
{
|
||
|
NoGroup = 0,
|
||
|
Group1 = 1,
|
||
|
Group2 = 2,
|
||
|
};
|
||
|
|
||
|
|
||
|
class CModDoc final : public CDocument
|
||
|
{
|
||
|
protected:
|
||
|
friend ScopedLogCapturer;
|
||
|
mutable std::vector<LogEntry> m_Log;
|
||
|
LogMode m_LogMode = LogModeInstantReporting;
|
||
|
CSoundFile m_SndFile;
|
||
|
|
||
|
HWND m_hWndFollow = nullptr;
|
||
|
FlagSet<Notification::Type, uint16> m_notifyType;
|
||
|
Notification::Item m_notifyItem = 0;
|
||
|
CSize m_szOldPatternScrollbarsPos = { -10, -10 };
|
||
|
|
||
|
CPatternUndo m_PatternUndo;
|
||
|
CSampleUndo m_SampleUndo;
|
||
|
CInstrumentUndo m_InstrumentUndo;
|
||
|
SplitKeyboardSettings m_SplitKeyboardSettings; // this is maybe not the best place to keep them, but it should do the job
|
||
|
time_t m_creationTime;
|
||
|
|
||
|
std::atomic<bool> m_modifiedAutosave = false; // Modified since last autosave?
|
||
|
|
||
|
public:
|
||
|
class NoteToChannelMap : public std::array<CHANNELINDEX, NOTE_MAX - NOTE_MIN + 1>
|
||
|
{
|
||
|
public:
|
||
|
NoteToChannelMap() { fill(CHANNELINDEX_INVALID); }
|
||
|
};
|
||
|
NoteToChannelMap m_noteChannel; // Note -> Preview channel assignment
|
||
|
|
||
|
bool m_ShowSavedialog = false;
|
||
|
bool m_bHasValidPath = false; //becomes true if document is loaded or saved.
|
||
|
|
||
|
protected:
|
||
|
// Note-off event buffer for MIDI sustain pedal
|
||
|
std::array<std::vector<uint32>, 16> m_midiSustainBuffer;
|
||
|
std::array<std::bitset<128>, 16> m_midiPlayingNotes;
|
||
|
std::bitset<16> m_midiSustainActive;
|
||
|
|
||
|
std::bitset<MAX_BASECHANNELS> m_bsMultiRecordMask;
|
||
|
std::bitset<MAX_BASECHANNELS> m_bsMultiSplitRecordMask;
|
||
|
|
||
|
protected: // create from serialization only
|
||
|
CModDoc();
|
||
|
DECLARE_DYNCREATE(CModDoc)
|
||
|
|
||
|
// public members
|
||
|
public:
|
||
|
CSoundFile &GetSoundFile() { return m_SndFile; }
|
||
|
const CSoundFile &GetSoundFile() const { return m_SndFile; }
|
||
|
|
||
|
#if MPT_COMPILER_CLANG
|
||
|
#pragma clang diagnostic push
|
||
|
#pragma clang diagnostic ignored "-Woverloaded-virtual"
|
||
|
#endif // MPT_COMPILER_CLANG
|
||
|
bool IsModified() const { return m_bModified != FALSE; } // Work-around: CDocument::IsModified() is not const...
|
||
|
#if MPT_COMPILER_CLANG
|
||
|
#pragma clang diagnostic pop
|
||
|
#endif // MPT_COMPILER_CLANG
|
||
|
void SetModified(bool modified = true);
|
||
|
bool ModifiedSinceLastAutosave();
|
||
|
void SetShowSaveDialog(bool b) { m_ShowSavedialog = b; }
|
||
|
void PostMessageToAllViews(UINT uMsg, WPARAM wParam = 0, LPARAM lParam = 0);
|
||
|
void SendNotifyMessageToAllViews(UINT uMsg, WPARAM wParam = 0, LPARAM lParam = 0);
|
||
|
void SendMessageToActiveView(UINT uMsg, WPARAM wParam = 0, LPARAM lParam = 0);
|
||
|
MODTYPE GetModType() const { return m_SndFile.m_nType; }
|
||
|
INSTRUMENTINDEX GetNumInstruments() const { return m_SndFile.m_nInstruments; }
|
||
|
SAMPLEINDEX GetNumSamples() const { return m_SndFile.m_nSamples; }
|
||
|
|
||
|
// Logging for general progress and error events.
|
||
|
void AddToLog(LogLevel level, const mpt::ustring &text) const;
|
||
|
/*[[deprecated]]*/ void AddToLog(const CString &text) const { AddToLog(LogInformation, mpt::ToUnicode(text)); }
|
||
|
/*[[deprecated]]*/ void AddToLog(const std::string &text) const { AddToLog(LogInformation, mpt::ToUnicode(mpt::Charset::Locale, text)); }
|
||
|
/*[[deprecated]]*/ void AddToLog(const char *text) const { AddToLog(LogInformation, mpt::ToUnicode(mpt::Charset::Locale, text ? text : "")); }
|
||
|
|
||
|
const std::vector<LogEntry> & GetLog() const { return m_Log; }
|
||
|
mpt::ustring GetLogString() const;
|
||
|
LogLevel GetMaxLogLevel() const;
|
||
|
protected:
|
||
|
LogMode GetLogMode() const { return m_LogMode; }
|
||
|
void SetLogMode(LogMode mode) { m_LogMode = mode; }
|
||
|
void ClearLog();
|
||
|
UINT ShowLog(const CString &preamble, const CString &title = {}, CWnd *parent = nullptr);
|
||
|
UINT ShowLog(const CString &title = {}, CWnd *parent = nullptr) { return ShowLog(_T(""), title, parent); }
|
||
|
|
||
|
public:
|
||
|
|
||
|
void ClearFilePath() { m_strPathName.Empty(); }
|
||
|
|
||
|
void ViewPattern(UINT nPat, UINT nOrd);
|
||
|
void ViewSample(UINT nSmp);
|
||
|
void ViewInstrument(UINT nIns);
|
||
|
HWND GetFollowWnd() const { return m_hWndFollow; }
|
||
|
void SetFollowWnd(HWND hwnd);
|
||
|
|
||
|
void SetNotifications(FlagSet<Notification::Type> type, Notification::Item item = 0) { m_notifyType = type; m_notifyItem = item; }
|
||
|
FlagSet<Notification::Type, uint16> GetNotificationType() const { return m_notifyType; }
|
||
|
Notification::Item GetNotificationItem() const { return m_notifyItem; }
|
||
|
|
||
|
void ActivateWindow();
|
||
|
|
||
|
void OnSongProperties();
|
||
|
|
||
|
void PrepareUndoForAllPatterns(bool storeChannelInfo = false, const char *description = "");
|
||
|
CPatternUndo &GetPatternUndo() { return m_PatternUndo; }
|
||
|
CSampleUndo &GetSampleUndo() { return m_SampleUndo; }
|
||
|
CInstrumentUndo &GetInstrumentUndo() { return m_InstrumentUndo; }
|
||
|
SplitKeyboardSettings &GetSplitKeyboardSettings() { return m_SplitKeyboardSettings; }
|
||
|
|
||
|
time_t GetCreationTime() const { return m_creationTime; }
|
||
|
|
||
|
// operations
|
||
|
public:
|
||
|
bool ChangeModType(MODTYPE wType);
|
||
|
|
||
|
bool ChangeNumChannels(CHANNELINDEX nNewChannels, const bool showCancelInRemoveDlg = true);
|
||
|
bool RemoveChannels(const std::vector<bool> &keepMask, bool verbose = false);
|
||
|
void CheckUsedChannels(std::vector<bool> &usedMask, CHANNELINDEX maxRemoveCount = MAX_BASECHANNELS) const;
|
||
|
|
||
|
CHANNELINDEX ReArrangeChannels(const std::vector<CHANNELINDEX> &fromToArray, const bool createUndoPoint = true);
|
||
|
SAMPLEINDEX ReArrangeSamples(const std::vector<SAMPLEINDEX> &newOrder);
|
||
|
INSTRUMENTINDEX ReArrangeInstruments(const std::vector<INSTRUMENTINDEX> &newOrder, deleteInstrumentSamples removeSamples = doNoDeleteAssociatedSamples);
|
||
|
SEQUENCEINDEX ReArrangeSequences(const std::vector<SEQUENCEINDEX> &newOrder);
|
||
|
|
||
|
bool ConvertInstrumentsToSamples();
|
||
|
bool ConvertSamplesToInstruments();
|
||
|
PLUGINDEX RemovePlugs(const std::vector<bool> &keepMask);
|
||
|
bool RemovePlugin(PLUGINDEX plugin);
|
||
|
|
||
|
void ClonePlugin(SNDMIXPLUGIN &target, const SNDMIXPLUGIN &source);
|
||
|
void AppendModule(const CSoundFile &source);
|
||
|
|
||
|
// Create a new pattern and, if order position is specified, inserts it into the order list.
|
||
|
PATTERNINDEX InsertPattern(ROWINDEX rows, ORDERINDEX ord = ORDERINDEX_INVALID);
|
||
|
SAMPLEINDEX InsertSample();
|
||
|
INSTRUMENTINDEX InsertInstrument(SAMPLEINDEX sample = SAMPLEINDEX_INVALID, INSTRUMENTINDEX duplicateSource = INSTRUMENTINDEX_INVALID, bool silent = false);
|
||
|
INSTRUMENTINDEX InsertInstrumentForPlugin(PLUGINDEX plug);
|
||
|
INSTRUMENTINDEX HasInstrumentForPlugin(PLUGINDEX plug) const;
|
||
|
void InitializeInstrument(ModInstrument *pIns);
|
||
|
bool RemoveOrder(SEQUENCEINDEX nSeq, ORDERINDEX nOrd);
|
||
|
bool RemovePattern(PATTERNINDEX nPat);
|
||
|
bool RemoveSample(SAMPLEINDEX nSmp);
|
||
|
bool RemoveInstrument(INSTRUMENTINDEX nIns);
|
||
|
|
||
|
void ProcessMIDI(uint32 midiData, INSTRUMENTINDEX ins, IMixPlugin *plugin, InputTargetContext ctx);
|
||
|
CHANNELINDEX PlayNote(PlayNoteParam ¶ms, NoteToChannelMap *noteChannel = nullptr);
|
||
|
bool NoteOff(UINT note, bool fade = false, INSTRUMENTINDEX ins = INSTRUMENTINDEX_INVALID, CHANNELINDEX currentChn = CHANNELINDEX_INVALID);
|
||
|
void CheckNNA(ModCommand::NOTE note, INSTRUMENTINDEX ins, std::bitset<128> &playingNotes);
|
||
|
void UpdateOPLInstrument(SAMPLEINDEX smp);
|
||
|
|
||
|
bool IsNotePlaying(UINT note, SAMPLEINDEX nsmp = 0, INSTRUMENTINDEX nins = 0);
|
||
|
bool MuteChannel(CHANNELINDEX nChn, bool bMute);
|
||
|
bool UpdateChannelMuteStatus(CHANNELINDEX nChn);
|
||
|
bool MuteSample(SAMPLEINDEX nSample, bool bMute);
|
||
|
bool MuteInstrument(INSTRUMENTINDEX nInstr, bool bMute);
|
||
|
// Returns true if toggling the mute status of a channel should set the document as modified given the current module format and settings.
|
||
|
bool MuteToggleModifiesDocument() const;
|
||
|
|
||
|
bool SoloChannel(CHANNELINDEX nChn, bool bSolo);
|
||
|
bool IsChannelSolo(CHANNELINDEX nChn) const;
|
||
|
|
||
|
bool SurroundChannel(CHANNELINDEX nChn, bool bSurround);
|
||
|
bool SetChannelGlobalVolume(CHANNELINDEX nChn, uint16 nVolume);
|
||
|
bool SetChannelDefaultPan(CHANNELINDEX nChn, uint16 nPan);
|
||
|
bool IsChannelMuted(CHANNELINDEX nChn) const;
|
||
|
bool IsSampleMuted(SAMPLEINDEX nSample) const;
|
||
|
bool IsInstrumentMuted(INSTRUMENTINDEX nInstr) const;
|
||
|
|
||
|
bool NoFxChannel(CHANNELINDEX nChn, bool bNoFx, bool updateMix = true);
|
||
|
bool IsChannelNoFx(CHANNELINDEX nChn) const;
|
||
|
|
||
|
RecordGroup GetChannelRecordGroup(CHANNELINDEX channel) const;
|
||
|
void SetChannelRecordGroup(CHANNELINDEX channel, RecordGroup recordGroup);
|
||
|
void ToggleChannelRecordGroup(CHANNELINDEX channel, RecordGroup recordGroup);
|
||
|
void ReinitRecordState(bool unselect = true);
|
||
|
|
||
|
CHANNELINDEX GetNumChannels() const { return m_SndFile.m_nChannels; }
|
||
|
UINT GetPatternSize(PATTERNINDEX nPat) const;
|
||
|
bool IsChildSample(INSTRUMENTINDEX nIns, SAMPLEINDEX nSmp) const;
|
||
|
INSTRUMENTINDEX FindSampleParent(SAMPLEINDEX sample) const;
|
||
|
SAMPLEINDEX FindInstrumentChild(INSTRUMENTINDEX nIns) const;
|
||
|
bool MoveOrder(ORDERINDEX nSourceNdx, ORDERINDEX nDestNdx, bool bUpdate = true, bool bCopy = false, SEQUENCEINDEX nSourceSeq = SEQUENCEINDEX_INVALID, SEQUENCEINDEX nDestSeq = SEQUENCEINDEX_INVALID);
|
||
|
BOOL ExpandPattern(PATTERNINDEX nPattern);
|
||
|
BOOL ShrinkPattern(PATTERNINDEX nPattern);
|
||
|
|
||
|
bool SetDefaultChannelColors() { return SetDefaultChannelColors(0, GetNumChannels()); }
|
||
|
bool SetDefaultChannelColors(CHANNELINDEX channel) { return SetDefaultChannelColors(channel, channel + 1u); }
|
||
|
bool SetDefaultChannelColors(CHANNELINDEX minChannel, CHANNELINDEX maxChannel);
|
||
|
bool SupportsChannelColors() const { return GetModType() & (MOD_TYPE_XM | MOD_TYPE_IT | MOD_TYPE_MPT); }
|
||
|
|
||
|
bool CopyEnvelope(INSTRUMENTINDEX nIns, EnvelopeType nEnv);
|
||
|
bool SaveEnvelope(INSTRUMENTINDEX nIns, EnvelopeType nEnv, const mpt::PathString &fileName);
|
||
|
bool PasteEnvelope(INSTRUMENTINDEX nIns, EnvelopeType nEnv);
|
||
|
bool LoadEnvelope(INSTRUMENTINDEX nIns, EnvelopeType nEnv, const mpt::PathString &fileName);
|
||
|
|
||
|
LRESULT ActivateView(UINT nIdView, DWORD dwParam);
|
||
|
// Notify all views of document updates (GUI thread only)
|
||
|
void UpdateAllViews(CView *pSender, UpdateHint hint, CObject *pHint=NULL);
|
||
|
// Notify all views of document updates (for non-GUI threads)
|
||
|
void UpdateAllViews(UpdateHint hint);
|
||
|
void GetEditPosition(ROWINDEX &row, PATTERNINDEX &pat, ORDERINDEX &ord);
|
||
|
LRESULT OnCustomKeyMsg(WPARAM, LPARAM);
|
||
|
void TogglePluginEditor(UINT m_nCurrentPlugin, bool onlyThisEditor = false);
|
||
|
void RecordParamChange(PLUGINDEX slot, PlugParamIndex param);
|
||
|
void LearnMacro(int macro, PlugParamIndex param);
|
||
|
void SetElapsedTime(ORDERINDEX nOrd, ROWINDEX nRow, bool setSamplePos);
|
||
|
void SetLoopSong(bool loop);
|
||
|
|
||
|
// Global settings to pattern effect conversion
|
||
|
bool GlobalVolumeToPattern();
|
||
|
|
||
|
bool HasMPTHacks(const bool autofix = false);
|
||
|
|
||
|
void FixNullStrings();
|
||
|
|
||
|
// Fix: save pattern scrollbar position when switching to other tab
|
||
|
CSize GetOldPatternScrollbarsPos() const { return m_szOldPatternScrollbarsPos; };
|
||
|
void SetOldPatternScrollbarsPos( CSize s ){ m_szOldPatternScrollbarsPos = s; };
|
||
|
|
||
|
void OnFileWaveConvert(ORDERINDEX nMinOrder, ORDERINDEX nMaxOrder);
|
||
|
void OnFileWaveConvert(ORDERINDEX nMinOrder, ORDERINDEX nMaxOrder, const std::vector<EncoderFactoryBase*> &encFactories);
|
||
|
|
||
|
// Returns formatted ModInstrument name.
|
||
|
// [in] bEmptyInsteadOfNoName: In case of unnamed instrument string, "(no name)" is returned unless this
|
||
|
// parameter is true is case which an empty name is returned.
|
||
|
// [in] bIncludeIndex: True to include instrument index in front of the instrument name, false otherwise.
|
||
|
CString GetPatternViewInstrumentName(INSTRUMENTINDEX nInstr, bool bEmptyInsteadOfNoName = false, bool bIncludeIndex = true) const;
|
||
|
|
||
|
// Check if a given channel contains data.
|
||
|
bool IsChannelUnused(CHANNELINDEX nChn) const;
|
||
|
// Check whether a sample is used.
|
||
|
// In sample mode, the sample numbers in all patterns are checked.
|
||
|
// In instrument mode, it is only checked if a sample is referenced by an instrument (but not if the sample is actually played anywhere)
|
||
|
bool IsSampleUsed(SAMPLEINDEX sample, bool searchInMutedChannels = true) const;
|
||
|
// Check whether an instrument is used (only for instrument mode).
|
||
|
bool IsInstrumentUsed(INSTRUMENTINDEX instr, bool searchInMutedChannels = true) const;
|
||
|
|
||
|
// protected members
|
||
|
protected:
|
||
|
|
||
|
void InitializeMod();
|
||
|
|
||
|
CChildFrame *GetChildFrame(); //rewbs.customKeys
|
||
|
|
||
|
// Overrides
|
||
|
// ClassWizard generated virtual function overrides
|
||
|
//{{AFX_VIRTUAL(CModDoc)
|
||
|
public:
|
||
|
BOOL OnNewDocument() override;
|
||
|
BOOL OnOpenDocument(LPCTSTR lpszPathName) override;
|
||
|
BOOL OnSaveDocument(LPCTSTR lpszPathName) override
|
||
|
{
|
||
|
return OnSaveDocument(lpszPathName ? mpt::PathString::FromCString(lpszPathName) : mpt::PathString()) ? TRUE : FALSE;
|
||
|
}
|
||
|
void OnCloseDocument() override;
|
||
|
void SafeFileClose();
|
||
|
bool OnSaveDocument(const mpt::PathString &filename, const bool setPath = true);
|
||
|
|
||
|
#if MPT_COMPILER_CLANG
|
||
|
#pragma clang diagnostic push
|
||
|
#pragma clang diagnostic ignored "-Woverloaded-virtual"
|
||
|
#endif // MPT_COMPILER_CLANG
|
||
|
void SetPathName(const mpt::PathString &filename, BOOL bAddToMRU = TRUE)
|
||
|
{
|
||
|
CDocument::SetPathName(filename.ToCString(), bAddToMRU);
|
||
|
}
|
||
|
#if MPT_COMPILER_CLANG
|
||
|
#pragma clang diagnostic pop
|
||
|
#endif // MPT_COMPILER_CLANG
|
||
|
mpt::PathString GetPathNameMpt() const
|
||
|
{
|
||
|
return mpt::PathString::FromCString(GetPathName());
|
||
|
}
|
||
|
|
||
|
BOOL SaveModified() override;
|
||
|
bool SaveAllSamples(bool showPrompt = true);
|
||
|
bool SaveSample(SAMPLEINDEX smp);
|
||
|
|
||
|
BOOL DoSave(LPCTSTR lpszPathName, BOOL /*bSaveAs*/ = TRUE) override
|
||
|
{
|
||
|
return DoSave(lpszPathName ? mpt::PathString::FromCString(lpszPathName) : mpt::PathString());
|
||
|
}
|
||
|
BOOL DoSave(const mpt::PathString &filename, bool setPath = true);
|
||
|
void DeleteContents() override;
|
||
|
//}}AFX_VIRTUAL
|
||
|
|
||
|
// Get the sample index for the current pattern cell (resolves instrument note maps, etc)
|
||
|
SAMPLEINDEX GetSampleIndex(const ModCommand &m, ModCommand::INSTR lastInstr = 0) const;
|
||
|
// Get group (octave) size from given instrument (or sample in sample mode)
|
||
|
int GetInstrumentGroupSize(INSTRUMENTINDEX instr) const;
|
||
|
int GetBaseNote(INSTRUMENTINDEX instr) const;
|
||
|
ModCommand::NOTE GetNoteWithBaseOctave(int noteOffset, INSTRUMENTINDEX instr) const;
|
||
|
|
||
|
// Convert a linear volume property to decibels
|
||
|
static CString LinearToDecibels(double value, double valueAtZeroDB);
|
||
|
// Convert a panning value to a more readable string
|
||
|
static CString PanningToString(int32 value, int32 valueAtCenter);
|
||
|
|
||
|
void SerializeViews() const;
|
||
|
void DeserializeViews();
|
||
|
|
||
|
// View MIDI Mapping dialog for given plugin and parameter combination.
|
||
|
void ViewMIDIMapping(PLUGINDEX plugin = PLUGINDEX_INVALID, PlugParamIndex param = 0);
|
||
|
|
||
|
// Implementation
|
||
|
public:
|
||
|
virtual ~CModDoc();
|
||
|
|
||
|
// Generated message map functions
|
||
|
public:
|
||
|
//{{AFX_MSG(CModDoc)
|
||
|
afx_msg void OnFileWaveConvert();
|
||
|
afx_msg void OnFileMidiConvert();
|
||
|
afx_msg void OnFileOPLExport();
|
||
|
afx_msg void OnFileCompatibilitySave();
|
||
|
afx_msg void OnPlayerPlay();
|
||
|
afx_msg void OnPlayerStop();
|
||
|
afx_msg void OnPlayerPause();
|
||
|
afx_msg void OnPlayerPlayFromStart();
|
||
|
afx_msg void OnPanic();
|
||
|
afx_msg void OnEditGlobals();
|
||
|
afx_msg void OnEditPatterns();
|
||
|
afx_msg void OnEditSamples();
|
||
|
afx_msg void OnEditInstruments();
|
||
|
afx_msg void OnEditComments();
|
||
|
afx_msg void OnShowCleanup();
|
||
|
afx_msg void OnShowSampleTrimmer();
|
||
|
afx_msg void OnSetupZxxMacros();
|
||
|
afx_msg void OnEstimateSongLength();
|
||
|
afx_msg void OnApproximateBPM();
|
||
|
afx_msg void OnUpdateXMITMPTOnly(CCmdUI *p);
|
||
|
afx_msg void OnUpdateHasEditHistory(CCmdUI *p);
|
||
|
afx_msg void OnUpdateHasMIDIMappings(CCmdUI *p);
|
||
|
afx_msg void OnUpdateCompatExportableOnly(CCmdUI *p);
|
||
|
afx_msg void OnPatternRestart() { OnPatternRestart(true); } //rewbs.customKeys
|
||
|
afx_msg void OnPatternRestart(bool loop); //rewbs.customKeys
|
||
|
afx_msg void OnPatternPlay(); //rewbs.customKeys
|
||
|
afx_msg void OnPatternPlayNoLoop(); //rewbs.customKeys
|
||
|
afx_msg void OnViewEditHistory();
|
||
|
afx_msg void OnViewMPTHacks();
|
||
|
afx_msg void OnViewTempoSwingSettings();
|
||
|
afx_msg void OnSaveCopy();
|
||
|
afx_msg void OnSaveTemplateModule();
|
||
|
afx_msg void OnAppendModule();
|
||
|
afx_msg void OnViewMIDIMapping() { ViewMIDIMapping(); }
|
||
|
afx_msg void OnChannelManager();
|
||
|
//}}AFX_MSG
|
||
|
DECLARE_MESSAGE_MAP()
|
||
|
private:
|
||
|
|
||
|
void ChangeFileExtension(MODTYPE nNewType);
|
||
|
CHANNELINDEX FindAvailableChannel() const;
|
||
|
};
|
||
|
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//{{AFX_INSERT_LOCATION}}
|
||
|
// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
|
||
|
|
||
|
|
||
|
OPENMPT_NAMESPACE_END
|