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