#pragma once
#include "BuildSettings.h"
#include "SoundFilePlayConfig.h"
#include "MixerSettings.h"
#include "../common/misc_util.h"
#include "../common/mptRandom.h"
#include "../common/version.h"
#include <vector>
#include <bitset>
#include <set>
#include "Snd_defs.h"
#include "tuningbase.h"
#include "MIDIMacros.h"
#ifdef MODPLUG_TRACKER
#include "../mptrack/MIDIMapping.h"
#endif
#include "Mixer.h"
#include "Resampler.h"
#ifndef NO_REVERB
#include "../sounddsp/Reverb.h"
#endif
#ifndef NO_AGC
#include "../sounddsp/AGC.h"
#endif
#ifndef NO_DSP
#include "../sounddsp/DSP.h"
#endif
#ifndef NO_EQ
#include "../sounddsp/EQ.h"
#endif
#include "modcommand.h"
#include "ModSample.h"
#include "ModInstrument.h"
#include "ModChannel.h"
#include "plugins/PluginStructs.h"
#include "RowVisitor.h"
#include "Message.h"
#include "pattern.h"
#include "patternContainer.h"
#include "ModSequence.h"
#include "../common/FileReaderFwd.h"
OPENMPT_NAMESPACE_BEGIN
#ifndef MODPLUG_NO_FILESAVE
extern void WriteInstrumentHeaderStructOrField(ModInstrument * input, std::ostream &file, uint32 only_this_code = -1 , uint16 fixedsize = 0);
#endif extern bool ReadInstrumentHeaderField(ModInstrument * input, uint32 fcode, uint16 fsize, FileReader &file);
typedef void (* LPSNDMIXHOOKPROC)(int *, unsigned long, unsigned long);
#ifdef LIBOPENMPT_BUILD
#ifndef NO_PLUGINS
class CVstPluginManager;
#endif
#endif
typedef std::bitset<kMaxPlayBehaviours> PlayBehaviourSet;
#ifdef MODPLUG_TRACKER
struct PatternCuePoint
{
uint64 offset; ORDERINDEX order; bool processed; };
#endif
struct GetLengthType
{
double duration = 0.0; ROWINDEX lastRow = ROWINDEX_INVALID; ROWINDEX endRow = ROWINDEX_INVALID; ROWINDEX startRow = 0; ORDERINDEX lastOrder = ORDERINDEX_INVALID; ORDERINDEX endOrder = ORDERINDEX_INVALID; ORDERINDEX startOrder = 0; bool targetReached = false; };
struct GetLengthTarget
{
ROWINDEX startRow;
ORDERINDEX startOrder;
SEQUENCEINDEX sequence;
struct pos_type
{
ROWINDEX row;
ORDERINDEX order;
};
union
{
double time;
pos_type pos;
};
enum Mode
{
NoTarget, GetAllSubsongs, SeekPosition, SeekSeconds, } mode;
GetLengthTarget(bool allSongs = false)
{
mode = allSongs ? GetAllSubsongs : NoTarget;
sequence = SEQUENCEINDEX_INVALID;
startOrder = 0;
startRow = 0;
}
GetLengthTarget(ORDERINDEX order, ROWINDEX row)
{
mode = NoTarget;
sequence = SEQUENCEINDEX_INVALID;
startOrder = 0;
startRow = 0;
if(order != ORDERINDEX_INVALID && row != ROWINDEX_INVALID)
{
mode = SeekPosition;
pos.row = row;
pos.order = order;
}
}
GetLengthTarget(double t)
{
mode = NoTarget;
sequence = SEQUENCEINDEX_INVALID;
startOrder = 0;
startRow = 0;
if(t >= 0.0)
{
mode = SeekSeconds;
time = t;
}
}
GetLengthTarget &StartPos(SEQUENCEINDEX seq, ORDERINDEX order, ROWINDEX row)
{
sequence = seq;
startOrder = order;
startRow = row;
return *this;
}
};
enum enmGetLengthResetMode
{
eNoAdjust = 0x00,
eAdjust = 0x01,
eAdjustOnSuccess = 0x02 | eAdjust,
eAdjustSamplePositions = 0x04 | eAdjustOnSuccess,
};
enum deleteInstrumentSamples
{
deleteAssociatedSamples,
doNoDeleteAssociatedSamples,
};
namespace Tuning {
class CTuningCollection;
} typedef Tuning::CTuningCollection CTuningCollection;
struct CModSpecifications;
class OPL;
#ifdef MODPLUG_TRACKER
class CModDoc;
#endif
#define HISTORY_TIMER_PRECISION 18.2
struct FileHistory
{
FileHistory() : openTime(0) { MemsetZero(loadDate); }
tm loadDate;
uint32 openTime;
mpt::ustring AsISO8601() const;
};
struct TimingInfo
{
double InputLatency = 0.0; double OutputLatency = 0.0; int64 StreamFrames = 0;
uint64 SystemTimestamp = 0; double Speed = 1.0;
};
struct ModFormatDetails
{
mpt::ustring formatName; mpt::ustring type; mpt::ustring madeWithTracker; mpt::ustring originalFormatName; mpt::ustring originalType; mpt::Charset charset = mpt::CharsetUTF8;
};
class IAudioReadTarget
{
protected:
virtual ~IAudioReadTarget() = default;
public:
virtual void DataCallback(int32 *MixSoundBuffer, std::size_t channels, std::size_t countChunk) = 0;
};
class IAudioSource
{
public:
virtual ~IAudioSource() = default;
public:
virtual void FillCallback(int32 * const *MixSoundBuffers, std::size_t channels, std::size_t countChunk) = 0;
};
class AudioSourceNone
: public IAudioSource
{
public:
void FillCallback(int32 * const *MixSoundBuffers, std::size_t channels, std::size_t countChunk) override
{
for(std::size_t channel = 0; channel < channels; ++channel)
{
for(std::size_t frame = 0; frame < countChunk; ++frame)
{
MixSoundBuffers[channel][frame] = 0;
}
}
}
};
typedef MPT_UCHAR_TYPE NoteName[4];
class CSoundFile
{
friend class GetLengthMemory;
public:
#ifdef MODPLUG_TRACKER
void ChangeModTypeTo(const MODTYPE newType);
#endif
double GetPlaybackTimeAt(ORDERINDEX ord, ROWINDEX row, bool updateVars, bool updateSamplePos);
public:
static CTuning* CreateTuning12TET(const std::string &name);
static CTuning *GetDefaultTuning() {return nullptr;}
CTuningCollection& GetTuneSpecificTunings() {return *m_pTuningsTuneSpecific;}
mpt::ustring GetNoteName(const ModCommand::NOTE note, const INSTRUMENTINDEX inst) const;
mpt::ustring GetNoteName(const ModCommand::NOTE note) const;
static mpt::ustring GetNoteName(const ModCommand::NOTE note, const NoteName *noteNames);
#ifdef MODPLUG_TRACKER
public:
static void SetDefaultNoteNames();
static const NoteName *GetDefaultNoteNames();
static mpt::ustring GetDefaultNoteName(int note) {
return m_NoteNames[note];
}
private:
static const NoteName *m_NoteNames;
#else
private:
const NoteName *m_NoteNames;
#endif
private:
CTuningCollection* m_pTuningsTuneSpecific = nullptr;
#ifdef MODPLUG_TRACKER
public:
CMIDIMapper& GetMIDIMapper() {return m_MIDIMapper;}
const CMIDIMapper& GetMIDIMapper() const {return m_MIDIMapper;}
private:
CMIDIMapper m_MIDIMapper;
#endif
private: static void SetModSpecsPointer(const CModSpecifications*& pModSpecs, const MODTYPE type);
private: const CModSpecifications *m_pModSpecs;
private:
mixsample_t MixSoundBuffer[MIXBUFFERSIZE * 4];
mixsample_t MixRearBuffer[MIXBUFFERSIZE * 2];
float MixFloatBuffer[2][MIXBUFFERSIZE];
mixsample_t gnDryLOfsVol = 0;
mixsample_t gnDryROfsVol = 0;
mixsample_t MixInputBuffer[NUMMIXINPUTBUFFERS][MIXBUFFERSIZE];
public:
MixerSettings m_MixerSettings;
CResampler m_Resampler;
#ifndef NO_REVERB
CReverb m_Reverb;
#endif
#ifndef NO_DSP
CSurround m_Surround;
CMegaBass m_MegaBass;
#endif
#ifndef NO_EQ
CQuadEQ m_EQ;
#endif
#ifndef NO_AGC
CAGC m_AGC;
#endif
typedef uint32 samplecount_t;
public: #ifdef MODPLUG_TRACKER
CModDoc *m_pModDoc = nullptr; #endif Enum<MODTYPE> m_nType;
private:
MODCONTAINERTYPE m_ContainerType = MOD_CONTAINERTYPE_NONE;
public:
CHANNELINDEX m_nChannels = 0;
SAMPLEINDEX m_nSamples = 0;
INSTRUMENTINDEX m_nInstruments = 0;
uint32 m_nDefaultSpeed, m_nDefaultGlobalVolume;
TEMPO m_nDefaultTempo;
FlagSet<SongFlags> m_SongFlags;
CHANNELINDEX m_nMixChannels = 0;
private:
CHANNELINDEX m_nMixStat;
public:
ROWINDEX m_nDefaultRowsPerBeat, m_nDefaultRowsPerMeasure; TempoMode m_nTempoMode = tempoModeClassic;
#ifdef MODPLUG_TRACKER
ROWINDEX m_lockRowStart = ROWINDEX_INVALID, m_lockRowEnd = ROWINDEX_INVALID;
ORDERINDEX m_lockOrderStart = ORDERINDEX_INVALID, m_lockOrderEnd = ORDERINDEX_INVALID;
#endif
uint32 m_nSamplePreAmp, m_nVSTiVolume;
uint32 m_OPLVolumeFactor; enum : uint32 { m_OPLVolumeFactorScale = (1 << 16) };
bool IsGlobalVolumeUnset() const { return IsFirstTick(); }
#ifndef MODPLUG_TRACKER
uint32 m_nFreqFactor = 65536; uint32 m_nTempoFactor = 65536; #endif
TempoSwing m_tempoSwing;
int32 m_nMinPeriod, m_nMaxPeriod;
ResamplingMode m_nResampling; int32 m_nRepeatCount = 0; ORDERINDEX m_nMaxOrderPosition;
ModChannelSettings ChnSettings[MAX_BASECHANNELS]; CPatternContainer Patterns;
ModSequenceSet Order; protected:
ModSample Samples[MAX_SAMPLES]; public:
ModInstrument *Instruments[MAX_INSTRUMENTS]; MIDIMacroConfig m_MidiCfg; #ifndef NO_PLUGINS
SNDMIXPLUGIN m_MixPlugins[MAX_MIXPLUGINS]; #endif
char m_szNames[MAX_SAMPLES][MAX_SAMPLENAME];
Version m_dwCreatedWithVersion;
Version m_dwLastSavedWithVersion;
PlayBehaviourSet m_playBehaviour;
protected:
mpt::fast_prng m_PRNG;
inline mpt::fast_prng & AccessPRNG() const { return const_cast<CSoundFile*>(this)->m_PRNG; }
inline mpt::fast_prng & AccessPRNG() { return m_PRNG; }
protected:
CSoundFilePlayConfig m_PlayConfig;
MixLevels m_nMixLevels;
public:
struct PlayState
{
friend class CSoundFile;
protected:
samplecount_t m_nBufferCount;
double m_dBufferDiff;
public:
samplecount_t m_lTotalSampleCount = 0;
public:
uint32 m_nTickCount;
protected:
uint32 m_nPatternDelay, m_nFrameDelay; public:
uint32 m_nSamplesPerTick;
ROWINDEX m_nCurrentRowsPerBeat, m_nCurrentRowsPerMeasure; uint32 m_nMusicSpeed; TEMPO m_nMusicTempo;
ROWINDEX m_nRow;
ROWINDEX m_nNextRow;
protected:
ROWINDEX m_nNextPatStartRow; public:
PATTERNINDEX m_nPattern;
ORDERINDEX m_nCurrentOrder, m_nNextOrder, m_nSeqOverride = ORDERINDEX_INVALID;
public:
int32 m_nGlobalVolume;
protected:
int32 m_nSamplesToGlobalVolRampDest, m_nGlobalVolumeRampAmount,
m_nGlobalVolumeDestination;
int32 m_lHighResRampingGlobalVolume;
public:
bool m_bPositionChanged = true;
public:
CHANNELINDEX ChnMix[MAX_CHANNELS]; ModChannel Chn[MAX_CHANNELS];
public:
PlayState()
{
std::fill(std::begin(Chn), std::end(Chn), ModChannel());
}
};
PlayState m_PlayState;
protected:
RowVisitor visitedSongRows;
public:
#ifdef MODPLUG_TRACKER
std::bitset<MAX_BASECHANNELS> m_bChannelMuteTogglePending;
std::vector<PatternCuePoint> *m_PatternCuePoints = nullptr; std::vector<SmpLength> *m_SamplePlayLengths = nullptr; #endif
std::unique_ptr<OPL> m_opl;
public:
#ifdef LIBOPENMPT_BUILD
#ifndef NO_PLUGINS
std::unique_ptr<CVstPluginManager> m_PluginManager;
#endif
#endif
public:
std::string m_songName;
mpt::ustring m_songArtist;
SongMessage m_songMessage;
ModFormatDetails m_modFormat;
protected:
std::vector<FileHistory> m_FileHistory; public:
std::vector<FileHistory> &GetFileHistory() { return m_FileHistory; }
const std::vector<FileHistory> &GetFileHistory() const { return m_FileHistory; }
#ifdef MPT_EXTERNAL_SAMPLES
protected:
std::vector<mpt::PathString> m_samplePaths;
public:
void SetSamplePath(SAMPLEINDEX smp, const mpt::PathString &filename) { if(m_samplePaths.size() < smp) m_samplePaths.resize(smp); m_samplePaths[smp - 1] = filename.Simplify(); }
void ResetSamplePath(SAMPLEINDEX smp) { if(m_samplePaths.size() >= smp) m_samplePaths[smp - 1] = mpt::PathString(); Samples[smp].uFlags.reset(SMP_KEEPONDISK | SMP_MODIFIED);}
mpt::PathString GetSamplePath(SAMPLEINDEX smp) const { if(m_samplePaths.size() >= smp) return m_samplePaths[smp - 1]; else return mpt::PathString(); }
bool SampleHasPath(SAMPLEINDEX smp) const { if(m_samplePaths.size() >= smp) return !m_samplePaths[smp - 1].empty(); else return false; }
bool IsExternalSampleMissing(SAMPLEINDEX smp) const { return Samples[smp].uFlags[SMP_KEEPONDISK] && !Samples[smp].HasSampleData(); }
bool LoadExternalSample(SAMPLEINDEX smp, const mpt::PathString &filename);
#endif
bool m_bIsRendering = false;
TimingInfo m_TimingInfo;
private:
ILog *m_pCustomLog = nullptr;
public:
CSoundFile();
~CSoundFile();
public:
void SetCustomLog(ILog *pLog) { m_pCustomLog = pLog; }
void AddToLog(LogLevel level, const mpt::ustring &text) const;
void AddToLog(const AnyStringLocale &text) const { AddToLog(LogInformation, mpt::ToUnicode(text)); }
public:
enum ModLoadingFlags
{
onlyVerifyHeader = 0x00,
loadPatternData = 0x01, loadSampleData = 0x02, loadPluginData = 0x04, loadPluginInstance = 0x08, skipContainer = 0x10,
skipModules = 0x20,
loadCompleteModule = loadSampleData | loadPatternData | loadPluginData | loadPluginInstance,
loadNoPatternOrPluginData = loadSampleData,
loadNoPluginInstance = loadSampleData | loadPatternData | loadPluginData,
};
#define PROBE_RECOMMENDED_SIZE 2048u
static const std::size_t ProbeRecommendedSize;
enum ProbeFlags
{
ProbeModules = 0x1,
ProbeContainers = 0x2,
ProbeFlagsDefault = ProbeModules | ProbeContainers,
ProbeFlagsNone = 0
};
enum ProbeResult
{
ProbeSuccess = 1,
ProbeFailure = 0,
ProbeWantMoreData = -1
};
static ProbeResult ProbeAdditionalSize(MemoryFileReader &file, const uint64 *pfilesize, uint64 minimumAdditionalSize);
static ProbeResult Probe(ProbeFlags flags, mpt::span<const mpt::byte> data, const uint64 *pfilesize);
public:
#ifdef MODPLUG_TRACKER
CModDoc *GetpModDoc() const noexcept { return m_pModDoc; }
bool Create(FileReader file, ModLoadingFlags loadFlags = loadCompleteModule, CModDoc *pModDoc = nullptr);
#else
bool Create(FileReader file, ModLoadingFlags loadFlags);
#endif
bool Destroy();
Enum<MODTYPE> GetType() const noexcept { return m_nType; }
MODCONTAINERTYPE GetContainerType() const noexcept { return m_ContainerType; }
mpt::Charset GetCharsetFile() const {
return m_modFormat.charset;
}
mpt::Charset GetCharsetInternal() const {
#if defined(MODPLUG_TRACKER)
return mpt::CharsetLocale;
#else
return GetCharsetFile();
#endif }
void SetPreAmp(uint32 vol);
uint32 GetPreAmp() const { return m_MixerSettings.m_nPreAmp; }
void SetMixLevels(MixLevels levels);
MixLevels GetMixLevels() const { return m_nMixLevels; }
const CSoundFilePlayConfig &GetPlayConfig() const { return m_PlayConfig; }
INSTRUMENTINDEX GetNumInstruments() const { return m_nInstruments; }
SAMPLEINDEX GetNumSamples() const { return m_nSamples; }
PATTERNINDEX GetCurrentPattern() const { return m_PlayState.m_nPattern; }
ORDERINDEX GetCurrentOrder() const { return m_PlayState.m_nCurrentOrder; }
CHANNELINDEX GetNumChannels() const { return m_nChannels; }
#ifndef NO_PLUGINS
IMixPlugin* GetInstrumentPlugin(INSTRUMENTINDEX instr);
#endif
const CModSpecifications& GetModSpecifications() const {return *m_pModSpecs;}
static const CModSpecifications& GetModSpecifications(const MODTYPE type);
#ifdef MODPLUG_TRACKER
void PatternTranstionChnSolo(const CHANNELINDEX chnIndex);
void PatternTransitionChnUnmuteAll();
#endif
double GetCurrentBPM() const;
void DontLoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0);
CHANNELINDEX GetMixStat() const { return m_nMixStat; }
void ResetMixStat() { m_nMixStat = 0; }
void ResetPlayPos();
void SetCurrentOrder(ORDERINDEX nOrder);
std::string GetTitle() const { return m_songName; }
bool SetTitle(const std::string &newTitle); const char *GetSampleName(SAMPLEINDEX nSample) const;
const char *GetInstrumentName(INSTRUMENTINDEX nInstr) const;
uint32 GetMusicSpeed() const { return m_PlayState.m_nMusicSpeed; }
TEMPO GetMusicTempo() const { return m_PlayState.m_nMusicTempo; }
bool IsFirstTick() const { return (m_PlayState.m_lTotalSampleCount == 0); }
std::vector<GetLengthType> GetLength(enmGetLengthResetMode adjustMode, GetLengthTarget target = GetLengthTarget());
public:
void RecalculateSamplesPerTick();
double GetRowDuration(TEMPO tempo, uint32 speed) const;
uint32 GetTickDuration(PlayState &playState) const;
void SetRepeatCount(int n) { m_nRepeatCount = n; }
int GetRepeatCount() const { return m_nRepeatCount; }
bool IsPaused() const { return m_SongFlags[SONG_PAUSED | SONG_STEP]; } void LoopPattern(PATTERNINDEX nPat, ROWINDEX nRow = 0);
bool InitChannel(CHANNELINDEX nChn);
void InitAmigaResampler();
void InitOPL();
static constexpr bool SupportsOPL(MODTYPE type) { return type & (MOD_TYPE_S3M | MOD_TYPE_MPT); }
bool SupportsOPL() const noexcept { return SupportsOPL(m_nType); }
static ProbeResult ProbeFileHeaderMMCMP(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderPP20(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderUMX(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderXPK(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeader669(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderAM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderAMF_Asylum(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderAMF_DSMI(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderAMS(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderAMS2(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderC67(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderDBM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderDTM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderDIGI(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderDMF(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderDSM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderFAR(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderGDM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderICE(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderIMF(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderIT(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderITP(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderJ2B(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderM15(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderMDL(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderMED(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderMO3(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderMOD(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderMT2(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderMTM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderOKT(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderPLM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderPSM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderPSM16(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderPT36(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderPTM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderS3M(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderSFX(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderSTM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderSTP(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderULT(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderXM(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderMID(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderUAX(MemoryFileReader file, const uint64 *pfilesize);
static ProbeResult ProbeFileHeaderWAV(MemoryFileReader file, const uint64 *pfilesize);
bool Read669(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAMF_Asylum(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAMF_DSMI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAMS(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadAMS2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadC67(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadDBM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadDTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadDIGI(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadDMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadDSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadFAR(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadGDM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadICE(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadIMF(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadIT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadITP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadJ2B(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadM15(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMDL(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMED(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMO3(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMOD(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMT2(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadOKT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadPLM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadPSM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadPSM16(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadPT36(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadPTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadS3M(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadSFX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadSTM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadSTP(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadULT(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadXM(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadMID(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadUAX(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
bool ReadWAV(FileReader &file, ModLoadingFlags loadFlags = loadCompleteModule);
static std::vector<const char *> GetSupportedExtensions(bool otherFormats);
static bool IsExtensionSupported(const char *ext); static mpt::ustring ModContainerTypeToString(MODCONTAINERTYPE containertype);
static mpt::ustring ModContainerTypeToTracker(MODCONTAINERTYPE containertype);
void UpgradeModule();
#ifndef MODPLUG_NO_FILESAVE
bool SaveXM(std::ostream &f, bool compatibilityExport = false);
bool SaveS3M(std::ostream &f) const;
bool SaveMod(std::ostream &f) const;
bool SaveIT(std::ostream &f, const mpt::PathString &filename, bool compatibilityExport = false);
uint32 SaveMixPlugins(std::ostream *file=nullptr, bool bUpdate=true);
void WriteInstrumentPropertyForAllInstruments(uint32 code, uint16 size, std::ostream &f, INSTRUMENTINDEX nInstruments) const;
void SaveExtendedInstrumentProperties(INSTRUMENTINDEX nInstruments, std::ostream &f) const;
void SaveExtendedSongProperties(std::ostream &f) const;
#endif void LoadExtendedSongProperties(FileReader &file, bool ignoreChannelCount, bool* pInterpretMptMade = nullptr);
void LoadMPTMProperties(FileReader &file, uint16 cwtv);
mpt::ustring GetSchismTrackerVersion(uint16 cwtv);
bool LoadExtendedInstrumentProperties(FileReader &file);
void SetDefaultPlaybackBehaviour(MODTYPE type);
static PlayBehaviourSet GetSupportedPlaybackBehaviour(MODTYPE type);
static PlayBehaviourSet GetDefaultPlaybackBehaviour(MODTYPE type);
MODTYPE GetBestSaveFormat() const;
static void ConvertModCommand(ModCommand &m);
static void S3MConvert(ModCommand &m, bool fromIT);
void S3MSaveConvert(uint8 &command, uint8 ¶m, bool toIT, bool compatibilityExport = false) const;
void ModSaveCommand(uint8 &command, uint8 ¶m, const bool toXM, const bool compatibilityExport = false) const;
static void ReadMODPatternEntry(FileReader &file, ModCommand &m);
static void ReadMODPatternEntry(const uint8 (&data)[4], ModCommand &m);
void SetupMODPanning(bool bForceSetup = false);
public:
void SuspendPlugins();
void ResumePlugins();
void StopAllVsti();
void RecalculateGainForAllPlugs();
void ResetChannels();
samplecount_t Read(samplecount_t count, IAudioReadTarget &target) { AudioSourceNone source; return Read(count, target, source); }
samplecount_t Read(samplecount_t count, IAudioReadTarget &target, IAudioSource &source);
private:
void CreateStereoMix(int count);
public:
bool FadeSong(uint32 msec);
private:
void ProcessDSP(uint32 countChunk);
void ProcessPlugins(uint32 nCount);
void ProcessInputChannels(IAudioSource &source, std::size_t countChunk);
public:
samplecount_t GetTotalSampleCount() const { return m_PlayState.m_lTotalSampleCount; }
bool HasPositionChanged() { bool b = m_PlayState.m_bPositionChanged; m_PlayState.m_bPositionChanged = false; return b; }
bool IsRenderingToDisc() const { return m_bIsRendering; }
void PrecomputeSampleLoops(bool updateChannels = false);
public:
void SetMixerSettings(const MixerSettings &mixersettings);
void SetResamplerSettings(const CResamplerSettings &resamplersettings);
void InitPlayer(bool bReset=false);
void SetDspEffects(uint32 DSPMask);
uint32 GetSampleRate() const { return m_MixerSettings.gdwMixingFreq; }
#ifndef NO_EQ
void SetEQGains(const uint32 *pGains, uint32 nBands, const uint32 *pFreqs=NULL, bool bReset=false) { m_EQ.SetEQGains(pGains, nBands, pFreqs, bReset, m_MixerSettings.gdwMixingFreq); } #endif public:
bool ReadNote();
bool ProcessRow();
bool ProcessEffects();
CHANNELINDEX GetNNAChannel(CHANNELINDEX nChn) const;
CHANNELINDEX CheckNNA(CHANNELINDEX nChn, uint32 instr, int note, bool forceCut);
void NoteChange(ModChannel &chn, int note, bool bPorta = false, bool bResetEnv = true, bool bManual = false, CHANNELINDEX channelHint = CHANNELINDEX_INVALID) const;
void InstrumentChange(ModChannel &chn, uint32 instr, bool bPorta = false, bool bUpdVol = true, bool bResetEnv = true) const;
void ApplyInstrumentPanning(ModChannel &chn, const ModInstrument *instr, const ModSample *smp) const;
uint32 CalculateXParam(PATTERNINDEX pat, ROWINDEX row, CHANNELINDEX chn, bool *isExtended = nullptr) const;
void KeyOff(ModChannel &chn) const;
void SetTempo(TEMPO param, bool setAsNonModcommand = false);
void SetSpeed(PlayState &playState, uint32 param) const;
static TEMPO ConvertST2Tempo(uint8 tempo);
protected:
void SetType(MODTYPE type);
void InitializeGlobals(MODTYPE type = MOD_TYPE_NONE);
void InitializeChannels();
int GetVibratoDelta(int type, int position) const;
void ProcessVolumeSwing(ModChannel &chn, int &vol) const;
void ProcessPanningSwing(ModChannel &chn) const;
void ProcessTremolo(ModChannel &chn, int &vol) const;
void ProcessTremor(CHANNELINDEX nChn, int &vol);
bool IsEnvelopeProcessed(const ModChannel &chn, EnvelopeType env) const;
void ProcessVolumeEnvelope(ModChannel &chn, int &vol) const;
void ProcessPanningEnvelope(ModChannel &chn) const;
int ProcessPitchFilterEnvelope(ModChannel &chn, int &period) const;
void IncrementEnvelopePosition(ModChannel &chn, EnvelopeType envType) const;
void IncrementEnvelopePositions(ModChannel &chn) const;
void ProcessInstrumentFade(ModChannel &chn, int &vol) const;
void ProcessPitchPanSeparation(ModChannel &chn) const;
void ProcessPanbrello(ModChannel &chn) const;
void ProcessArpeggio(CHANNELINDEX nChn, int &period, Tuning::NOTEINDEXTYPE &arpeggioSteps);
void ProcessVibrato(CHANNELINDEX nChn, int &period, Tuning::RATIOTYPE &vibratoFactor);
void ProcessSampleAutoVibrato(ModChannel &chn, int &period, Tuning::RATIOTYPE &vibratoFactor, int &nPeriodFrac) const;
void ProcessRamping(ModChannel &chn) const;
SamplePosition GetChannelIncrement(const ModChannel &chn, uint32 period, int periodFrac) const;
protected:
enum PanningType
{
Pan4bit = 4,
Pan6bit = 6,
Pan8bit = 8,
};
void UpdateS3MEffectMemory(ModChannel &chn, ModCommand::PARAM param) const;
void PortamentoUp(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular = false);
void PortamentoDown(CHANNELINDEX nChn, ModCommand::PARAM param, const bool doFinePortamentoAsRegular = false);
void MidiPortamento(CHANNELINDEX nChn, int param, bool doFineSlides);
void FinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const;
void FinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const;
void ExtraFinePortamentoUp(ModChannel &chn, ModCommand::PARAM param) const;
void ExtraFinePortamentoDown(ModChannel &chn, ModCommand::PARAM param) const;
void PortamentoMPT(ModChannel &chn, int);
void PortamentoFineMPT(ModChannel &chn, int);
void PortamentoExtraFineMPT(ModChannel &chn, int);
void NoteSlide(ModChannel &chn, uint32 param, bool slideUp, bool retrig) const;
void TonePortamento(ModChannel &chn, uint32 param) const;
void Vibrato(ModChannel &chn, uint32 param) const;
void FineVibrato(ModChannel &chn, uint32 param) const;
void VolumeSlide(ModChannel &chn, ModCommand::PARAM param);
void PanningSlide(ModChannel &chn, ModCommand::PARAM param, bool memory = true);
void ChannelVolSlide(ModChannel &chn, ModCommand::PARAM param) const;
void FineVolumeUp(ModChannel &chn, ModCommand::PARAM param, bool volCol) const;
void FineVolumeDown(ModChannel &chn, ModCommand::PARAM param, bool volCol) const;
void Tremolo(ModChannel &chn, uint32 param) const;
void Panbrello(ModChannel &chn, uint32 param) const;
void Panning(ModChannel &chn, uint32 param, PanningType panBits) const;
void RetrigNote(CHANNELINDEX nChn, int param, int offset = 0);
void SampleOffset(ModChannel &chn, SmpLength param) const;
void ReverseSampleOffset(ModChannel &chn, ModCommand::PARAM param) const;
void NoteCut(CHANNELINDEX nChn, uint32 nTick, bool cutSample);
ROWINDEX PatternLoop(ModChannel &chn, uint32 param);
void ExtendedMODCommands(CHANNELINDEX nChn, ModCommand::PARAM param);
void ExtendedS3MCommands(CHANNELINDEX nChn, ModCommand::PARAM param);
void ExtendedChannelEffect(ModChannel &chn, uint32 param);
void InvertLoop(ModChannel &chn);
ROWINDEX PatternBreak(PlayState &state, CHANNELINDEX chn, uint8 param) const;
void GlobalVolSlide(ModCommand::PARAM param, uint8 &nOldGlobalVolSlide);
void ProcessMacroOnChannel(CHANNELINDEX nChn);
void ProcessMIDIMacro(CHANNELINDEX nChn, bool isSmooth, const char *macro, uint8 param = 0, PLUGINDEX plugin = 0);
float CalculateSmoothParamChange(float currentValue, float param) const;
uint32 SendMIDIData(CHANNELINDEX nChn, bool isSmooth, const unsigned char *macro, uint32 macroLen, PLUGINDEX plugin);
void SendMIDINote(CHANNELINDEX chn, uint16 note, uint16 volume);
int SetupChannelFilter(ModChannel &chn, bool bReset, int envModifier = 256) const;
void DoFreqSlide(ModChannel &chn, int32 nFreqSlide) const;
void UpdateTimeSignature();
public:
uint8 FrequencyToCutOff(double frequency) const;
uint32 CutOffToFrequency(uint32 nCutOff, int envModifier = 256) const;
bool PeriodsAreFrequencies() const
{
return m_SongFlags[SONG_LINEARSLIDES] && m_playBehaviour[kHertzInLinearMode] && GetType() != MOD_TYPE_XM;
}
static constexpr bool UseFinetuneAndTranspose(MODTYPE type)
{
return (type & (MOD_TYPE_AMF0 | MOD_TYPE_DIGI | MOD_TYPE_MED | MOD_TYPE_MOD | MOD_TYPE_MTM | MOD_TYPE_OKT | MOD_TYPE_SFX | MOD_TYPE_STP | MOD_TYPE_XM));
}
bool UseFinetuneAndTranspose() const
{
return UseFinetuneAndTranspose(GetType());
}
public:
uint32 GetNumTicksOnCurrentRow() const
{
return (m_PlayState.m_nMusicSpeed + m_PlayState.m_nFrameDelay) * std::max(m_PlayState.m_nPatternDelay, static_cast<uint32>(1));
}
bool DestroySample(SAMPLEINDEX nSample);
bool DestroySampleThreadsafe(SAMPLEINDEX nSample);
SAMPLEINDEX GetNextFreeSample(INSTRUMENTINDEX targetInstrument = INSTRUMENTINDEX_INVALID, SAMPLEINDEX start = 1) const;
INSTRUMENTINDEX GetNextFreeInstrument(INSTRUMENTINDEX start = 1) const;
bool IsSampleReferencedByInstrument(SAMPLEINDEX sample, INSTRUMENTINDEX instr) const;
ModInstrument *AllocateInstrument(INSTRUMENTINDEX instr, SAMPLEINDEX assignedSample = 0);
bool DestroyInstrument(INSTRUMENTINDEX nInstr, deleteInstrumentSamples removeSamples);
bool RemoveInstrumentSamples(INSTRUMENTINDEX nInstr, SAMPLEINDEX keepSample = SAMPLEINDEX_INVALID);
SAMPLEINDEX DetectUnusedSamples(std::vector<bool> &sampleUsed) const;
SAMPLEINDEX RemoveSelectedSamples(const std::vector<bool> &keepSamples);
void PropagateXMAutoVibrato(INSTRUMENTINDEX ins, VibratoType type, uint8 sweep, uint8 depth, uint8 rate);
bool ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false, bool includeInstrumentFormats = true);
bool ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false, FileReader *wsmpChunk = nullptr);
protected:
bool ReadW64Sample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false);
bool ReadPATSample(SAMPLEINDEX nSample, FileReader &file);
bool ReadS3ISample(SAMPLEINDEX nSample, FileReader &file);
bool ReadSBISample(SAMPLEINDEX sample, FileReader &file);
bool ReadCAFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false);
bool ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false);
bool ReadAUSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize = false);
bool ReadXISample(SAMPLEINDEX nSample, FileReader &file);
bool ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewind = true);
bool ReadITISample(SAMPLEINDEX nSample, FileReader &file);
bool ReadIFFSample(SAMPLEINDEX nInstr, FileReader &file);
bool ReadFLACSample(SAMPLEINDEX sample, FileReader &file);
bool ReadOpusSample(SAMPLEINDEX sample, FileReader &file);
bool ReadVorbisSample(SAMPLEINDEX sample, FileReader &file);
bool ReadMP3Sample(SAMPLEINDEX sample, FileReader &file, bool raw = false, bool mo3Decode = false); bool ReadMediaFoundationSample(SAMPLEINDEX sample, FileReader &file, bool mo3Decode = false); public:
#ifdef MODPLUG_TRACKER
static std::vector<FileType> GetMediaFoundationFileTypes();
#endif #ifndef MODPLUG_NO_FILESAVE
bool SaveWAVSample(SAMPLEINDEX nSample, std::ostream &f) const;
bool SaveRAWSample(SAMPLEINDEX nSample, std::ostream &f) const;
bool SaveFLACSample(SAMPLEINDEX nSample, std::ostream &f) const;
bool SaveS3ISample(SAMPLEINDEX smp, std::ostream &f) const;
#endif
static bool CanReadMP3();
static bool CanReadVorbis();
static bool CanReadMediaFoundation();
bool ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize=false);
bool ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize=false);
protected:
bool ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
bool ReadITIInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
bool ReadPATInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
bool ReadSFZInstrument(INSTRUMENTINDEX nInstr, FileReader &file);
public:
#ifndef MODPLUG_NO_FILESAVE
bool SaveXIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f) const;
bool SaveITIInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, const mpt::PathString &filename, bool compress, bool allowExternal) const;
bool SaveSFZInstrument(INSTRUMENTINDEX nInstr, std::ostream &f, const mpt::PathString &filename, bool useFLACsamples) const;
#endif
bool ReadInstrumentFromSong(INSTRUMENTINDEX targetInstr, const CSoundFile &srcSong, INSTRUMENTINDEX sourceInstr);
bool ReadSampleFromSong(SAMPLEINDEX targetSample, const CSoundFile &srcSong, SAMPLEINDEX sourceSample);
uint32 GetNoteFromPeriod(uint32 period, int32 nFineTune = 0, uint32 nC5Speed = 0) const;
uint32 GetPeriodFromNote(uint32 note, int32 nFineTune, uint32 nC5Speed) const;
uint32 GetFreqFromPeriod(uint32 period, uint32 c5speed, int32 nPeriodFrac = 0) const;
ModSample &GetSample(SAMPLEINDEX sample) { MPT_ASSERT(sample <= m_nSamples && sample < CountOf(Samples)); return Samples[sample]; }
const ModSample &GetSample(SAMPLEINDEX sample) const { MPT_ASSERT(sample <= m_nSamples && sample < CountOf(Samples)); return Samples[sample]; }
uint32 MapMidiInstrument(uint8 program, uint16 bank, uint8 midiChannel, uint8 note, bool isXG, std::bitset<16> drumChns);
size_t ITInstrToMPT(FileReader &file, ModInstrument &ins, uint16 trkvers);
bool LoadMixPlugins(FileReader &file);
#ifndef NO_PLUGINS
static void ReadMixPluginChunk(FileReader &file, SNDMIXPLUGIN &plugin);
void ProcessMidiOut(CHANNELINDEX nChn);
#endif
void ProcessGlobalVolume(long countChunk);
void ProcessStereoSeparation(long countChunk);
private:
PLUGINDEX GetChannelPlugin(CHANNELINDEX nChn, PluginMutePriority respectMutes) const;
PLUGINDEX GetActiveInstrumentPlugin(CHANNELINDEX, PluginMutePriority respectMutes) const;
IMixPlugin *GetChannelInstrumentPlugin(CHANNELINDEX chn) const;
void HandlePatternTransitionEvents();
public:
PLUGINDEX GetBestPlugin(CHANNELINDEX nChn, PluginPriority priority, PluginMutePriority respectMutes) const;
uint8 GetBestMidiChannel(CHANNELINDEX nChn) const;
};
#ifndef NO_PLUGINS
inline IMixPlugin* CSoundFile::GetInstrumentPlugin(INSTRUMENTINDEX instr)
{
if(instr > 0 && instr <= GetNumInstruments() && Instruments[instr] && Instruments[instr]->nMixPlug && Instruments[instr]->nMixPlug <= MAX_MIXPLUGINS)
return m_MixPlugins[Instruments[instr]->nMixPlug - 1].pMixPlugin;
else
return nullptr;
}
#endif
#define FADESONGDELAY 100
static MPT_CONSTEXPR11_FUN int8 MOD2XMFineTune(int v) { return static_cast<int8>(static_cast<uint8>(v) << 4); }
static MPT_CONSTEXPR11_FUN int8 XM2MODFineTune(int v) { return static_cast<int8>(static_cast<uint8>(v) >> 4); }
void ReadInstrumentExtensionField(ModInstrument* pIns, const uint32 code, const uint16 size, FileReader &file);
void ReadExtendedInstrumentProperty(ModInstrument* pIns, const uint32 code, FileReader &file);
void ReadExtendedInstrumentProperties(ModInstrument* pIns, FileReader &file);
OPENMPT_NAMESPACE_END