winamp/Src/external_dependencies/openmpt-trunk/soundlib/patternContainer.cpp
2024-09-24 14:54:57 +02:00

202 lines
4.3 KiB
C++

/*
* PatternContainer.cpp
* --------------------
* Purpose: Container class for managing patterns.
* Notes : (currently none)
* Authors: OpenMPT Devs
* The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
*/
#include "stdafx.h"
#include "patternContainer.h"
#include "Sndfile.h"
#include "mod_specifications.h"
#include "../common/serialization_utils.h"
#include "../common/version.h"
OPENMPT_NAMESPACE_BEGIN
void CPatternContainer::ClearPatterns()
{
DestroyPatterns();
m_Patterns.assign(m_Patterns.size(), CPattern(*this));
}
void CPatternContainer::DestroyPatterns()
{
m_Patterns.clear();
}
PATTERNINDEX CPatternContainer::Duplicate(PATTERNINDEX from, bool respectQtyLimits)
{
if(!IsValidPat(from))
{
return PATTERNINDEX_INVALID;
}
PATTERNINDEX newPatIndex = InsertAny(m_Patterns[from].GetNumRows(), respectQtyLimits);
if(newPatIndex != PATTERNINDEX_INVALID)
{
m_Patterns[newPatIndex] = m_Patterns[from];
}
return newPatIndex;
}
PATTERNINDEX CPatternContainer::InsertAny(const ROWINDEX rows, bool respectQtyLimits)
{
PATTERNINDEX i = 0;
for(i = 0; i < m_Patterns.size(); i++)
if(!m_Patterns[i].IsValid()) break;
if(respectQtyLimits && i >= m_rSndFile.GetModSpecifications().patternsMax)
return PATTERNINDEX_INVALID;
if(!Insert(i, rows))
return PATTERNINDEX_INVALID;
else return i;
}
bool CPatternContainer::Insert(const PATTERNINDEX index, const ROWINDEX rows)
{
if(rows > MAX_PATTERN_ROWS || rows == 0 || index >= PATTERNINDEX_INVALID)
return false;
if(IsValidPat(index))
return false;
try
{
if(index >= m_Patterns.size())
{
m_Patterns.resize(index + 1, CPattern(*this));
}
m_Patterns[index].AllocatePattern(rows);
m_Patterns[index].RemoveSignature();
m_Patterns[index].SetName("");
} catch(mpt::out_of_memory e)
{
mpt::delete_out_of_memory(e);
return false;
}
return m_Patterns[index].IsValid();
}
void CPatternContainer::Remove(const PATTERNINDEX ipat)
{
if(ipat < m_Patterns.size()) m_Patterns[ipat].Deallocate();
}
bool CPatternContainer::IsPatternEmpty(const PATTERNINDEX nPat) const
{
if(!IsValidPat(nPat))
return false;
for(const auto &m : m_Patterns[nPat].m_ModCommands)
{
if(!m.IsEmpty())
return false;
}
return true;
}
void CPatternContainer::ResizeArray(const PATTERNINDEX newSize)
{
m_Patterns.resize(newSize, CPattern(*this));
}
void CPatternContainer::OnModTypeChanged(const MODTYPE /*oldtype*/)
{
const CModSpecifications specs = m_rSndFile.GetModSpecifications();
//if(specs.patternsMax < Size())
// ResizeArray(specs.patternsMax);
// remove pattern time signatures
if(!specs.hasPatternSignatures)
{
for(PATTERNINDEX nPat = 0; nPat < m_Patterns.size(); nPat++)
{
m_Patterns[nPat].RemoveSignature();
m_Patterns[nPat].RemoveTempoSwing();
}
}
}
PATTERNINDEX CPatternContainer::GetNumPatterns() const
{
for(PATTERNINDEX pat = Size(); pat > 0; pat--)
{
if(IsValidPat(pat - 1))
{
return pat;
}
}
return 0;
}
PATTERNINDEX CPatternContainer::GetNumNamedPatterns() const
{
if(Size() == 0)
{
return 0;
}
for(PATTERNINDEX nPat = Size(); nPat > 0; nPat--)
{
if(!m_Patterns[nPat - 1].GetName().empty())
{
return nPat;
}
}
return 0;
}
void WriteModPatterns(std::ostream& oStrm, const CPatternContainer& patc)
{
srlztn::SsbWrite ssb(oStrm);
ssb.BeginWrite(FileIdPatterns, Version::Current().GetRawVersion());
const PATTERNINDEX nPatterns = patc.Size();
uint16 nCount = 0;
for(uint16 i = 0; i < nPatterns; i++) if (patc[i].IsValid())
{
ssb.WriteItem(patc[i], srlztn::ID::FromInt<uint16>(i), &WriteModPattern);
nCount = i + 1;
}
ssb.WriteItem<uint16>(nCount, "num"); // Index of last pattern + 1.
ssb.FinishWrite();
}
void ReadModPatterns(std::istream& iStrm, CPatternContainer& patc, const size_t)
{
srlztn::SsbRead ssb(iStrm);
ssb.BeginRead(FileIdPatterns, Version::Current().GetRawVersion());
if ((ssb.GetStatus() & srlztn::SNT_FAILURE) != 0)
return;
PATTERNINDEX nPatterns = patc.Size();
uint16 nCount = uint16_max;
if (ssb.ReadItem(nCount, "num") != srlztn::SsbRead::EntryNotFound)
nPatterns = nCount;
LimitMax(nPatterns, ModSpecs::mptm.patternsMax);
if (nPatterns > patc.Size())
patc.ResizeArray(nPatterns);
for(uint16 i = 0; i < nPatterns; i++)
{
ssb.ReadItem(patc[i], srlztn::ID::FromInt<uint16>(i), &ReadModPattern);
}
}
OPENMPT_NAMESPACE_END