diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h b/Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h new file mode 100644 index 00000000..12d1952d --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h @@ -0,0 +1,219 @@ +/* + * ModSequence.h + * ------------- + * Purpose: Order and sequence handling. + * 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 "Snd_defs.h" + +#include <algorithm> +#include <vector> + +OPENMPT_NAMESPACE_BEGIN + +class CPattern; +class CSoundFile; +class ModSequenceSet; + +class ModSequence: public std::vector<PATTERNINDEX> +{ + friend class ModSequenceSet; + +protected: + mpt::ustring m_name; // Sequence name + CSoundFile &m_sndFile; // Associated CSoundFile + ORDERINDEX m_restartPos = 0; // Restart position when playback of this order ended + +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()); } + // Returns last accessible index, i.e. GetLength() - 1, or 0 if the order list is empty. + ORDERINDEX GetLastIndex() const { return std::max(ORDERINDEX(1), GetLength()) - 1u; } + // Returns length of sequence without counting trailing '---' items. + ORDERINDEX GetLengthTailTrimmed() const; + // Returns length of sequence stopping counting on first '---' (or at the end of sequence). + ORDERINDEX GetLengthFirstEmpty() const; + + // Replaces order list with 'newSize' copies of 'pat'. + void assign(ORDERINDEX newSize, PATTERNINDEX pat); + + // Inserts 'count' orders starting from 'pos' using 'fill' as the pattern index for all inserted orders. + // Sequence will automatically grow if needed and if it can't grow enough, some tail orders will be discarded. + // Return: Number of orders inserted (up to 'count' many). + 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); } + + // Removes orders from range [posBegin, posEnd]. + void Remove(ORDERINDEX posBegin, ORDERINDEX posEnd); + + // Remove all references to a given pattern index from the order list. Jump commands are updated accordingly. + void RemovePattern(PATTERNINDEX pat); + + // Replaces all occurences of oldPat with newPat. + void Replace(PATTERNINDEX oldPat, PATTERNINDEX newPat) { if(oldPat != newPat) std::replace(begin(), end(), oldPat, newPat); } + + // Removes any "---" patterns at the end of the list. + void Shrink() { resize(GetLengthTailTrimmed()); } + + // Check if pattern at sequence position ord is valid. + bool IsValidPat(ORDERINDEX ord) const; + + CPattern *PatternAt(ORDERINDEX ord) const; + + void AdjustToNewModType(const MODTYPE oldtype); + + // Returns the internal representation of a stop '---' index + static constexpr PATTERNINDEX GetInvalidPatIndex() { return uint16_max; } + // Returns the internal representation of an ignore '+++' index + static constexpr PATTERNINDEX GetIgnoreIndex() { return uint16_max - 1; } + + // Returns the previous/next order ignoring skip indices (+++). + // If no previous/next order exists, return first/last order, and zero + // when orderlist is empty. + ORDERINDEX GetPreviousOrderIgnoringSkips(const ORDERINDEX start) const; + ORDERINDEX GetNextOrderIgnoringSkips(const ORDERINDEX start) const; + + // Find an order item that contains a given pattern number. + ORDERINDEX FindOrder(PATTERNINDEX pat, ORDERINDEX startSearchAt = 0, bool searchForward = true) const; + + // Ensures that the pattern at the specified order position is used only once (across all sequences). + // If another usage is found, the pattern is replaced by a copy and the new index is returned. + PATTERNINDEX EnsureUnique(ORDERINDEX ord); + +#ifndef MODPLUG_NO_FILESAVE + // Write order items as bytes. '---' is written as stopIndex, '+++' is written as ignoreIndex + size_t WriteAsByte(std::ostream &f, const ORDERINDEX count, uint8 stopIndex = 0xFF, uint8 ignoreIndex = 0xFE) const; +#endif // MODPLUG_NO_FILESAVE + + // Returns true if the IT orderlist datafield is not sufficient to store orderlist information. + bool NeedsExtraDatafield() const; + +#ifdef MODPLUG_TRACKER + // Check if a playback position is currently locked (inaccessible) + bool IsPositionLocked(ORDERINDEX position) const; + // Check if this sequence has subsongs separated by invalid ("---" or non-existing) patterns + bool HasSubsongs() const; +#endif // MODPLUG_TRACKER + + // Sequence name setter / getter + inline void SetName(const mpt::ustring &newName) { m_name = newName;} + inline mpt::ustring GetName() const { return m_name; } + + // Restart position setter / getter + inline void SetRestartPos(ORDERINDEX restartPos) noexcept { m_restartPos = restartPos; } + inline ORDERINDEX GetRestartPos() const noexcept { 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, mpt::Charset defaultCharset); + +protected: + std::vector<ModSequence> m_Sequences; // Array of sequences + CSoundFile &m_sndFile; + SEQUENCEINDEX m_currentSeq = 0; // Index of current sequence. + +public: + ModSequenceSet(CSoundFile &sndFile); + ModSequenceSet(ModSequenceSet &&) noexcept = default; + + // Remove all sequences and initialize default sequence + void Initialize(); + + // Get the working sequence + ModSequence& operator() () { return m_Sequences[m_currentSeq]; } + const ModSequence& operator() () const { return m_Sequences[m_currentSeq]; } + // Get an arbitrary sequence + 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; } + + // Sets working sequence. + void SetSequence(SEQUENCEINDEX); + // Add new empty sequence. + // Returns the ID of the new sequence, or SEQUENCEINDEX_INVALID on failure. + SEQUENCEINDEX AddSequence(); + // Removes given sequence. + void RemoveSequence(SEQUENCEINDEX); + + // Returns the internal representation of a stop '---' index + static constexpr PATTERNINDEX GetInvalidPatIndex() { return ModSequence::GetInvalidPatIndex(); } + // Returns the internal representation of an ignore '+++' index + static constexpr PATTERNINDEX GetIgnoreIndex() { return ModSequence::GetIgnoreIndex(); } + +#ifdef MODPLUG_TRACKER + // Assigns a new set of sequences. The vector contents indicate which existing sequences to keep / duplicate or if a new sequences should be inserted (SEQUENCEINDEX_INVALID) + // The function fails if the vector is empty or contains too many sequences. + bool Rearrange(const std::vector<SEQUENCEINDEX> &newOrder); + + // Adjust sequence when converting between module formats + void OnModTypeChanged(MODTYPE oldType); + // Check if there is a single sequences that qualifies for subsong splitting + bool CanSplitSubsongs() const; + // If there are subsongs (separated by "---" patterns) in the module, + // asks user whether to convert these into multiple sequences (given that the + // modformat supports multiple sequences). + // Returns true if sequences were modified, false otherwise. + bool SplitSubsongsToMultipleSequences(); + + // Convert the sequence's restart position information to a pattern command. + bool RestartPosToPattern(SEQUENCEINDEX seq); + // Merges multiple sequences into one and destroys all other sequences. + // Returns false if there were no sequences to merge, true otherwise. + bool MergeSequences(); +#endif // MODPLUG_TRACKER + + 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 // MODPLUG_NO_FILESAVE +void ReadModSequences(std::istream& iStrm, ModSequenceSet& seq, const size_t nSize, mpt::Charset defaultCharset); + +#ifndef MODPLUG_NO_FILESAVE +void WriteModSequence(std::ostream& oStrm, const ModSequence& seq); +#endif // MODPLUG_NO_FILESAVE +void ReadModSequence(std::istream& iStrm, ModSequence& seq, const size_t, mpt::Charset defaultCharset); + +#ifndef MODPLUG_NO_FILESAVE +void WriteModSequenceOld(std::ostream& oStrm, const ModSequenceSet& seq); +#endif // MODPLUG_NO_FILESAVE +void ReadModSequenceOld(std::istream& iStrm, ModSequenceSet& seq, const size_t); + + +OPENMPT_NAMESPACE_END |