Exemplo n.º 1
0
void Demidify::disectPhrase(Song *song, size_t trackNo,
                            int prog_base, int max_prog_delta)
{
    if ((*song)[trackNo]->size() == 0) return;

    Phrase *phrase = (*(*song)[trackNo])[0]->phrase();
    if (!phrase) return;

    if (verbose >= 2)
    {
        out << "    |    +- Disecting Phrase '" << phrase->title()
            << "' which has "
            << phrase->size() << " events and is in Track " << trackNo
            << ".\n";
    }

    // STEP ZERO
    // Remove program changes and other fun from the Phrase.

    if (pullTrackParameters && phrase->size())
    {
        if (verbose >= 2) out << "    |    +- Pulling Track parameters.\n";
        PhraseEdit pe;
        pe.reset(phrase);
        size_t    pos = 0;
        bool      culled = false;
        MidiEvent e;
        do
        {
            if (pos < pe.size())
            {
                e = pe[pos];
                switch (e.data.status)
                {
                    case MidiCommand_ProgramChange:
                        (*song)[trackNo]->params()->setProgram(e.data.data1);
                        (*song)[trackNo]->filter()->setChannel(e.data.channel);
                        (*song)[trackNo]->filter()->setPort(e.data.port);
                        pe.erase(pos);
                        culled = true;
                        break;
                    case MidiCommand_ControlChange:
                        switch (e.data.data1)
                        {
                            case MidiControl_BankSelectMSB:
                                (*song)[trackNo]->params()->setBankMSB
                                    (e.data.data2);
                                pe.erase(pos);
                                culled = true;
                                break;
                            case MidiControl_BankSelectLSB:
                                (*song)[trackNo]->params()->setBankLSB
                                    (e.data.data2);
                                pe.erase(pos);
                                culled = true;
                                break;
                            case MidiControl_PanMSB:
                                (*song)[trackNo]->params()->setPan
                                    (e.data.data2);
                                pe.erase(pos);
                                culled = true;
                                break;
                            case MidiControl_ReverbDepth:
                                (*song)[trackNo]->params()->setReverb
                                    (e.data.data2);
                                pe.erase(pos);
                                culled = true;
                                break;
                            case MidiControl_ChorusDepth:
                                (*song)[trackNo]->params()->setChorus
                                    (e.data.data2);
                                pe.erase(pos);
                                culled = true;
                                break;
                            default:
                                ++pos;
                        }
                        break;
                    default:
                        ++pos;
                        break;
                }
            }
        }
        while (pos < pe.size() && e.data.status != MidiCommand_NoteOn);
        if (culled)
        {
            if (verbose >= 2)
                out << "    |    |    |\n"
                    << "    |    |    +- Culled some Track information\n";
            Phrase *newPhrase = pe.createPhrase(song->phraseList());
            replacePhrase(song, phrase, newPhrase);
            phrase = newPhrase;
        }
    }

    // STEP ONE:
    // Remove the original MidiImport Part from the Track.

    if (verbose >= 2) out << "    |    +- Removing original Part\n";
    Part *part = (*((*song)[trackNo]))[0];
    (*song)[trackNo]->remove(part);
    delete part;

    if (phrase->size() == 0) return;

    // STEP TWO:
    // Break the Phrase up into smaller Phrase chunks.

    if (verbose >= 2) out << "    |    +- Breaking up Phrase\n";

    Clock startTime = (*phrase)[0].time; // start time of Phrase
    Clock endTime;                       // end time of Phrase
    for (size_t pos = 0; pos < phrase->size(); ++pos)
    {
        if ((*phrase)[pos].time > endTime)
            endTime = (*phrase)[pos].time;
        if ((*phrase)[pos].data.status == MidiCommand_NoteOn
            && (*phrase)[pos].offTime > endTime)
            endTime = (*phrase)[pos].offTime;
    }

    size_t pos = 0;
    size_t noParts = 0;
    for (Clock partStart = (startTime / partSize) * partSize;
         partStart < endTime && pos < phrase->size();
         partStart += partSize)
    {
        if (progress)
            progress->progress(prog_base + pos*max_prog_delta/phrase->size());

        PhraseEdit pe;
        MidiEvent  e, lastE;
        do
        {
            e = (*phrase)[pos];
            if (e.time < partStart + partSize)
            {
                MidiEvent e2 = e;
                e2.time    -= partStart;
                if (e2.data.status == MidiCommand_NoteOn)
                    e2.offTime -= partStart;
                pe.insert(e2);
                ++pos;
                lastE = e;
            }
        }
        while (pos < phrase->size() && e.time < partStart + partSize);

        if (pe.size())
        {
            if (verbose >= 3)
                out << "    |    |    +- Created Phrase between "
                    << partStart << "-" << partStart+lastE.time << " with "
                    << pe.size() << " events\n";

            // If there is an identical Phrase already in this Track,
            // use that, otherwise create a new Phrase.

            Phrase *newPhrase = 0;

            for (size_t plpos = 0; plpos < song->phraseList()->size(); ++plpos)
            {
                if (identical(&pe, (*song->phraseList())[plpos]))
                {
                    newPhrase = (*song->phraseList())[plpos];
                    break;
                }
            }

            if (newPhrase == 0)
            {
                newPhrase = pe.createPhrase(song->phraseList());
            }

            Part *newPart = new Part;
            newPart->setStart(partStart);
            newPart->setEnd(partStart+partSize);
            newPart->setPhrase(newPhrase);

            (*song)[trackNo]->insert(newPart);

            ++noParts;
        }
        else
        {
            if (verbose >= 3)
                out << "    |    |    +- No Phrase at "
                    << partStart << "\n";
        }
    }
    if (verbose >= 2)
        out << "    |    |    |    +- split into " << noParts
            << " Parts\n";

    // STEP THREE:
    // Look at the Part we've instered. Can any be reduced to repeats in Parts?

    if (compactParts)
    {
        if (verbose >= 2) out << "    |    +- Reducing repeated Parts\n";
        reduceParts(song, trackNo);
    }

    // STEP FOUR:
    // Look at the pattern of Phrases (ignoring the repeated ones).
    // Can we make any bigger Phrases?

    if (aggressive)
    {
        if (verbose >= 2)
            out << "    |    +- Extending Parts/Phrases (there are "
                << (*song)[trackNo]->size() << " Parts)\n";
        size_t pos = 0;
        while (pos < (*song)[trackNo]->size() - 4)
        {
            if (!matchParts(song, trackNo, pos)) ++pos;
        }
        // Try the repeat thing again?
        if (compactParts) reduceParts(song, trackNo);
    }


    // STEP FIVE:
    // Now remove the original Phrase.

    if (verbose >= 2) out << "    |    +- Removing original Phrase\n";
    song->phraseList()->erase(phrase);


    if (verbose >= 2) out << "    |    +- Phrase disection done\n";
}