123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /*
- * SampleTrimmer.cpp
- * -----------------
- * Purpose: Automatic trimming of unused sample parts for module size optimization.
- * 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 <numeric>
- #include "InputHandler.h"
- #include "Mainfrm.h"
- #include "Moddoc.h"
- #include "ProgressDialog.h"
- #include "../tracklib/SampleEdit.h"
- #include "../soundlib/OPL.h"
- OPENMPT_NAMESPACE_BEGIN
- class CRenderProgressDlg : public CProgressDialog
- {
- CSoundFile &m_SndFile;
- class DummyAudioTarget : public IAudioTarget
- {
- public:
- void Process(mpt::audio_span_interleaved<MixSampleInt>) override { }
- void Process(mpt::audio_span_interleaved<MixSampleFloat>) override { }
- };
- public:
- std::vector<SmpLength> m_SamplePlayLengths;
- CRenderProgressDlg(CWnd *parent, CSoundFile &sndFile)
- : CProgressDialog{parent}
- , m_SndFile{sndFile}
- {
- m_SndFile.m_SamplePlayLengths = &m_SamplePlayLengths;
- }
- ~CRenderProgressDlg()
- {
- m_SndFile.m_SamplePlayLengths = nullptr;
- }
- void Run() override
- {
- // We're not interested in plugin rendering
- std::bitset<MAX_MIXPLUGINS> plugMuteStatus;
- for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
- {
- plugMuteStatus[i] = m_SndFile.m_MixPlugins[i].IsBypassed();
- m_SndFile.m_MixPlugins[i].SetBypass(true);
- }
- m_SamplePlayLengths.assign(m_SndFile.GetNumSamples() + 1, 0);
- const auto origSequence = m_SndFile.Order.GetCurrentSequenceIndex();
- const auto origRepeatCount = m_SndFile.GetRepeatCount();
- auto opl = std::move(m_SndFile.m_opl);
- m_SndFile.SetRepeatCount(0);
- m_SndFile.m_bIsRendering = true;
- auto prevTime = timeGetTime();
- const auto subSongs = m_SndFile.GetAllSubSongs();
- SetRange(0, mpt::saturate_round<uint64>(std::accumulate(subSongs.begin(), subSongs.end(), 0.0, [](double acc, const auto& song) { return acc + song.duration; }) * m_SndFile.GetSampleRate()));
- size_t totalSamples = 0;
- for(size_t i = 0; i < subSongs.size() && !m_abort; i++)
- {
- SetWindowText(MPT_CFORMAT("Automatic Sample Trimmer - Song {} / {}")(i + 1, subSongs.size()));
- const auto &song = subSongs[i];
- m_SndFile.ResetPlayPos();
- m_SndFile.GetLength(eAdjust, GetLengthTarget(song.startOrder, song.startRow).StartPos(song.sequence, 0, 0));
- m_SndFile.m_SongFlags.reset(SONG_PLAY_FLAGS);
- size_t subsongSamples = 0;
- DummyAudioTarget target;
- while(!m_abort)
- {
- auto count = m_SndFile.Read(MIXBUFFERSIZE, target);
- if(count == 0)
- break;
- totalSamples += count;
- subsongSamples += count;
- auto currentTime = timeGetTime();
- if(currentTime - prevTime >= 16)
- {
- prevTime = currentTime;
- auto timeSec = subsongSamples / m_SndFile.GetSampleRate();
- SetText(MPT_CFORMAT("Analyzing... {}:{}:{}")(timeSec / 3600, mpt::cfmt::dec0<2>((timeSec / 60) % 60), mpt::cfmt::dec0<2>(timeSec % 60)));
- SetProgress(totalSamples);
- ProcessMessages();
- }
- }
- }
- // Reset globals to previous values
- m_SndFile.Order.SetSequence(origSequence);
- m_SndFile.SetRepeatCount(origRepeatCount);
- m_SndFile.ResetPlayPos();
- m_SndFile.StopAllVsti();
- m_SndFile.m_bIsRendering = false;
- m_SndFile.m_opl = std::move(opl);
- for(PLUGINDEX i = 0; i < MAX_MIXPLUGINS; i++)
- {
- m_SndFile.m_MixPlugins[i].SetBypass(plugMuteStatus[i]);
- }
- EndDialog(IDOK);
- }
- };
- void CModDoc::OnShowSampleTrimmer()
- {
- BypassInputHandler bih;
- CMainFrame::GetMainFrame()->StopMod(this);
- CRenderProgressDlg dlg(CMainFrame::GetMainFrame(), m_SndFile);
- dlg.DoModal();
- SAMPLEINDEX numTrimmed = 0;
- SmpLength numBytes = 0;
- for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
- {
- ModSample &sample = m_SndFile.GetSample(smp);
- auto &newLength = dlg.m_SamplePlayLengths[smp];
- if(newLength == 0)
- continue;
- // Take interpolation look-ahead into account
- if((!sample.uFlags[CHN_LOOP] || newLength != sample.nLoopEnd)
- && (!sample.uFlags[CHN_SUSTAINLOOP] || newLength != sample.nSustainEnd))
- {
- newLength = std::min(newLength + InterpolationMaxLookahead, sample.nLength);
- }
- if(sample.nLength > newLength)
- {
- numTrimmed++;
- numBytes += (sample.nLength - newLength) * sample.GetBytesPerSample();
- }
- }
- if(numTrimmed == 0)
- {
- Reporting::Information(_T("No samples can be trimmed, because all samples are played in their full length."));
- return;
- }
- mpt::ustring s = MPT_UFORMAT("{} sample{} can be trimmed, saving {} byte{}.")(numTrimmed, (numTrimmed == 1) ? U_("") : U_("s"), mpt::ufmt::dec(3, ',', numBytes), numBytes != 1 ? U_("s") : U_(""));
- if(dlg.m_abort)
- {
- s += U_("\n\nWARNING: Only partial results are available, possibly causing used sample parts to be trimmed.\nContinue anyway?");
- } else
- {
- s += U_(" Continue?");
- }
- if(Reporting::Confirm(s, false, dlg.m_abort) == cnfYes)
- {
- for(SAMPLEINDEX smp = 1; smp <= GetNumSamples(); smp++)
- {
- ModSample &sample = m_SndFile.GetSample(smp);
- if(dlg.m_SamplePlayLengths[smp] != 0 && sample.nLength > dlg.m_SamplePlayLengths[smp])
- {
- GetSampleUndo().PrepareUndo(smp, sundo_delete, "Automatic Sample Trimming", dlg.m_SamplePlayLengths[smp], sample.nLength);
- SampleEdit::ResizeSample(sample, dlg.m_SamplePlayLengths[smp], m_SndFile);
- sample.uFlags.set(SMP_MODIFIED);
- }
- }
- SetModified();
- UpdateAllViews(SampleHint().Data().Info());
- }
- }
- OPENMPT_NAMESPACE_END
|