#pragma once
#include "BuildSettings.h"
#include <vector>
#include "modcommand.h"
#include "Snd_defs.h"
OPENMPT_NAMESPACE_BEGIN
class CPatternContainer;
class CSoundFile;
class EffectWriter;
typedef ModCommand* PatternRow;
class CPattern
{
friend class CPatternContainer;
public:
CPattern& operator= (const CPattern &pat);
bool operator== (const CPattern &other) const;
bool operator!= (const CPattern &other) const { return !(*this == other); }
public:
ModCommand* GetpModCommand(const ROWINDEX r, const CHANNELINDEX c) { return &m_ModCommands[r * GetNumChannels() + c]; }
const ModCommand* GetpModCommand(const ROWINDEX r, const CHANNELINDEX c) const { return &m_ModCommands[r * GetNumChannels() + c]; }
ROWINDEX GetNumRows() const { return m_Rows; }
ROWINDEX GetRowsPerBeat() const { return m_RowsPerBeat; } ROWINDEX GetRowsPerMeasure() const { return m_RowsPerMeasure; } bool GetOverrideSignature() const { return (m_RowsPerBeat + m_RowsPerMeasure > 0); }
bool IsValidRow(const ROWINDEX row) const { return (row < GetNumRows()); }
bool IsValid() const { return !m_ModCommands.empty(); }
PatternRow GetRow(const ROWINDEX row) { return GetpModCommand(row, 0); }
PatternRow GetRow(const ROWINDEX row) const { return const_cast<ModCommand *>(GetpModCommand(row, 0)); }
CHANNELINDEX GetNumChannels() const;
bool Resize(const ROWINDEX newRowCount, bool enforceFormatLimits = true, bool resizeAtEnd = true);
bool IsEmptyRow(ROWINDEX row) const;
bool AllocatePattern(ROWINDEX rows);
void Deallocate();
void ClearCommands();
CSoundFile& GetSoundFile();
const CSoundFile& GetSoundFile() const;
const std::vector<ModCommand> &GetData() const { return m_ModCommands; }
void SetData(std::vector<ModCommand> &&data) { MPT_ASSERT(data.size() == GetNumRows() * GetNumChannels()); m_ModCommands = std::move(data); }
bool SetSignature(const ROWINDEX rowsPerBeat, const ROWINDEX rowsPerMeasure);
void RemoveSignature() { m_RowsPerBeat = m_RowsPerMeasure = 0; }
bool HasTempoSwing() const { return !m_tempoSwing.empty(); }
const TempoSwing& GetTempoSwing() const { return m_tempoSwing; }
void SetTempoSwing(const TempoSwing &swing) { m_tempoSwing = swing; m_tempoSwing.Normalize(); }
void RemoveTempoSwing() { m_tempoSwing.clear(); }
bool SetName(const std::string &newName);
bool SetName(const char *newName, size_t maxChars);
template<size_t bufferSize>
bool SetName(const char (&buffer)[bufferSize])
{
return SetName(buffer, bufferSize);
}
std::string GetName() const { return m_PatternName; }
#ifdef MODPLUG_TRACKER
bool Expand();
bool Shrink();
#endif
bool WriteEffect(EffectWriter &settings);
typedef std::vector<ModCommand>::iterator iterator;
typedef std::vector<ModCommand>::const_iterator const_iterator;
iterator begin() { return m_ModCommands.begin(); }
const_iterator begin() const { return m_ModCommands.begin(); }
const_iterator cbegin() const { return m_ModCommands.cbegin(); }
iterator end() { return m_ModCommands.end(); }
const_iterator end() const { return m_ModCommands.end(); }
const_iterator cend() const { return m_ModCommands.cend(); }
CPattern(CPatternContainer& patCont) : m_rPatternContainer(patCont) {}
CPattern(const CPattern &) = default;
CPattern(CPattern &&) noexcept = default;
protected:
ModCommand& GetModCommand(size_t i) { return m_ModCommands[i]; }
ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) { return m_ModCommands[r * GetNumChannels() + c]; }
const ModCommand& GetModCommand(ROWINDEX r, CHANNELINDEX c) const { return m_ModCommands[r * GetNumChannels() + c]; }
protected:
std::vector<ModCommand> m_ModCommands;
ROWINDEX m_Rows = 0;
ROWINDEX m_RowsPerBeat = 0; ROWINDEX m_RowsPerMeasure = 0; TempoSwing m_tempoSwing;
std::string m_PatternName;
CPatternContainer& m_rPatternContainer;
};
const char FileIdPattern[] = "mptP";
void ReadModPattern(std::istream& iStrm, CPattern& patc, const size_t nSize = 0);
void WriteModPattern(std::ostream& oStrm, const CPattern& patc);
class EffectWriter
{
friend class CPattern;
enum RetryMode
{
rmIgnore, rmTryNextRow, rmTryPreviousRow, };
public:
EffectWriter(EffectCommand cmd, ModCommand::PARAM param) : m_command(cmd), m_param(param), m_isVolEffect(false) { Init(); }
EffectWriter(VolumeCommand cmd, ModCommand::VOL param) : m_volcmd(cmd), m_vol(param), m_isVolEffect(true) { Init(); }
EffectWriter &Row(ROWINDEX row) { m_row = row; return *this; }
EffectWriter &Channel(CHANNELINDEX chn) { m_channel = chn; return *this; }
EffectWriter &AllowMultiple() { m_allowMultiple = true; return *this; }
EffectWriter &RetryNextRow() { m_retryMode = rmTryNextRow; return *this; }
EffectWriter &RetryPreviousRow() { m_retryMode = rmTryPreviousRow; return *this; }
protected:
RetryMode m_retryMode;
ROWINDEX m_row;
CHANNELINDEX m_channel;
union
{
EffectCommand m_command;
VolumeCommand m_volcmd;
};
union
{
ModCommand::PARAM m_param;
ModCommand::VOL m_vol;
};
bool m_retry : 1;
bool m_allowMultiple : 1;
bool m_isVolEffect : 1;
void Init()
{
m_row = 0;
m_channel = CHANNELINDEX_INVALID; m_retryMode = rmIgnore; m_retry = true;
m_allowMultiple = false; }
};
OPENMPT_NAMESPACE_END