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/mptrack/AppendModule.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/AppendModule.cpp')
-rw-r--r-- | Src/external_dependencies/openmpt-trunk/mptrack/AppendModule.cpp | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/AppendModule.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/AppendModule.cpp new file mode 100644 index 00000000..a7dcf221 --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/mptrack/AppendModule.cpp @@ -0,0 +1,316 @@ +/* + * AppendModule.cpp + * ---------------- + * Purpose: Appending one module to an existing module + * 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 "Moddoc.h" +#include "../soundlib/mod_specifications.h" + + +OPENMPT_NAMESPACE_BEGIN + +// Add samples, instruments, plugins and patterns from another module to the current module +void CModDoc::AppendModule(const CSoundFile &source) +{ + const CModSpecifications &specs = m_SndFile.GetModSpecifications(); + // Mappings between old and new indices + std::vector<PLUGINDEX> pluginMapping(MAX_MIXPLUGINS + 1, 0); + std::vector<INSTRUMENTINDEX> instrMapping((source.GetNumInstruments() ? source.GetNumInstruments() : source.GetNumSamples()) + 1, INSTRUMENTINDEX_INVALID); + std::vector<ORDERINDEX> orderMapping; + std::vector<PATTERNINDEX> patternMapping(source.Patterns.GetNumPatterns(), PATTERNINDEX_INVALID); + + /////////////////////////////////////////////////////////////////////////// + // Copy plugins +#ifndef NO_PLUGINS + if(specs.supportsPlugins) + { + PLUGINDEX plug = 0; + for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++) + { + if(!source.m_MixPlugins[i].IsValidPlugin()) + { + continue; + } + while(plug < MAX_MIXPLUGINS && m_SndFile.m_MixPlugins[plug].IsValidPlugin()) + { + plug++; + } + if(plug < MAX_MIXPLUGINS) + { + ClonePlugin(m_SndFile.m_MixPlugins[plug], source.m_MixPlugins[i]); + pluginMapping[i + 1] = plug + 1; + } else + { + AddToLog("Too many plugins!"); + break; + } + } + // Fix up references between plugins + for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++) + { + if(pluginMapping[i + 1] != 0 && source.m_MixPlugins[i].GetOutputPlugin() < MAX_MIXPLUGINS) + { + m_SndFile.m_MixPlugins[pluginMapping[i + 1] - 1].SetOutputPlugin(pluginMapping[source.m_MixPlugins[i].GetOutputPlugin() + 1] - 1); + } + } + } +#endif // NO_PLUGINS + + /////////////////////////////////////////////////////////////////////////// + // Copy samples / instruments + if(source.GetNumInstruments() != 0 && m_SndFile.GetNumInstruments() == 0 && specs.instrumentsMax) + { + // Convert to instruments first + ConvertSamplesToInstruments(); + } + + // Check which samples / instruments are actually referenced. + for(const auto &pat : source.Patterns) if(pat.IsValid()) + { + for(const auto &m : pat) + { + if(!m.IsPcNote() && m.instr < instrMapping.size()) instrMapping[m.instr] = 0; + } + } + + if(m_SndFile.GetNumInstruments()) + { + INSTRUMENTINDEX targetIns = 0; + if(source.GetNumInstruments()) + { + for(INSTRUMENTINDEX i = 1; i <= source.GetNumInstruments(); i++) if(source.Instruments[i] != nullptr && !instrMapping[i]) + { + targetIns = m_SndFile.GetNextFreeInstrument(targetIns + 1); + if(targetIns == INSTRUMENTINDEX_INVALID) + { + AddToLog("Too many instruments!"); + break; + } + if(m_SndFile.ReadInstrumentFromSong(targetIns, source, i)) + { + ModInstrument *ins = m_SndFile.Instruments[targetIns]; + if(ins->nMixPlug <= MAX_MIXPLUGINS) + { + ins->nMixPlug = pluginMapping[ins->nMixPlug]; + } + instrMapping[i] = targetIns; + } + } + } else + { + SAMPLEINDEX targetSmp = 0; + for(SAMPLEINDEX i = 1; i <= source.GetNumSamples(); i++) if(!instrMapping[i]) + { + targetIns = m_SndFile.GetNextFreeInstrument(targetIns + 1); + targetSmp = m_SndFile.GetNextFreeSample(targetIns, targetSmp + 1); + if(targetIns == INSTRUMENTINDEX_INVALID) + { + AddToLog("Too many instruments!"); + break; + } else if(targetSmp == SAMPLEINDEX_INVALID) + { + AddToLog("Too many samples!"); + break; + } + if(m_SndFile.AllocateInstrument(targetIns, targetSmp) != nullptr) + { + m_SndFile.ReadSampleFromSong(targetSmp, source, i); + } + instrMapping[i] = targetIns; + } + } + } else + { + SAMPLEINDEX targetSmp = 0; + if(source.GetNumInstruments()) + { + for(INSTRUMENTINDEX i = 1; i <= source.GetNumInstruments(); i++) if(source.Instruments[i] != nullptr && !instrMapping[i]) + { + targetSmp = m_SndFile.GetNextFreeSample(INSTRUMENTINDEX_INVALID, targetSmp + 1); + if(targetSmp == SAMPLEINDEX_INVALID) + { + AddToLog("Too many samples!"); + break; + } + m_SndFile.ReadSampleFromSong(targetSmp, source, source.Instruments[i]->Keyboard[NOTE_MIDDLEC - NOTE_MIN]); + instrMapping[i] = targetSmp; + } + } else + { + for(SAMPLEINDEX i = 1; i <= source.GetNumSamples(); i++) if(!instrMapping[i]) + { + targetSmp = m_SndFile.GetNextFreeSample(INSTRUMENTINDEX_INVALID, targetSmp + 1); + if(targetSmp == SAMPLEINDEX_INVALID) + { + AddToLog("Too many samples!"); + break; + } + m_SndFile.ReadSampleFromSong(targetSmp, source, i); + instrMapping[i] = targetSmp; + } + } + } + + /////////////////////////////////////////////////////////////////////////// + // Copy order lists + const bool useOrderMapping = source.Order.GetNumSequences() == 1; + for(auto &srcOrder : source.Order) + { + ORDERINDEX insertPos = 0; + if(m_SndFile.Order.GetNumSequences() < specs.sequencesMax) + { + m_SndFile.Order.AddSequence(); + m_SndFile.Order().SetName(srcOrder.GetName()); + } else + { + insertPos = m_SndFile.Order().GetLengthTailTrimmed(); + if(specs.hasStopIndex) + insertPos++; + } + const ORDERINDEX ordLen = srcOrder.GetLengthTailTrimmed(); + if(useOrderMapping) orderMapping.resize(ordLen, ORDERINDEX_INVALID); + for(ORDERINDEX ord = 0; ord < ordLen; ord++) + { + if(insertPos >= specs.ordersMax) + { + AddToLog("Too many order items!"); + break; + } + + PATTERNINDEX insertPat = PATTERNINDEX_INVALID; + PATTERNINDEX srcPat = srcOrder[ord]; + if(source.Patterns.IsValidPat(srcPat) && srcPat < patternMapping.size()) + { + if(patternMapping[srcPat] == PATTERNINDEX_INVALID && source.Patterns.IsValidPat(srcPat)) + { + patternMapping[srcPat] = InsertPattern(Clamp(source.Patterns[srcPat].GetNumRows(), specs.patternRowsMin, specs.patternRowsMax)); + if(patternMapping[srcPat] == PATTERNINDEX_INVALID) + { + AddToLog("Too many patterns!"); + break; + } + } + if(patternMapping[srcPat] == PATTERNINDEX_INVALID) + { + continue; + } + insertPat = patternMapping[srcPat]; + } else if(srcPat == srcOrder.GetIgnoreIndex() && specs.hasIgnoreIndex) + { + insertPat = m_SndFile.Order.GetIgnoreIndex(); + } else if(srcPat == srcOrder.GetInvalidPatIndex() && specs.hasStopIndex) + { + insertPat = m_SndFile.Order.GetInvalidPatIndex(); + } else + { + continue; + } + m_SndFile.Order().insert(insertPos, 1, insertPat); + if(useOrderMapping) orderMapping[ord] = insertPos++; + } + } + + /////////////////////////////////////////////////////////////////////////// + // Adjust number of channels + if(source.GetNumChannels() > m_SndFile.GetNumChannels()) + { + CHANNELINDEX newChn = source.GetNumChannels(); + if(newChn > specs.channelsMax) + { + AddToLog("Too many channels!"); + newChn = specs.channelsMax; + } + if(newChn > m_SndFile.GetNumChannels()) + { + ChangeNumChannels(newChn, false); + } + } + + /////////////////////////////////////////////////////////////////////////// + // Copy patterns + const bool tempoSwingDiffers = source.m_tempoSwing != m_SndFile.m_tempoSwing; + const bool timeSigDiffers = source.m_nDefaultRowsPerBeat != m_SndFile.m_nDefaultRowsPerBeat || source.m_nDefaultRowsPerMeasure != m_SndFile.m_nDefaultRowsPerMeasure; + const CHANNELINDEX copyChannels = std::min(m_SndFile.GetNumChannels(), source.GetNumChannels()); + for(PATTERNINDEX pat = 0; pat < patternMapping.size(); pat++) + { + if(patternMapping[pat] == PATTERNINDEX_INVALID) + { + continue; + } + + const CPattern &sourcePat = source.Patterns[pat]; + CPattern &targetPat = m_SndFile.Patterns[patternMapping[pat]]; + + if(specs.hasPatternNames) + { + targetPat.SetName(sourcePat.GetName()); + } + if(specs.hasPatternSignatures) + { + if(sourcePat.GetOverrideSignature()) + { + targetPat.SetSignature(sourcePat.GetRowsPerBeat(), sourcePat.GetRowsPerMeasure()); + } else if(timeSigDiffers) + { + // Try fixing differing signature settings by copying them to the newly created patterns + targetPat.SetSignature(source.m_nDefaultRowsPerBeat, source.m_nDefaultRowsPerMeasure); + } + } + if(m_SndFile.m_nTempoMode == TempoMode::Modern) + { + // Swing only works in modern tempo mode + if(sourcePat.HasTempoSwing()) + { + targetPat.SetTempoSwing(sourcePat.GetTempoSwing()); + } else if(tempoSwingDiffers) + { + // Try fixing differing swing settings by copying them to the newly created patterns + targetPat.SetSignature(source.m_nDefaultRowsPerBeat, source.m_nDefaultRowsPerMeasure); + targetPat.SetTempoSwing(source.m_tempoSwing); + } + } + + const ROWINDEX copyRows = std::min(sourcePat.GetNumRows(), targetPat.GetNumRows()); + for(ROWINDEX row = 0; row < copyRows; row++) + { + const ModCommand *src = sourcePat.GetRow(row); + ModCommand *m = targetPat.GetRow(row); + for(CHANNELINDEX chn = 0; chn < copyChannels; chn++, src++, m++) + { + *m = *src; + m->Convert(source.GetType(), m_SndFile.GetType(), source); + if(m->IsPcNote()) + { + if(m->instr && m->instr < pluginMapping.size()) m->instr = static_cast<ModCommand::INSTR>(pluginMapping[m->instr]); + } else + { + if(m->instr && m->instr < instrMapping.size()) m->instr = static_cast<ModCommand::INSTR>(instrMapping[m->instr]); + + if(m->command == CMD_POSITIONJUMP && m->param < orderMapping.size()) + { + if(orderMapping[m->param] == ORDERINDEX_INVALID) + { + m->command = CMD_NONE; + } else + { + m->param = static_cast<ModCommand::PARAM>(orderMapping[m->param]); + } + } + } + } + } + if(copyRows < targetPat.GetNumRows()) + { + // If source pattern was smaller, write pattern break effect. + targetPat.WriteEffect(EffectWriter(CMD_PATTERNBREAK, 0).Row(copyRows - 1).RetryNextRow()); + } + } +} + +OPENMPT_NAMESPACE_END |