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 "AudioSegmentRescaleCommand.h"
20 
21 #include "misc/AppendLabel.h"
22 #include "misc/Strings.h"
23 #include "misc/Debug.h"
24 #include "base/Event.h"
25 #include "base/Composition.h"
26 #include "base/NotationTypes.h"
27 #include "base/Segment.h"
28 #include "document/RosegardenDocument.h"
29 #include "sound/AudioFileTimeStretcher.h"
30 #include "sound/AudioFileManager.h"
31 #include <QString>
32 
33 
34 namespace Rosegarden
35 {
36 
AudioSegmentRescaleCommand(RosegardenDocument * doc,Segment * s,float ratio)37 AudioSegmentRescaleCommand::AudioSegmentRescaleCommand(RosegardenDocument *doc,
38                                                        Segment *s,
39 						       float ratio) :
40     NamedCommand(getGlobalName()),
41     m_afm(&doc->getAudioFileManager()),
42     m_stretcher(new AudioFileTimeStretcher(m_afm)),
43     m_segment(s),
44     m_newSegment(nullptr),
45     m_timesGiven(false),
46     m_startTime(0),
47     m_endMarkerTime(0),
48     m_fid(-1),
49     m_ratio(ratio),
50     m_detached(false)
51 {
52     // nothing
53 }
54 
AudioSegmentRescaleCommand(RosegardenDocument * doc,Segment * s,float ratio,timeT st,timeT emt)55 AudioSegmentRescaleCommand::AudioSegmentRescaleCommand(RosegardenDocument *doc,
56                                                        Segment *s,
57 						       float ratio,
58                                                        timeT st,
59                                                        timeT emt) :
60     NamedCommand(getGlobalName()),
61     m_afm(&doc->getAudioFileManager()),
62     m_stretcher(new AudioFileTimeStretcher(m_afm)),
63     m_segment(s),
64     m_newSegment(nullptr),
65     m_timesGiven(true),
66     m_startTime(st),
67     m_endMarkerTime(emt),
68     m_fid(-1),
69     m_ratio(ratio),
70     m_detached(false)
71 {
72     // nothing
73 }
74 
~AudioSegmentRescaleCommand()75 AudioSegmentRescaleCommand::~AudioSegmentRescaleCommand()
76 {
77     delete m_stretcher;
78 
79     if (m_detached) {
80         delete m_segment;
81     } else {
82         delete m_newSegment;
83     }
84 }
85 
86 void
setProgressDialog(QPointer<QProgressDialog> progressDialog)87 AudioSegmentRescaleCommand::setProgressDialog(
88         QPointer<QProgressDialog> progressDialog)
89 {
90     if (m_stretcher)
91         m_stretcher->setProgressDialog(progressDialog);
92 }
93 
94 void
execute()95 AudioSegmentRescaleCommand::execute()
96 {
97     // Audio segments only.
98     if (m_segment->getType() != Segment::Audio) {
99         RG_WARNING << "WARNING: execute() called with a non-audio segment.";
100         return;
101     }
102 
103     // If we don't have the rescaled segment yet, create it.
104     if (!m_newSegment) {
105 
106         // Rescale the audio file.
107 
108         AudioFileId sourceFileId = m_segment->getAudioFileId();
109         float absoluteRatio = m_ratio;
110 
111         RG_DEBUG << "AudioSegmentRescaleCommand: segment file id " << sourceFileId << ", given ratio " << m_ratio;
112 
113         if (m_segment->getStretchRatio() != 1.f &&
114             m_segment->getStretchRatio() != 0.f) {
115             sourceFileId = m_segment->getUnstretchedFileId();
116             absoluteRatio *= m_segment->getStretchRatio();
117             RG_DEBUG << "AudioSegmentRescaleCommand: unstretched file id " << sourceFileId << ", prev ratio " << m_segment->getStretchRatio() << ", resulting ratio " << absoluteRatio;
118         }
119 
120         if (!m_timesGiven) {
121             m_endMarkerTime = m_segment->getStartTime() +
122                 (m_segment->getEndMarkerTime() - m_segment->getStartTime()) * m_ratio;
123         }
124 
125         m_fid = m_stretcher->getStretchedAudioFile(sourceFileId,
126                                                    absoluteRatio);
127         // If the stretch failed, bail.
128         if (m_fid < 0)
129             return;
130 
131         // Audio file was rescaled successfully.  Create the new Segment.
132 
133         m_newSegment = m_segment->clone(false);
134 
135         std::string label = m_newSegment->getLabel();
136         m_newSegment->setLabel(appendLabel(label, qstrtostr(tr("(rescaled)"))));
137 
138         m_newSegment->setAudioFileId(m_fid);
139         m_newSegment->setUnstretchedFileId(sourceFileId);
140         m_newSegment->setStretchRatio(absoluteRatio);
141         m_newSegment->setAudioStartTime(m_segment->getAudioStartTime() *
142                                         m_ratio);
143         if (m_timesGiven) {
144             m_newSegment->setStartTime(m_startTime);
145             m_newSegment->setAudioEndTime(m_segment->getAudioEndTime() *
146                                           m_ratio);
147             m_newSegment->setEndMarkerTime(m_endMarkerTime);
148         } else {
149             m_newSegment->setEndMarkerTime(m_endMarkerTime);
150             m_newSegment->setAudioEndTime(m_segment->getAudioEndTime() *
151                                           m_ratio);
152         }
153     }
154 
155     m_segment->getComposition()->addSegment(m_newSegment);
156     m_segment->getComposition()->detachSegment(m_segment);
157 
158 //    m_newSegment->setEndMarkerTime
159 //    (startTime + rescale(m_segment->getEndMarkerTime() - startTime));
160 
161     m_detached = true;
162 }
163 
164 void
unexecute()165 AudioSegmentRescaleCommand::unexecute()
166 {
167     if (m_newSegment) {
168         m_newSegment->getComposition()->addSegment(m_segment);
169         m_newSegment->getComposition()->detachSegment(m_newSegment);
170         m_detached = false;
171     }
172 }
173 
174 }
175