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 #ifndef RG_AUDIOFILEMANAGER_H 19 #define RG_AUDIOFILEMANAGER_H 20 21 #include <string> 22 #include <vector> 23 #include <set> 24 25 #include <QPixmap> 26 #include <QObject> 27 #include <QUrl> 28 #include <QPointer> 29 #include <QProgressDialog> 30 31 #include "AudioFile.h" 32 #include "PeakFileManager.h" 33 34 #include "base/XmlExportable.h" 35 #include "base/Exception.h" 36 37 class QProcess; 38 39 namespace Rosegarden 40 { 41 42 typedef std::vector<AudioFile *>::const_iterator AudioFileManagerIterator; 43 44 /** 45 * AudioFileManager loads and maps audio files to their 46 * internal references (ids). A point of contact for 47 * AudioFile information - loading a Composition should 48 * use this class to pick up the AudioFile references, 49 * editing the AudioFiles in a Composition will be 50 * made through this manager. 51 * 52 * This is in the sound library because it's so closely 53 * connected to other sound classes like the AudioFile 54 * ones. However, the audio file manager itself within 55 * Rosegarden is stored in the GUI process. This class 56 * is not (and should not be) used elsewhere within the 57 * sound or sequencer libraries. 58 */ 59 class AudioFileManager : public QObject, public XmlExportable 60 { 61 Q_OBJECT 62 public: 63 AudioFileManager(); 64 ~AudioFileManager() override; 65 66 class BadAudioPathException : public Exception 67 { 68 public: BadAudioPathException(QString path)69 BadAudioPathException(QString path) : 70 Exception(QObject::tr("Bad audio file path ") + path), m_path(path) { } BadAudioPathException(QString path,QString file,int line)71 BadAudioPathException(QString path, QString file, int line) : 72 Exception(QObject::tr("Bad audio file path ") + path, file, line), m_path(path) { } BadAudioPathException(const SoundFile::BadSoundFileException & e)73 BadAudioPathException(const SoundFile::BadSoundFileException &e) : 74 Exception(QObject::tr("Bad audio file path (malformed file?) ") + e.getPath()), m_path(e.getPath()) { } 75 throw()76 ~BadAudioPathException() throw() override { } 77 getPath()78 QString getPath() const { return m_path; } 79 80 private: 81 QString m_path; 82 }; 83 84 private: 85 AudioFileManager(const AudioFileManager &aFM); 86 AudioFileManager &operator=(const AudioFileManager &); 87 88 public: 89 90 /// Create an AudioFile object from an absolute path 91 /** 92 * We use this interface to add an actual file. This only works 93 * with files that are already in a format RG understands natively. 94 * If you are not sure about that, use importFile() or importURL() 95 * instead. 96 * 97 * throws BadAudioPathException 98 */ 99 AudioFileId addFile(const QString &filePath); 100 101 /// Create an audio file by importing from a URL 102 /** 103 * throws BadAudioPathException, BadSoundFileException 104 */ 105 AudioFileId importURL(const QUrl &filePath, 106 int targetSampleRate); 107 108 /// Used by RoseXmlHandler to add an audio file. 109 /** 110 * throws BadAudioPathException 111 */ 112 bool insertFile(const std::string &name, const QString &fileName, 113 AudioFileId id); 114 115 /// Does a specific file id exist? 116 bool fileExists(AudioFileId id); 117 118 /// Does a specific file path exist? Return ID or -1. 119 int fileExists(const QString &path); 120 121 AudioFile* getAudioFile(AudioFileId id); 122 123 /// Get an iterator into the list of AudioFile objects. begin()124 AudioFileManagerIterator begin() const 125 { return m_audioFiles.begin(); } 126 end()127 AudioFileManagerIterator end() const 128 { return m_audioFiles.end(); } 129 130 /// Remove one audio file. 131 bool removeFile(AudioFileId id); 132 /// Remove all audio files. 133 void clear(); 134 135 /// Get the audio record path getAudioPath()136 QString getAudioPath() const { return m_audioPath; } 137 /// Set the audio record path 138 void setAudioPath(const QString &path); 139 140 /// Throw if the current audio path does not exist or is not writable 141 /** 142 * throws BadAudioPathException 143 */ 144 void testAudioPath(); 145 146 /** 147 * Get a new audio filename at the audio record path, inserting the 148 * projectFilename and instrumentAlias into the filename for easier 149 * recognition away from the file's original context. 150 * 151 * throws BadAudioPathException 152 */ 153 AudioFile *createRecordingAudioFile( 154 QString projectName, QString instrumentAlias); 155 156 /// Return whether a file was created by recording within this "session" 157 bool wasAudioFileRecentlyRecorded(AudioFileId id); 158 159 /// Return whether a file was created by derivation within this "session" 160 bool wasAudioFileRecentlyDerived(AudioFileId id); 161 162 /** 163 * Indicate that a new "session" has started from the point of 164 * view of recorded and derived audio files (e.g. that the 165 * document has been saved) 166 */ 167 void resetRecentlyCreatedFiles(); 168 169 /// Create an empty file "derived from" the source (used by e.g. stretcher) 170 AudioFile *createDerivedAudioFile(AudioFileId source, 171 const char *prefix); 172 173 /// Export audio files and assorted bits and bobs 174 /** 175 * The files are stored in a format that's user independent so 176 * that people can pack up and swap their songs (including audio 177 * files) and shift them about easily. 178 */ 179 std::string toXmlString() const override; 180 181 /// Generate previews for all audio files. 182 /** 183 * Generates preview peak files or peak chunks according to file type. 184 * 185 * throw BadSoundFileException, BadPeakFileException 186 */ 187 void generatePreviews(); 188 189 /// Generate preview for a single audio file. 190 /** 191 * Generate a preview for a specific audio file - say if 192 * one has just been added to the AudioFileManager. 193 * Also used for generating previews if the file has been 194 * modified. 195 * 196 * throws BadSoundFileException, BadPeakFileException 197 */ 198 bool generatePreview(AudioFileId id); 199 200 /** 201 * Get a preview for an AudioFile adjusted to Segment start and 202 * end parameters (assuming they fall within boundaries). 203 * 204 * We can get back a set of values (floats) or a Pixmap if we 205 * supply the details. 206 * 207 * throws BadPeakFileException, BadAudioPathException 208 */ 209 std::vector<float> getPreview(AudioFileId id, 210 const RealTime &startTime, 211 const RealTime &endTime, 212 int width, 213 bool withMinima); 214 215 /// Draw a fixed size (fixed by QPixmap) preview of an audio file 216 /** 217 * throws BadPeakFileException, BadAudioPathException 218 */ 219 void drawPreview(AudioFileId id, 220 const RealTime &startTime, 221 const RealTime &endTime, 222 QPixmap *pixmap); 223 224 /** 225 * Usually used to show how an audio Segment makes up part of 226 * an audio file. 227 * 228 * throws BadPeakFileException, BadAudioPathException 229 */ 230 void drawHighlightedPreview(AudioFileId it, 231 const RealTime &startTime, 232 const RealTime &endTime, 233 const RealTime &highlightStart, 234 const RealTime &highlightEnd, 235 QPixmap *pixmap); 236 237 /// Convert the user's home directory to a "~". 238 QString homeToTilde(const QString &path) const; 239 /// Expand "~" to the user's home directory. 240 QString tildeToHome(const QString &path) const; 241 242 /// Get a split point vector from a peak file 243 /** 244 * throws BadPeakFileException, BadAudioPathException 245 */ 246 std::vector<SplitPointPair> 247 getSplitPoints(AudioFileId id, 248 const RealTime &startTime, 249 const RealTime &endTime, 250 int threshold, 251 const RealTime &minTime = RealTime(0, 100000000)); 252 getExpectedSampleRate()253 int getExpectedSampleRate() const { return m_expectedSampleRate; } setExpectedSampleRate(int rate)254 void setExpectedSampleRate(int rate) { m_expectedSampleRate = rate; } 255 256 std::set<int> getActualSampleRates() const; 257 258 /// Provide a progress dialog to be used to show progress. setProgressDialog(QPointer<QProgressDialog> progressDialog)259 void setProgressDialog(QPointer<QProgressDialog> progressDialog) 260 { m_progressDialog = progressDialog; } 261 262 /// Show entries for debug purposes 263 void print(); 264 265 /** 266 * Insert an audio file into the AudioFileManager and get the 267 * first allocated id for it. Used from the RG file as we already 268 * have both name and filename/path. 269 * 270 * throws BadAudioPathException 271 */ 272 //AudioFileId insertFile(const std::string &name, 273 // const QString &fileName); 274 275 //const PeakFileManager &getPeakFileManager() const { return m_peakManager; } 276 //PeakFileManager &getPeakFileManager() { return m_peakManager; } 277 278 /// Get the last file in the vector - the last created. 279 //AudioFile *getLastAudioFile(); 280 281 private: 282 /// The audio files we are managing. 283 std::vector<AudioFile *> m_audioFiles; 284 285 /** 286 * Create an audio file by importing (i.e. converting and/or 287 * resampling) an existing file using the conversion library. If 288 * you are not sure whether to use addFile() or importFile(), go for 289 * importFile(). 290 * 291 * throws BadAudioPathException, BadSoundFileException 292 */ 293 AudioFileId importFile(const QString &filePath, 294 int targetSampleRate); 295 296 /** 297 * Convert an audio file from arbitrary external format to an 298 * internal format suitable for use by addFile, using packages in 299 * Rosegarden. This replaces the Perl script previously used. It 300 * returns 0 for OK. This is used by importFile and importURL 301 * which normally provide the more suitable interface for import. 302 */ 303 int convertAudioFile(const QString &inFile, const QString &outFile); 304 305 /// Get a short file name from a long one (with '/'s) 306 QString getShortFilename(const QString &fileName) const; 307 308 /// Get a directory from a full file path 309 QString getDirectory(const QString &path) const; 310 311 /// See if we can find a given file in our search path 312 /** 313 * Returns the first occurrence of a match or the empty 314 * std::string if no match. 315 */ 316 QString getFileInPath(const QString &file); 317 318 /// Reset ID counter based on actual Audio Files in Composition 319 void updateAudioFileID(AudioFileId id); 320 321 /// Fetch a new unique Audio File ID. 322 AudioFileId getUniqueAudioFileID(); 323 /// Last Audio File ID that was handed out by getUniqueAudioFileID(). 324 unsigned int m_lastAudioFileID; 325 326 QString m_audioPath; 327 328 PeakFileManager m_peakManager; 329 330 // All audio files are stored in m_audioFiles. These additional 331 // sets of pointers just refer to those that have been created by 332 // recording or derivations within the current session, and thus 333 // that the user may wish to remove at the end of the session if 334 // the document is not saved. 335 std::set<AudioFile *> m_recordedAudioFiles; 336 std::set<AudioFile *> m_derivedAudioFiles; 337 338 int m_expectedSampleRate; 339 340 /// Progress Dialog passed in by clients. 341 QPointer<QProgressDialog> m_progressDialog; 342 }; 343 344 345 } 346 347 #endif // RG_AUDIOFILEMANAGER_H 348