aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/soundlib/ModSequence.h
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-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.h219
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