1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4     Rosegarden
5     A MIDI and audio sequencer and musical notation editor.
6     Copyright 2000-2021 the Rosegarden development team.
7 
8     Other copyrights also apply to some parts of this work.  Please
9     see the AUTHORS file and individual file headers for details.
10 
11     This program is free software; you can redistribute it and/or
12     modify it under the terms of the GNU General Public License as
13     published by the Free Software Foundation; either version 2 of the
14     License, or (at your option) any later version.  See the file
15     COPYING included with this distribution for more information.
16 */
17 
18 
19 #include "SegmentSyncCommand.h"
20 
21 #include "base/Selection.h"
22 #include "commands/notation/KeyInsertionCommand.h"
23 #include "commands/edit/TransposeCommand.h"
24 #include "commands/segment/SegmentChangeTransposeCommand.h"
25 #include "commands/segment/SegmentTransposeCommand.h"
26 #include "commands/segment/SegmentSyncClefCommand.h"
27 
28 namespace Rosegarden
29 {
SegmentSyncCommand(Segment & segment,int newTranspose,int lowRange,int highRange,const Clef & clef)30 SegmentSyncCommand::SegmentSyncCommand(Segment &segment, int newTranspose, int lowRange, int highRange, const Clef& clef) :
31         MacroCommand(tr("Sync segment parameters"))
32 {
33     processSegment(segment, newTranspose, lowRange, highRange, clef);
34 }
35 
SegmentSyncCommand(SegmentSelection selection,int newTranspose,int lowRange,int highRange,const Clef & clef)36 SegmentSyncCommand::SegmentSyncCommand(SegmentSelection selection, int newTranspose, int lowRange, int highRange, const Clef& clef) :
37         MacroCommand(tr("Sync segment parameters"))
38 {
39     for (SegmentSelection::iterator i = selection.begin();
40             i != selection.end(); ++i)
41     {
42         Segment &segment = **i;
43         processSegment(segment, newTranspose, lowRange, highRange, clef);
44     }
45 }
46 
SegmentSyncCommand(std::vector<Segment * > segments,int newTranspose,int lowRange,int highRange,const Clef & clef)47 SegmentSyncCommand::SegmentSyncCommand(std::vector<Segment *> segments, int newTranspose, int lowRange, int highRange, const Clef& clef) :
48         MacroCommand(tr("Sync segment parameters"))
49 {
50 	for (size_t i = 0; i < segments.size(); i++) {
51         processSegment(*(segments[i]), newTranspose, lowRange, highRange, clef);
52     }
53 }
54 
SegmentSyncCommand(SegmentMultiSet & segments,TrackId selectedTrack,int newTranspose,int lowRange,int highRange,const Clef & clef)55 SegmentSyncCommand::SegmentSyncCommand(SegmentMultiSet& segments, TrackId selectedTrack, int newTranspose, int lowRange, int highRange, const Clef& clef) :
56         MacroCommand(tr("Sync segment parameters"))
57 {
58     for (SegmentMultiSet::const_iterator si = segments.begin();
59                         si != segments.end(); ++si) {
60         if ((*si)->getTrack() == selectedTrack) {
61             processSegment(**si, newTranspose, lowRange, highRange, clef);
62         }
63     }
64 }
65 
66 void
processSegment(Segment & segment,int newTranspose,int lowRange,int highRange,const Clef & clef)67 SegmentSyncCommand::processSegment(Segment &segment, int newTranspose, int lowRange, int highRange, const Clef& clef)
68 {
69     MacroCommand * macroCommand = this;
70 
71     // if the new desired setting for 'transpose' is higher, we need to
72     // transpose the notes upwards to compensate:
73     int semitones = segment.getTranspose() - newTranspose;
74 
75     // Say the old transpose was -2 and the new is 0, this corresponds to
76     // Bb and C. The height of the old transpose is 1 below the height of the new.
77     //
78     // "Both segment.getTranspose() and newTranspose might be less then zero
79     // yielding an invalid pitch. Simple solution, use an offset for both, like
80     // 60. Since we are interested in the difference, this common offset won't harm
81     // but is make sure the pitch will be positive (unless we have to transpose over 5
82     // octaves which is very unlikely :-))." --Niek van den Berg
83     //
84     // And that's why we use 60 here:
85     int oldHeight = Pitch(60 + segment.getTranspose()).getHeightOnStaff(Clef::Treble, Key("C major"));
86     int newHeight = Pitch(60 + newTranspose).getHeightOnStaff(Clef::Treble, Key("C major"));
87     int steps = oldHeight - newHeight;
88 
89     SegmentTransposeCommand* command = new SegmentTransposeCommand(segment, true, steps, semitones, true);
90     macroCommand->addCommand(command);
91 
92     // TODO do this in an undoable fashion:
93     segment.setLowestPlayable(lowRange);
94     segment.setHighestPlayable(highRange);
95 
96     macroCommand->addCommand(new SegmentSyncClefCommand(segment, clef));
97 }
98 
99 
~SegmentSyncCommand()100 SegmentSyncCommand::~SegmentSyncCommand()
101 {}
102 
103 
104 }
105