1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2
3 /*
4 Rosegarden
5 A sequencer and musical notation editor.
6 Copyright 2000-2021 the Rosegarden development team.
7 See the AUTHORS file for more details.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version. See the file
13 COPYING included with this distribution for more information.
14 */
15
16 #define RG_MODULE_STRING "[PeakFileManager]"
17
18 #include "PeakFileManager.h"
19
20 #include <vector>
21
22 #include <QProgressDialog>
23
24 #include "AudioFile.h"
25 #include "base/RealTime.h"
26 #include "PeakFile.h"
27 #include "misc/Debug.h"
28
29 namespace Rosegarden
30 {
31
32
PeakFileManager()33 PeakFileManager::PeakFileManager()
34 {
35 }
36
~PeakFileManager()37 PeakFileManager::~PeakFileManager()
38 {
39 }
40
41 bool
insertAudioFile(AudioFile * audioFile)42 PeakFileManager::insertAudioFile(AudioFile *audioFile)
43 {
44 // For each PeakFile
45 for (std::vector<PeakFile *>::iterator it = m_peakFiles.begin();
46 it != m_peakFiles.end();
47 ++it) {
48 if ((*it)->getAudioFile()->getId() == audioFile->getId())
49 return false;
50 }
51
52 //RG_DEBUG << "insertAudioFile() - creating peak file " << m_peakFiles.size() + 1 << " for \"" << audioFile->getFilename() << "\"";
53
54 // Insert
55 m_peakFiles.push_back(new PeakFile(audioFile));
56
57 return true;
58 }
59
60 bool
removeAudioFile(AudioFile * audioFile)61 PeakFileManager::removeAudioFile(AudioFile *audioFile)
62 {
63 // For each PeakFile
64 for (std::vector<PeakFile *>::iterator it = m_peakFiles.begin();
65 it != m_peakFiles.end();
66 ++it) {
67 if ((*it)->getAudioFile()->getId() == audioFile->getId()) {
68 delete *it;
69 m_peakFiles.erase(it);
70 return true;
71 }
72 }
73
74 return false;
75 }
76
77 PeakFile *
getPeakFile(AudioFile * audioFile)78 PeakFileManager::getPeakFile(AudioFile *audioFile)
79 {
80 PeakFile *ptr = nullptr;
81
82 while (ptr == nullptr) {
83 // For each PeakFile
84 for (std::vector<PeakFile *>::iterator it = m_peakFiles.begin();
85 it != m_peakFiles.end();
86 ++it) {
87 if ((*it)->getAudioFile()->getId() == audioFile->getId())
88 ptr = *it;
89 }
90
91 // If nothing is found then insert and retry
92 //
93 if (ptr == nullptr) {
94 // Insert - if we fail we return as empty
95 //
96 // ??? If this would return the pointer, we can get rid of the
97 // while loop.
98 if (insertAudioFile(audioFile) == false)
99 return nullptr;
100 }
101 }
102
103 return ptr;
104 }
105
106 bool
hasValidPeaks(AudioFile * audioFile)107 PeakFileManager::hasValidPeaks(AudioFile *audioFile)
108 {
109 if (audioFile->getType() == WAV) {
110 // Check external peak file
111 PeakFile *peakFile = getPeakFile(audioFile);
112
113 if (peakFile == nullptr) {
114 #ifdef DEBUG_PEAKFILEMANAGER
115 RG_WARNING << "hasValidPeaks() - no peak file found";
116 #endif
117
118 return false;
119 }
120 // If it doesn't open and parse correctly
121 if (peakFile->open() == false)
122 return false;
123
124 // or if the data is old or invalid
125 if (peakFile->isValid() == false)
126 return false;
127
128 } else if (audioFile->getType() == BWF) {
129 // check internal peak chunk
130 } else {
131 #ifdef DEBUG_PEAKFILEMANAGER
132 RG_WARNING << "hasValidPeaks() - unsupported file type";
133 #endif
134
135 return false;
136 }
137
138 return true;
139
140 }
141
142 void
generatePeaks(AudioFile * audioFile)143 PeakFileManager::generatePeaks(AudioFile *audioFile)
144 {
145 #ifdef DEBUG_PEAKFILEMANAGER
146 RG_DEBUG << "generatePeaks() - generating peaks for \"" << audioFile->getFilename() << "\"";
147 #endif
148
149 if (audioFile->getType() == WAV) {
150 PeakFile *currentPeakFile = getPeakFile(audioFile);
151
152 currentPeakFile->setProgressDialog(m_progressDialog);
153
154 // Just write out a peak file
155 //
156 if (currentPeakFile->write() == false) {
157 RG_WARNING << "generatePeaks() - Can't write peak file for " << audioFile->getFilename() << " - no preview generated";
158 throw BadPeakFileException(
159 audioFile->getFilename(), __FILE__, __LINE__);
160 }
161
162 // If we were cancelled, don't leave a partial peak file lying
163 // around.
164 if (m_progressDialog && m_progressDialog->wasCanceled()) {
165 QFile file(currentPeakFile->getFilename());
166 file.remove();
167 return;
168 }
169
170 // close writes out important things
171 currentPeakFile->close();
172
173 } else if (audioFile->getType() == BWF) {
174 // write the file out and incorporate the peak chunk
175 RG_WARNING << "generatePeaks() - unsupported file type: BWF";
176 } else {
177 RG_WARNING << "generatePeaks() - unknown file type";
178 }
179 }
180
181 std::vector<float>
getPreview(AudioFile * audioFile,const RealTime & startTime,const RealTime & endTime,int width,bool showMinima)182 PeakFileManager::getPreview(AudioFile *audioFile,
183 const RealTime &startTime,
184 const RealTime &endTime,
185 int width,
186 bool showMinima)
187 {
188 std::vector<float> rV;
189
190 // If we've got no channels then the audio file hasn't
191 // completed (recording) - so don't generate a preview
192 //
193 if (audioFile->getChannels() == 0)
194 return rV;
195
196 if (audioFile->getType() == WAV) {
197 PeakFile *peakFile = getPeakFile(audioFile);
198
199 // just write out a peak file
200 try {
201 peakFile->open();
202 rV = peakFile->getPreview(startTime,
203 endTime,
204 width,
205 showMinima);
206 } catch (const SoundFile::BadSoundFileException &e) {
207 #ifdef DEBUG_PEAKFILEMANAGER
208 RG_WARNING << "getPreview() - \"" << e << "\"";
209 #endif
210
211 throw BadPeakFileException(e);
212 }
213 } else if (audioFile->getType() == BWF) {
214 // write the file out and incorporate the peak chunk
215 }
216 #ifdef DEBUG_PEAKFILEMANAGER
217 else {
218 RG_WARNING << "getPreview() - unsupported file type";
219 }
220 #endif
221
222 return rV;
223 }
224
225 void
clear()226 PeakFileManager::clear()
227 {
228 // Delete the PeakFile objects.
229 for (std::vector<PeakFile *>::iterator it = m_peakFiles.begin();
230 it != m_peakFiles.end();
231 ++it)
232 delete (*it);
233
234 m_peakFiles.erase(m_peakFiles.begin(), m_peakFiles.end());
235 }
236
237 std::vector<SplitPointPair>
getSplitPoints(AudioFile * audioFile,const RealTime & startTime,const RealTime & endTime,int threshold,const RealTime & minTime)238 PeakFileManager::getSplitPoints(AudioFile *audioFile,
239 const RealTime &startTime,
240 const RealTime &endTime,
241 int threshold,
242 const RealTime &minTime)
243 {
244 PeakFile *peakFile = getPeakFile(audioFile);
245
246 if (peakFile == nullptr)
247 return std::vector<SplitPointPair>();
248
249 return peakFile->getSplitPoints(startTime,
250 endTime,
251 threshold,
252 minTime);
253 }
254
255
256 }
257