Page 1 of 1

Condense patterns

Posted: Wed Oct 26, 2016 2:40 am
by beachbum811
Forgive me if this was already suggested, because I don't know what to search for.
Welp.
Here's a diagram of the frame editor of a hypothetical FTM.

00 00 00 00 00
01 01 01 01 01
02 02 02 02 02
03 03 03 03 03
04 04 04 04 04

Let's say I go to
Clean up > Merge duplicated patterns
and then
Clean up > Delete unused patterns
This is a feasible result:

00 00 00 00 00
01 01 00 00 00
02 01 02 00 00
03 03 02 00 00
04 04 04 04 00

This leaves a bunch of unused patterns that really annoy me for some reason.
For example, the noise channel (the fourth one). Pattern 0 has the drum loop, patterns 1, 2, and 3 are empty, and frame 4 has different notes.
What I want is a function that instead makes this:

00 00 00 00 00
01 01 00 00 00
02 01 01 00 00
03 02 01 00 00
04 03 02 01 00

This makes frame editing easier for me, for the patterns of a channel to be in the order they're first used.
I feel like I'm whining when I request for a feature like this so I'm obligated to say that famitracker Is great

Re: Condense patterns

Posted: Wed Oct 26, 2016 7:41 am
by HertzDevil

Code: Select all

void CPatternData::PartitionUnused(unsigned int Channel)
{
    unsigned int p = 0;
    unsigned int mapping[MAX_PATTERNS] = {};

    for (unsigned int i = 0; i < MAX_PATTERNS; ++i)
        if (IsPatternInUse(Channel, i)) {
            std::swap(m_pPatternData[Channel][i], m_pPatternData[Channel][p]);
            mapping[i] = p++;
        }

    for (unsigned int i = 0; i < MAX_FRAMES; ++i)
        SetFramePattern(Channel, i, mapping[GetFramePattern(Channel, i)]);
}

void CFamiTrackerDoc::PartitionUnusedPatterns()
{
    const int Channels = GetChannelCount();
    for (int t = 0, n = GetTrackCount(); t < n; ++t) {
        CPatternData *pTrack = GetTrack(t);
        for (int i = 0; i < Channels; ++i)
            pTrack->PartitionUnused(i);
    }
}

The relative order of the unused but non-empty patterns are not preserved; doing so requires a stable sort or more auxiliary variables. It also does not care about duplicated patterns, however this is a non-issue if the entire method is simply called after CFamiTrackerDoc::RemoveUnusedPatterns(void).

Actually, it is possible to condense anything using numerical indices (instruments, instrument sequences, DPCM samples (, grooves)), but there isn't a common underlying container interface, so this does not generalize to other kinds of module data.