1 /*
2 * PatternContainer.cpp
3 * --------------------
4 * Purpose: Container class for managing patterns.
5 * Notes : (currently none)
6 * Authors: OpenMPT Devs
7 * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
8 */
9
10
11 #include "stdafx.h"
12 #include "patternContainer.h"
13 #include "Sndfile.h"
14 #include "mod_specifications.h"
15 #include "../common/serialization_utils.h"
16 #include "../common/version.h"
17
18
19 OPENMPT_NAMESPACE_BEGIN
20
21
ClearPatterns()22 void CPatternContainer::ClearPatterns()
23 {
24 DestroyPatterns();
25 m_Patterns.assign(m_Patterns.size(), CPattern(*this));
26 }
27
28
DestroyPatterns()29 void CPatternContainer::DestroyPatterns()
30 {
31 for(PATTERNINDEX i = 0; i < m_Patterns.size(); i++)
32 {
33 Remove(i);
34 }
35 }
36
37
Duplicate(PATTERNINDEX from,bool respectQtyLimits)38 PATTERNINDEX CPatternContainer::Duplicate(PATTERNINDEX from, bool respectQtyLimits)
39 {
40 if(!IsValidPat(from))
41 {
42 return PATTERNINDEX_INVALID;
43 }
44
45 PATTERNINDEX newPatIndex = InsertAny(m_Patterns[from].GetNumRows(), respectQtyLimits);
46
47 if(newPatIndex != PATTERNINDEX_INVALID)
48 {
49 m_Patterns[newPatIndex] = m_Patterns[from];
50 }
51 return newPatIndex;
52 }
53
54
InsertAny(const ROWINDEX rows,bool respectQtyLimits)55 PATTERNINDEX CPatternContainer::InsertAny(const ROWINDEX rows, bool respectQtyLimits)
56 {
57 PATTERNINDEX i = 0;
58 for(i = 0; i < m_Patterns.size(); i++)
59 if(!m_Patterns[i].IsValid()) break;
60 if(respectQtyLimits && i >= m_rSndFile.GetModSpecifications().patternsMax)
61 return PATTERNINDEX_INVALID;
62 if(!Insert(i, rows))
63 return PATTERNINDEX_INVALID;
64 else return i;
65 }
66
67
Insert(const PATTERNINDEX index,const ROWINDEX rows)68 bool CPatternContainer::Insert(const PATTERNINDEX index, const ROWINDEX rows)
69 {
70 if(rows > MAX_PATTERN_ROWS || rows == 0)
71 return false;
72 if(IsValidPat(index))
73 return false;
74
75 try
76 {
77 if(index >= m_Patterns.size())
78 {
79 m_Patterns.resize(index + 1, CPattern(*this));
80 }
81 m_Patterns[index].AllocatePattern(rows);
82 m_Patterns[index].RemoveSignature();
83 m_Patterns[index].SetName("");
84 } catch(mpt::out_of_memory e)
85 {
86 mpt::delete_out_of_memory(e);
87 return false;
88 }
89 return m_Patterns[index].IsValid();
90 }
91
92
Remove(const PATTERNINDEX ipat)93 void CPatternContainer::Remove(const PATTERNINDEX ipat)
94 {
95 if(ipat < m_Patterns.size()) m_Patterns[ipat].Deallocate();
96 }
97
98
IsPatternEmpty(const PATTERNINDEX nPat) const99 bool CPatternContainer::IsPatternEmpty(const PATTERNINDEX nPat) const
100 {
101 if(!IsValidPat(nPat))
102 return false;
103
104 for(const auto &m : m_Patterns[nPat].m_ModCommands)
105 {
106 if(!m.IsEmpty())
107 return false;
108 }
109 return true;
110 }
111
112
ResizeArray(const PATTERNINDEX newSize)113 void CPatternContainer::ResizeArray(const PATTERNINDEX newSize)
114 {
115 m_Patterns.resize(newSize, CPattern(*this));
116 }
117
118
OnModTypeChanged(const MODTYPE)119 void CPatternContainer::OnModTypeChanged(const MODTYPE /*oldtype*/)
120 {
121 const CModSpecifications specs = m_rSndFile.GetModSpecifications();
122 //if(specs.patternsMax < Size())
123 // ResizeArray(specs.patternsMax);
124
125 // remove pattern time signatures
126 if(!specs.hasPatternSignatures)
127 {
128 for(PATTERNINDEX nPat = 0; nPat < m_Patterns.size(); nPat++)
129 {
130 m_Patterns[nPat].RemoveSignature();
131 m_Patterns[nPat].RemoveTempoSwing();
132 }
133 }
134 }
135
136
GetNumPatterns() const137 PATTERNINDEX CPatternContainer::GetNumPatterns() const
138 {
139 for(PATTERNINDEX pat = Size(); pat > 0; pat--)
140 {
141 if(IsValidPat(pat - 1))
142 {
143 return pat;
144 }
145 }
146 return 0;
147 }
148
149
GetNumNamedPatterns() const150 PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const
151 {
152 if(Size() == 0)
153 {
154 return 0;
155 }
156 for(PATTERNINDEX nPat = Size(); nPat > 0; nPat--)
157 {
158 if(!m_Patterns[nPat - 1].GetName().empty())
159 {
160 return nPat;
161 }
162 }
163 return 0;
164 }
165
166
167
WriteModPatterns(std::ostream & oStrm,const CPatternContainer & patc)168 void WriteModPatterns(std::ostream& oStrm, const CPatternContainer& patc)
169 {
170 srlztn::SsbWrite ssb(oStrm);
171 ssb.BeginWrite(FileIdPatterns, Version::Current().GetRawVersion());
172 const PATTERNINDEX nPatterns = patc.Size();
173 uint16 nCount = 0;
174 for(uint16 i = 0; i < nPatterns; i++) if (patc[i].IsValid())
175 {
176 ssb.WriteItem(patc[i], srlztn::ID::FromInt<uint16>(i), &WriteModPattern);
177 nCount = i + 1;
178 }
179 ssb.WriteItem<uint16>(nCount, "num"); // Index of last pattern + 1.
180 ssb.FinishWrite();
181 }
182
183
ReadModPatterns(std::istream & iStrm,CPatternContainer & patc,const size_t)184 void ReadModPatterns(std::istream& iStrm, CPatternContainer& patc, const size_t)
185 {
186 srlztn::SsbRead ssb(iStrm);
187 ssb.BeginRead(FileIdPatterns, Version::Current().GetRawVersion());
188 if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0)
189 return;
190 PATTERNINDEX nPatterns = patc.Size();
191 uint16 nCount = uint16_max;
192 if (ssb.ReadItem(nCount, "num") != srlztn::SsbRead::EntryNotFound)
193 nPatterns = nCount;
194 LimitMax(nPatterns, ModSpecs::mptm.patternsMax);
195 if (nPatterns > patc.Size())
196 patc.ResizeArray(nPatterns);
197 for(uint16 i = 0; i < nPatterns; i++)
198 {
199 ssb.ReadItem(patc[i], srlztn::ID::FromInt<uint16>(i), &ReadModPattern);
200 }
201 }
202
203
204 OPENMPT_NAMESPACE_END
205