123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /*
- * 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
|