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.
386 lines
8.1 KiB
386 lines
8.1 KiB
/*
|
|
Rosegarden
|
|
A 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 <bownie@bownie.com>
|
|
|
|
The moral right of the authors to claim authorship of this work
|
|
has been asserted.
|
|
|
|
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 "Clipboard.h"
|
|
#include "Selection.h"
|
|
|
|
namespace Rosegarden
|
|
{
|
|
|
|
Clipboard::Clipboard() :
|
|
m_partial(false),
|
|
m_haveTimeSigSelection(false),
|
|
m_haveTempoSelection(false),
|
|
m_nominalStart(0),
|
|
m_nominalEnd(0)
|
|
{
|
|
// nothing
|
|
}
|
|
|
|
Clipboard::Clipboard(const Clipboard &c) :
|
|
m_partial(false)
|
|
{
|
|
copyFrom(&c);
|
|
}
|
|
|
|
Clipboard &
|
|
Clipboard::operator=(const Clipboard &c)
|
|
{
|
|
copyFrom(&c);
|
|
return *this;
|
|
}
|
|
|
|
Clipboard::~Clipboard()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void
|
|
Clipboard::clear()
|
|
{
|
|
for (iterator i = begin(); i != end(); ++i) {
|
|
delete *i;
|
|
}
|
|
m_segments.clear();
|
|
clearTimeSignatureSelection();
|
|
clearTempoSelection();
|
|
clearNominalRange();
|
|
m_partial = false;
|
|
}
|
|
|
|
bool
|
|
Clipboard::isEmpty() const
|
|
{
|
|
return (m_segments.size() == 0 &&
|
|
!m_haveTimeSigSelection &&
|
|
!m_haveTempoSelection &&
|
|
m_nominalStart == m_nominalEnd);
|
|
}
|
|
|
|
bool
|
|
Clipboard::isSingleSegment() const
|
|
{
|
|
return (m_segments.size() == 1 &&
|
|
!m_haveTimeSigSelection &&
|
|
!m_haveTempoSelection);
|
|
}
|
|
|
|
Segment *
|
|
Clipboard::getSingleSegment() const
|
|
{
|
|
if (isSingleSegment()) return *begin();
|
|
else return 0;
|
|
}
|
|
|
|
bool
|
|
Clipboard::isPartial() const
|
|
{
|
|
return m_partial;
|
|
}
|
|
|
|
Segment *
|
|
Clipboard::newSegment()
|
|
{
|
|
Segment *s = new Segment();
|
|
m_segments.insert(s);
|
|
// don't change m_partial
|
|
return s;
|
|
}
|
|
|
|
Segment *
|
|
Clipboard::newSegment(const Segment *copyFrom)
|
|
{
|
|
Segment *s = new Segment(*copyFrom);
|
|
m_segments.insert(s);
|
|
// don't change m_partial
|
|
return s;
|
|
}
|
|
|
|
void
|
|
Clipboard::newSegment(const Segment *copyFrom, timeT from, timeT to,
|
|
bool expandRepeats)
|
|
{
|
|
// create with copy ctor so as to inherit track, instrument etc
|
|
Segment *s = new Segment(*copyFrom);
|
|
|
|
if (from <= s->getStartTime() && to >= s->getEndMarkerTime()) {
|
|
m_segments.insert(s);
|
|
s->setEndTime(s->getEndMarkerTime());
|
|
// don't change m_partial
|
|
return;
|
|
}
|
|
|
|
timeT segStart = copyFrom->getStartTime();
|
|
timeT segEnd = copyFrom->getEndMarkerTime();
|
|
timeT segDuration = segEnd - segStart;
|
|
|
|
int firstRepeat = 0;
|
|
int lastRepeat = 0;
|
|
|
|
if (!copyFrom->isRepeating() || segDuration <= 0) {
|
|
expandRepeats = false;
|
|
}
|
|
|
|
if (expandRepeats) {
|
|
firstRepeat = (from - segStart) / segDuration;
|
|
lastRepeat = (to - segStart) / segDuration;
|
|
to = std::min(to, copyFrom->getRepeatEndTime());
|
|
}
|
|
|
|
s->setRepeating(false);
|
|
|
|
if (s->getType() == Segment::Audio) {
|
|
|
|
Composition *c = copyFrom->getComposition();
|
|
|
|
for (int repeat = firstRepeat; repeat <= lastRepeat; ++repeat) {
|
|
|
|
timeT wrappedFrom = segStart;
|
|
timeT wrappedTo = segEnd;
|
|
|
|
if (!expandRepeats) {
|
|
wrappedFrom = from;
|
|
wrappedTo = to;
|
|
} else {
|
|
if (repeat == firstRepeat) {
|
|
wrappedFrom = segStart + (from - segStart) % segDuration;
|
|
}
|
|
if (repeat == lastRepeat) {
|
|
wrappedTo = segStart + (to - segStart) % segDuration;
|
|
}
|
|
}
|
|
|
|
if (wrappedFrom > segStart) {
|
|
if (c) {
|
|
s->setAudioStartTime
|
|
(s->getAudioStartTime() +
|
|
c->getRealTimeDifference(segStart + repeat * segDuration,
|
|
from));
|
|
}
|
|
s->setStartTime(from);
|
|
} else {
|
|
s->setStartTime(segStart + repeat * segDuration);
|
|
}
|
|
|
|
if (wrappedTo < segEnd) {
|
|
s->setEndMarkerTime(to);
|
|
if (c) {
|
|
s->setAudioEndTime
|
|
(s->getAudioStartTime() +
|
|
c->getRealTimeDifference(segStart + repeat * segDuration,
|
|
to));
|
|
}
|
|
} else {
|
|
s->setEndMarkerTime(segStart + (repeat + 1) * segDuration);
|
|
}
|
|
|
|
m_segments.insert(s);
|
|
if (repeat < lastRepeat) {
|
|
s = new Segment(*copyFrom);
|
|
s->setRepeating(false);
|
|
}
|
|
}
|
|
|
|
m_partial = true;
|
|
return;
|
|
}
|
|
|
|
s->erase(s->begin(), s->end());
|
|
|
|
for (int repeat = firstRepeat; repeat <= lastRepeat; ++repeat) {
|
|
|
|
Segment::const_iterator ifrom = copyFrom->begin();
|
|
Segment::const_iterator ito = copyFrom->end();
|
|
|
|
if (!expandRepeats) {
|
|
ifrom = copyFrom->findTime(from);
|
|
ito = copyFrom->findTime(to);
|
|
} else {
|
|
if (repeat == firstRepeat) {
|
|
ifrom = copyFrom->findTime
|
|
(segStart + (from - segStart) % segDuration);
|
|
}
|
|
if (repeat == lastRepeat) {
|
|
ito = copyFrom->findTime
|
|
(segStart + (to - segStart) % segDuration);
|
|
}
|
|
}
|
|
|
|
for (Segment::const_iterator i = ifrom;
|
|
i != ito && copyFrom->isBeforeEndMarker(i); ++i) {
|
|
|
|
timeT absTime = (*i)->getAbsoluteTime() + repeat * segDuration;
|
|
timeT duration = (*i)->getDuration();
|
|
|
|
Event *e = (*i)->copyMoving(repeat * segDuration);
|
|
|
|
if (absTime + duration <= to) {
|
|
|
|
s->insert(e);
|
|
|
|
} else {
|
|
|
|
s->insert(new Event(*e,
|
|
e->getAbsoluteTime(),
|
|
duration,
|
|
e->getSubOrdering(),
|
|
e->getNotationAbsoluteTime(),
|
|
e->getNotationDuration()));
|
|
delete e;
|
|
}
|
|
}
|
|
}
|
|
|
|
// need to call getEndMarkerTime() on copyFrom, not on s, because
|
|
// its return value may depend on the composition it's in
|
|
if (copyFrom->getEndMarkerTime() > to) {
|
|
s->setEndMarkerTime(to);
|
|
}
|
|
|
|
m_segments.insert(s);
|
|
m_partial = true;
|
|
return;
|
|
}
|
|
|
|
Segment *
|
|
Clipboard::newSegment(const EventSelection *copyFrom)
|
|
{
|
|
// create with copy ctor so as to inherit track, instrument etc
|
|
Segment *s = new Segment(copyFrom->getSegment());
|
|
s->erase(s->begin(), s->end());
|
|
|
|
const EventSelection::eventcontainer &events(copyFrom->getSegmentEvents());
|
|
for (EventSelection::eventcontainer::const_iterator i = events.begin();
|
|
i != events.end(); ++i) {
|
|
s->insert(new Event(**i));
|
|
}
|
|
|
|
m_segments.insert(s);
|
|
m_partial = true;
|
|
return s;
|
|
}
|
|
|
|
void
|
|
Clipboard::setTimeSignatureSelection(const TimeSignatureSelection &ts)
|
|
{
|
|
m_timeSigSelection = ts;
|
|
m_haveTimeSigSelection = true;
|
|
}
|
|
|
|
void
|
|
Clipboard::clearTimeSignatureSelection()
|
|
{
|
|
m_timeSigSelection = TimeSignatureSelection();
|
|
m_haveTimeSigSelection = false;
|
|
}
|
|
|
|
const TimeSignatureSelection &
|
|
Clipboard::getTimeSignatureSelection() const
|
|
{
|
|
return m_timeSigSelection;
|
|
}
|
|
|
|
void
|
|
Clipboard::setTempoSelection(const TempoSelection &ts)
|
|
{
|
|
m_tempoSelection = ts;
|
|
m_haveTempoSelection = true;
|
|
}
|
|
|
|
void
|
|
Clipboard::clearTempoSelection()
|
|
{
|
|
m_tempoSelection = TempoSelection();
|
|
m_haveTempoSelection = false;
|
|
}
|
|
|
|
const TempoSelection &
|
|
Clipboard::getTempoSelection() const
|
|
{
|
|
return m_tempoSelection;
|
|
}
|
|
|
|
void
|
|
Clipboard::copyFrom(const Clipboard *c)
|
|
{
|
|
if (c == this) return;
|
|
clear();
|
|
|
|
for (Clipboard::const_iterator i = c->begin(); i != c->end(); ++i) {
|
|
newSegment(*i);
|
|
}
|
|
|
|
m_partial = c->m_partial;
|
|
|
|
m_timeSigSelection = c->m_timeSigSelection;
|
|
m_haveTimeSigSelection = c->m_haveTimeSigSelection;
|
|
|
|
m_tempoSelection = c->m_tempoSelection;
|
|
m_haveTempoSelection = c->m_haveTempoSelection;
|
|
|
|
m_nominalStart = c->m_nominalStart;
|
|
m_nominalEnd = c->m_nominalEnd;
|
|
}
|
|
|
|
timeT
|
|
Clipboard::getBaseTime() const
|
|
{
|
|
if (hasNominalRange()) {
|
|
return m_nominalStart;
|
|
}
|
|
|
|
timeT t = 0;
|
|
|
|
for (iterator i = begin(); i != end(); ++i) {
|
|
if (i == begin() || (*i)->getStartTime() < t) {
|
|
t = (*i)->getStartTime();
|
|
}
|
|
}
|
|
|
|
if (m_haveTimeSigSelection && !m_timeSigSelection.empty()) {
|
|
if (m_timeSigSelection.begin()->first < t) {
|
|
t = m_timeSigSelection.begin()->first;
|
|
}
|
|
}
|
|
|
|
if (m_haveTempoSelection && !m_tempoSelection.empty()) {
|
|
if (m_tempoSelection.begin()->first < t) {
|
|
t = m_tempoSelection.begin()->first;
|
|
}
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
void
|
|
Clipboard::setNominalRange(timeT start, timeT end)
|
|
{
|
|
m_nominalStart = start;
|
|
m_nominalEnd = end;
|
|
}
|
|
|
|
void
|
|
Clipboard::getNominalRange(timeT &start, timeT &end)
|
|
{
|
|
start = m_nominalStart;
|
|
end = m_nominalEnd;
|
|
}
|
|
|
|
}
|