#pragma once
#include "BuildSettings.h"
#include <algorithm>
#include <vector>
#include "Snd_defs.h"
OPENMPT_NAMESPACE_BEGIN
class CSoundFile;
class ModSequenceSet;
class ModSequence: public std::vector<PATTERNINDEX>
{
friend class ModSequenceSet;
protected:
std::string m_name; CSoundFile &m_sndFile; ORDERINDEX m_restartPos;
public:
ModSequence(CSoundFile &sndFile);
ModSequence(ModSequence &&) noexcept = default;
ModSequence(const ModSequence &) = default;
ModSequence& operator=(const ModSequence &other);
bool operator==(const ModSequence &other) const;
bool operator!=(const ModSequence &other) const { return !(*this == other); }
ORDERINDEX GetLength() const { return mpt::saturate_cast<ORDERINDEX>(size()); }
ORDERINDEX GetLastIndex() const { return std::max(ORDERINDEX(1), GetLength()) - 1u; }
ORDERINDEX GetLengthTailTrimmed() const;
ORDERINDEX GetLengthFirstEmpty() const;
void assign(ORDERINDEX newSize, PATTERNINDEX pat);
ORDERINDEX insert(ORDERINDEX pos, ORDERINDEX count) { return insert(pos, count, GetInvalidPatIndex()); }
ORDERINDEX insert(ORDERINDEX pos, ORDERINDEX count, PATTERNINDEX fill);
void push_back() { push_back(GetInvalidPatIndex()); }
void push_back(PATTERNINDEX pat) { if(GetLength() < MAX_ORDERS) std::vector<PATTERNINDEX>::push_back(pat); }
void resize(ORDERINDEX newSize) { resize(newSize, GetInvalidPatIndex()); }
void resize(ORDERINDEX newSize, PATTERNINDEX pat) { std::vector<PATTERNINDEX>::resize(std::min(MAX_ORDERS, newSize), pat); }
void Remove(ORDERINDEX posBegin, ORDERINDEX posEnd);
void RemovePattern(PATTERNINDEX pat);
void Replace(PATTERNINDEX oldPat, PATTERNINDEX newPat) { if(oldPat != newPat) std::replace(begin(), end(), oldPat, newPat); }
void Shrink() { resize(GetLengthTailTrimmed()); }
bool IsValidPat(ORDERINDEX ord) const;
void AdjustToNewModType(const MODTYPE oldtype);
static PATTERNINDEX GetInvalidPatIndex() { return uint16_max; }
static PATTERNINDEX GetIgnoreIndex() { return uint16_max - 1; }
ORDERINDEX GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const;
ORDERINDEX GetNextOrderIgnoringSkips(const ORDERINDEX start) const;
ORDERINDEX FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt = 0, bool searchForward = true) const;
PATTERNINDEX EnsureUnique(ORDERINDEX ord);
#ifndef MODPLUG_NO_FILESAVE
size_t WriteAsByte(std::ostream &f, const ORDERINDEX count, uint8 stopIndex = 0xFF, uint8 ignoreIndex = 0xFE) const;
#endif
bool NeedsExtraDatafield() const;
#ifdef MODPLUG_TRACKER
bool IsPositionLocked(ORDERINDEX position) const;
#endif
inline void SetName(const std::string &newName) { m_name = newName;}
inline std::string GetName() const { return m_name; }
inline void SetRestartPos(ORDERINDEX restartPos) { m_restartPos = restartPos; }
inline ORDERINDEX GetRestartPos() const { return m_restartPos; }
};
class ModSequenceSet
{
friend void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t);
friend void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t);
protected:
std::vector<ModSequence> m_Sequences; CSoundFile &m_sndFile;
SEQUENCEINDEX m_currentSeq;
public:
ModSequenceSet(CSoundFile &sndFile);
ModSequenceSet(ModSequenceSet &&) noexcept = default;
void Initialize();
ModSequence& operator() () { return m_Sequences[m_currentSeq]; }
const ModSequence& operator() () const { return m_Sequences[m_currentSeq]; }
ModSequence& operator() (SEQUENCEINDEX seq) { return m_Sequences[seq]; }
const ModSequence& operator() (SEQUENCEINDEX seq) const { return m_Sequences[seq]; }
SEQUENCEINDEX GetNumSequences() const { return static_cast<SEQUENCEINDEX>(m_Sequences.size()); }
SEQUENCEINDEX GetCurrentSequenceIndex() const { return m_currentSeq; }
void SetSequence(SEQUENCEINDEX);
SEQUENCEINDEX AddSequence(bool duplicate = true);
void RemoveSequence(SEQUENCEINDEX);
static PATTERNINDEX GetInvalidPatIndex() { return ModSequence::GetInvalidPatIndex(); }
static PATTERNINDEX GetIgnoreIndex() { return ModSequence::GetIgnoreIndex(); }
#ifdef MODPLUG_TRACKER
void OnModTypeChanged(MODTYPE oldType);
bool ConvertSubsongsToMultipleSequences();
bool RestartPosToPattern(SEQUENCEINDEX seq);
bool MergeSequences();
#endif
std::vector<ModSequence>::iterator begin() { return m_Sequences.begin(); }
std::vector<ModSequence>::const_iterator begin() const { return m_Sequences.begin(); }
std::vector<ModSequence>::const_iterator cbegin() const { return m_Sequences.cbegin(); }
std::vector<ModSequence>::iterator end() { return m_Sequences.end(); }
std::vector<ModSequence>::const_iterator end() const { return m_Sequences.end(); }
std::vector<ModSequence>::const_iterator cend() const { return m_Sequences.cend(); }
};
const char FileIdSequences[] = "mptSeqC";
const char FileIdSequence[] = "mptSeq";
#ifndef MODPLUG_NO_FILESAVE
void WriteModSequences(std::ostream& oStrm, const ModSequenceSet& seq);
#endif void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t nSize = 0);
#ifndef MODPLUG_NO_FILESAVE
void WriteModSequence(std::ostream& oStrm, const ModSequence& seq);
#endif void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t);
#ifndef MODPLUG_NO_FILESAVE
void WriteModSequenceOld(std::ostream& oStrm, const ModSequenceSet& seq);
#endif void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t);
OPENMPT_NAMESPACE_END