You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
6.4 KiB
204 lines
6.4 KiB
/*
|
|
Rosegarden
|
|
A MIDI and audio sequencer and musical notation editor.
|
|
|
|
This program is Copyright 2000-2008
|
|
Guillaume Laurent <glaurent@telegraph-road.org>,
|
|
Chris Cannam <cannam@all-day-breakfast.com>,
|
|
Richard Bown <richard.bown@ferventsoftware.com>
|
|
|
|
The moral rights of Guillaume Laurent, Chris Cannam, and Richard
|
|
Bown to claim authorship of this work have been asserted.
|
|
|
|
Other copyrights also apply to some parts of this work. Please
|
|
see the AUTHORS file and individual file headers for details.
|
|
|
|
This program is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the
|
|
License, or (at your option) any later version. See the file
|
|
COPYING included with this distribution for more information.
|
|
*/
|
|
|
|
|
|
#include "SegmentAutoSplitCommand.h"
|
|
|
|
#include "base/Event.h"
|
|
#include "misc/Debug.h"
|
|
#include "misc/Strings.h"
|
|
#include "base/Composition.h"
|
|
#include "base/NotationTypes.h"
|
|
#include "base/Segment.h"
|
|
#include <tqstring.h>
|
|
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
struct AutoSplitPoint
|
|
{
|
|
timeT time;
|
|
timeT lastSoundTime;
|
|
Clef clef;
|
|
Rosegarden::Key key;
|
|
AutoSplitPoint(timeT t, timeT lst, Clef c, Rosegarden::Key k) :
|
|
time(t), lastSoundTime(lst), clef(c), key(k) { }
|
|
};
|
|
|
|
SegmentAutoSplitCommand::SegmentAutoSplitCommand(Segment *segment) :
|
|
KNamedCommand(getGlobalName()),
|
|
m_segment(segment),
|
|
m_composition(segment->getComposition()),
|
|
m_detached(false)
|
|
{}
|
|
|
|
SegmentAutoSplitCommand::~SegmentAutoSplitCommand()
|
|
{
|
|
if (m_detached) {
|
|
delete m_segment;
|
|
} else {
|
|
for (unsigned int i = 0; i < m_newSegments.size(); ++i) {
|
|
delete m_newSegments[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SegmentAutoSplitCommand::execute()
|
|
{
|
|
if (m_newSegments.size() == 0) {
|
|
|
|
std::vector<AutoSplitPoint> splitPoints;
|
|
|
|
Clef clef;
|
|
Key key;
|
|
timeT segmentStart = m_segment->getStartTime();
|
|
timeT lastSoundTime = segmentStart;
|
|
timeT lastSplitTime = segmentStart - 1;
|
|
|
|
for (Segment::iterator i = m_segment->begin();
|
|
m_segment->isBeforeEndMarker(i); ++i) {
|
|
|
|
timeT myTime = (*i)->getAbsoluteTime();
|
|
int barNo = m_composition->getBarNumber(myTime);
|
|
|
|
if ((*i)->isa(Clef::EventType)) {
|
|
clef = Clef(**i);
|
|
} else if ((*i)->isa(Key::EventType)) {
|
|
key = Key(**i);
|
|
}
|
|
|
|
if (myTime <= lastSplitTime)
|
|
continue;
|
|
|
|
bool newTimeSig = false;
|
|
TimeSignature tsig =
|
|
m_composition->getTimeSignatureInBar(barNo, newTimeSig);
|
|
|
|
if (newTimeSig) {
|
|
|
|
// If there's a new time sig in this bar and we haven't
|
|
// already made a split in this bar, make one
|
|
|
|
if (splitPoints.size() == 0 ||
|
|
m_composition->getBarNumber
|
|
(splitPoints[splitPoints.size() - 1].time) < barNo) {
|
|
|
|
splitPoints.push_back(AutoSplitPoint(myTime, lastSoundTime,
|
|
clef, key));
|
|
lastSoundTime = lastSplitTime = myTime;
|
|
}
|
|
|
|
} else if ((*i)->isa(Note::EventRestType)) {
|
|
|
|
// Otherwise never start a subsegment on a rest
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
// When we meet a non-rest event, start a new split
|
|
// if an entire bar has passed since the last one
|
|
|
|
int lastSoundBarNo = m_composition->getBarNumber(lastSoundTime);
|
|
|
|
if (lastSoundBarNo < barNo - 1 ||
|
|
(lastSoundBarNo == barNo - 1 &&
|
|
m_composition->getBarStartForTime(lastSoundTime) ==
|
|
lastSoundTime &&
|
|
lastSoundTime > segmentStart)) {
|
|
|
|
splitPoints.push_back
|
|
(AutoSplitPoint
|
|
(m_composition->getBarStartForTime(myTime), lastSoundTime,
|
|
clef, key));
|
|
lastSplitTime = myTime;
|
|
}
|
|
}
|
|
|
|
lastSoundTime = std::max(lastSoundTime, myTime + (*i)->getDuration());
|
|
}
|
|
|
|
for (unsigned int split = 0; split <= splitPoints.size(); ++split) {
|
|
|
|
Segment *newSegment = new Segment();
|
|
newSegment->setTrack(m_segment->getTrack());
|
|
newSegment->setLabel(qstrtostr(i18n("%1 (part)").arg
|
|
(strtoqstr(m_segment->getLabel()))));
|
|
newSegment->setColourIndex(m_segment->getColourIndex());
|
|
|
|
timeT startTime = segmentStart;
|
|
if (split > 0) {
|
|
|
|
RG_DEBUG << "Auto-split point " << split - 1 << ": time "
|
|
<< splitPoints[split - 1].time << ", lastSoundTime "
|
|
<< splitPoints[split - 1].lastSoundTime << endl;
|
|
|
|
startTime = splitPoints[split - 1].time;
|
|
newSegment->insert(splitPoints[split - 1].clef.getAsEvent(startTime));
|
|
newSegment->insert(splitPoints[split - 1].key.getAsEvent(startTime));
|
|
}
|
|
|
|
Segment::iterator i = m_segment->findTime(startTime);
|
|
|
|
// A segment has to contain at least one note to be a worthy
|
|
// candidate for adding back into the composition
|
|
bool haveNotes = false;
|
|
|
|
while (m_segment->isBeforeEndMarker(i)) {
|
|
timeT t = (*i)->getAbsoluteTime();
|
|
if (split < splitPoints.size() &&
|
|
t >= splitPoints[split].lastSoundTime)
|
|
break;
|
|
if ((*i)->isa(Note::EventType))
|
|
haveNotes = true;
|
|
newSegment->insert(new Event(**i));
|
|
++i;
|
|
}
|
|
|
|
if (haveNotes)
|
|
m_newSegments.push_back(newSegment);
|
|
else
|
|
delete newSegment;
|
|
}
|
|
}
|
|
|
|
m_composition->detachSegment(m_segment);
|
|
for (unsigned int i = 0; i < m_newSegments.size(); ++i) {
|
|
m_composition->addSegment(m_newSegments[i]);
|
|
}
|
|
m_detached = true;
|
|
}
|
|
|
|
void
|
|
SegmentAutoSplitCommand::unexecute()
|
|
{
|
|
for (unsigned int i = 0; i < m_newSegments.size(); ++i) {
|
|
m_composition->detachSegment(m_newSegments[i]);
|
|
}
|
|
m_composition->addSegment(m_segment);
|
|
m_detached = false;
|
|
}
|
|
|
|
}
|