You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rosegarden/src/sound/AudioFileManager.cpp

1252 lines
32 KiB

/*
Rosegarden
A sequencer and musical notation editor.
This program is Copyright 2000-2008
Guillaume Laurent <glaurent@telegraph-road.org>,
Chris Cannam <cannam@all-day-breakfast.com>,
Richard Bown <bownie@bownie.com>
The moral right of the authors to claim authorship of this work
has been asserted.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version. See the file
COPYING included with this distribution for more information.
*/
#include <iostream>
#include <tdeapplication.h>
#include <fstream>
#include <string>
#include <dirent.h> // for new recording file
#include <cstdio> // sprintf
#include <cstdlib>
#include <pthread.h>
#include <sstream>
#include <kapp.h>
#include <tdelocale.h>
#include <kprocess.h>
#include <tdeio/netaccess.h>
#include <tdemessagebox.h>
#include <tqpixmap.h>
#include <tqpainter.h>
#include <tqdatetime.h>
#include <tqfile.h>
#include "AudioFile.h"
#include "AudioFileManager.h"
#include "WAVAudioFile.h"
#include "BWFAudioFile.h"
#include "MP3AudioFile.h"
#include "misc/Strings.h"
namespace Rosegarden
{
static pthread_mutex_t _audioFileManagerLock;
class MutexLock
{
public:
MutexLock(pthread_mutex_t *mutex) : m_mutex(mutex)
{
pthread_mutex_lock(m_mutex);
}
~MutexLock()
{
pthread_mutex_unlock(m_mutex);
}
private:
pthread_mutex_t *m_mutex;
};
AudioFileManager::AudioFileManager() :
m_importProcess(0),
m_expectedSampleRate(0)
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
#ifdef HAVE_PTHREAD_MUTEX_RECURSIVE
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#else
#ifdef PTHREAD_MUTEX_RECURSIVE
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
#else
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
#endif
#endif
pthread_mutex_init(&_audioFileManagerLock, &attr);
// Set this through the set method so that the tilde gets
// shaken out.
//
setAudioPath("~/rosegarden");
// Retransmit progress
//
connect(&m_peakManager, TQ_SIGNAL(setProgress(int)),
this, TQ_SIGNAL(setProgress(int)));
}
AudioFileManager::~AudioFileManager()
{
clear();
}
// Add a file from an absolute path
//
AudioFileId
AudioFileManager::addFile(const std::string &filePath)
{
MutexLock lock (&_audioFileManagerLock)
;
TQString ext;
if (filePath.length() > 3) {
ext = TQString(filePath.substr(filePath.length() - 3, 3).c_str()).lower();
}
// Check for file existing already in manager by path
//
int check = fileExists(filePath);
if (check != -1) {
return AudioFileId(check);
}
// prepare for audio file
AudioFile *aF = 0;
AudioFileId id = getFirstUnusedID();
if (ext == "wav") {
// identify file type
AudioFileType subType = RIFFAudioFile::identifySubType(filePath);
if (subType == BWF) {
#ifdef DEBUG_AUDIOFILEMANAGER
std::cout << "FOUND BWF" << std::endl;
#endif
try {
aF = new BWFAudioFile(id, getShortFilename(filePath), filePath);
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
} else if (subType == WAV) {
try {
aF = new WAVAudioFile(id, getShortFilename(filePath), filePath);
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
}
// Ensure we have a valid file handle
//
if (aF == 0) {
std::cerr << "AudioFileManager: Unknown WAV audio file subtype in " << filePath << std::endl;
throw BadAudioPathException(filePath, __FILE__, __LINE__);
}
// Add file type on extension
try {
if (aF->open() == false) {
delete aF;
std::cerr << "AudioFileManager: Malformed audio file in " << filePath << std::endl;
throw BadAudioPathException(filePath, __FILE__, __LINE__);
}
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
}
#ifdef HAVE_LIBMAD
else if (ext == "mp3") {
try {
aF = new MP3AudioFile(id, getShortFilename(filePath), filePath);
if (aF->open() == false) {
delete aF;
std::cerr << "AudioFileManager: Malformed mp3 audio file in " << filePath << std::endl;
throw BadAudioPathException(filePath, __FILE__, __LINE__);
}
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
}
#endif // HAVE_LIBMAD
else {
std::cerr << "AudioFileManager: Unsupported audio file extension in " << filePath << std::endl;
throw BadAudioPathException(filePath, __FILE__, __LINE__);
}
if (aF) {
m_audioFiles.push_back(aF);
return id;
}
return 0;
}
// Convert long filename to shorter version
std::string
AudioFileManager::getShortFilename(const std::string &fileName)
{
std::string rS = fileName;
unsigned int pos = rS.find_last_of("/");
if (pos > 0 && ( pos + 1 ) < rS.length())
rS = rS.substr(pos + 1, rS.length());
return rS;
}
// Turn a long path into a directory ending with a slash
//
std::string
AudioFileManager::getDirectory(const std::string &path)
{
std::string rS = path;
unsigned int pos = rS.find_last_of("/");
if (pos > 0 && ( pos + 1 ) < rS.length())
rS = rS.substr(0, pos + 1);
return rS;
}
// Create a new AudioFile with unique ID and label - insert from
// our RG4 file
//
AudioFileId
AudioFileManager::insertFile(const std::string &name,
const std::string &fileName)
{
MutexLock lock (&_audioFileManagerLock)
;
// first try to expand any beginning tilde
//
std::string foundFileName = substituteTildeForHome(fileName);
// If we've expanded and we can't find the file
// then try to find it in audio file directory.
//
TQFileInfo info(foundFileName.c_str());
if (!info.exists())
foundFileName = getFileInPath(foundFileName);
#ifdef DEBUG_AUDIOFILEMANAGER_INSERT_FILE
std::cout << "AudioFileManager::insertFile - "
<< "expanded fileName = \""
<< foundFileName << "\"" << std::endl;
#endif
// bail if we haven't found any reasonable filename
if (foundFileName == "")
return false;
AudioFileId id = getFirstUnusedID();
WAVAudioFile *aF = 0;
try {
aF = new WAVAudioFile(id, name, foundFileName);
// if we don't recognise the file then don't insert it
//
if (aF->open() == false) {
delete aF;
std::cerr << "AudioFileManager::insertFile - don't recognise file type in " << foundFileName << std::endl;
throw BadAudioPathException(foundFileName, __FILE__, __LINE__);
}
m_audioFiles.push_back(aF);
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
return id;
}
bool
AudioFileManager::removeFile(AudioFileId id)
{
MutexLock lock (&_audioFileManagerLock)
;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin();
it != m_audioFiles.end();
++it) {
if ((*it)->getId() == id) {
m_peakManager.removeAudioFile(*it);
m_recordedAudioFiles.erase(*it);
m_derivedAudioFiles.erase(*it);
delete(*it);
m_audioFiles.erase(it);
return true;
}
}
return false;
}
AudioFileId
AudioFileManager::getFirstUnusedID()
{
AudioFileId rI = 0;
if (m_audioFiles.size() == 0)
return rI;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin();
it != m_audioFiles.end();
++it) {
if (rI < (*it)->getId())
rI = (*it)->getId();
}
rI++;
return rI;
}
bool
AudioFileManager::insertFile(const std::string &name,
const std::string &fileName,
AudioFileId id)
{
MutexLock lock (&_audioFileManagerLock)
;
// first try to expany any beginning tilde
std::string foundFileName = substituteTildeForHome(fileName);
// If we've expanded and we can't find the file
// then try to find it in audio file directory.
//
TQFileInfo info(foundFileName.c_str());
if (!info.exists())
foundFileName = getFileInPath(foundFileName);
#ifdef DEBUG_AUDIOFILEMANAGER_INSERT_FILE
std::cout << "AudioFileManager::insertFile - "
<< "expanded fileName = \""
<< foundFileName << "\"" << std::endl;
#endif
// If no joy here then we can't find this file
if (foundFileName == "")
return false;
// make sure we don't have a file of this ID hanging around already
removeFile(id);
// and insert
WAVAudioFile *aF = 0;
try {
aF = new WAVAudioFile(id, name, foundFileName);
// Test the file
if (aF->open() == false) {
delete aF;
return false;
}
m_audioFiles.push_back(aF);
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
return true;
}
// Add a given path to our sample search path
//
void
AudioFileManager::setAudioPath(const std::string &path)
{
MutexLock lock (&_audioFileManagerLock)
;
std::string hPath = path;
// add a trailing / if we don't have one
//
if (hPath[hPath.size() - 1] != '/')
hPath += std::string("/");
// get the home directory
if (hPath[0] == '~') {
hPath.erase(0, 1);
hPath = std::string(getenv("HOME")) + hPath;
}
m_audioPath = hPath;
}
void
AudioFileManager::testAudioPath()
{
TQFileInfo info(m_audioPath.c_str());
if (!(info.exists() && info.isDir() && !info.isRelative() &&
info.isWritable() && info.isReadable()))
throw BadAudioPathException(m_audioPath.data());
}
// See if we can find a given file in our search path
// return the first occurence of a match or the empty
// std::string if no match.
//
std::string
AudioFileManager::getFileInPath(const std::string &file)
{
MutexLock lock (&_audioFileManagerLock)
;
TQFileInfo info(file.c_str());
if (info.exists())
return file;
// Build the search filename from the audio path and
// the file basename.
//
TQString searchFile = TQString(m_audioPath.c_str()) + info.fileName();
TQFileInfo searchInfo(searchFile);
if (searchInfo.exists())
return searchFile.latin1();
std::cout << "AudioFileManager::getFileInPath - "
<< "searchInfo = " << searchFile.ascii() << std::endl;
return "";
}
// Check for file path existence
//
int
AudioFileManager::fileExists(const std::string &path)
{
MutexLock lock (&_audioFileManagerLock)
;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin();
it != m_audioFiles.end();
++it) {
if ((*it)->getFilename() == path)
return (*it)->getId();
}
return -1;
}
// Does a specific file id exist on the manager?
//
bool
AudioFileManager::fileExists(AudioFileId id)
{
MutexLock lock (&_audioFileManagerLock)
;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin();
it != m_audioFiles.end();
++it) {
if ((*it)->getId() == id)
return true;
}
return false;
}
void
AudioFileManager::clear()
{
MutexLock lock (&_audioFileManagerLock)
;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin();
it != m_audioFiles.end();
++it) {
m_recordedAudioFiles.erase(*it);
m_derivedAudioFiles.erase(*it);
delete(*it);
}
m_audioFiles.erase(m_audioFiles.begin(), m_audioFiles.end());
// Clear the PeakFileManager too
//
m_peakManager.clear();
}
AudioFile *
AudioFileManager::createRecordingAudioFile()
{
MutexLock lock (&_audioFileManagerLock)
;
AudioFileId newId = getFirstUnusedID();
TQString fileName = "";
while (fileName == "") {
fileName = TQString("rg-%1-%2.wav")
.arg(TQDateTime::currentDateTime().toString("yyyyMMdd-hhmmss"))
.arg(newId + 1);
if (TQFile(m_audioPath.c_str() + fileName).exists()) {
fileName = "";
++newId;
}
}
// insert file into vector
WAVAudioFile *aF = 0;
try {
aF = new WAVAudioFile(newId, fileName.ascii(), (m_audioPath.c_str() + fileName).ascii());
m_audioFiles.push_back(aF);
m_recordedAudioFiles.insert(aF);
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
return aF;
}
std::vector<std::string>
AudioFileManager::createRecordingAudioFiles(unsigned int n)
{
std::vector<std::string> v;
for (unsigned int i = 0; i < n; ++i) {
AudioFile *af = createRecordingAudioFile();
if (af)
v.push_back(m_audioPath + af->getFilename().data());
// !af should not happen, and we have no good recovery if it does
}
return v;
}
bool
AudioFileManager::wasAudioFileRecentlyRecorded(AudioFileId id)
{
AudioFile *file = getAudioFile(id);
if (file)
return (m_recordedAudioFiles.find(file) !=
m_recordedAudioFiles.end());
return false;
}
bool
AudioFileManager::wasAudioFileRecentlyDerived(AudioFileId id)
{
AudioFile *file = getAudioFile(id);
if (file)
return (m_derivedAudioFiles.find(file) !=
m_derivedAudioFiles.end());
return false;
}
void
AudioFileManager::resetRecentlyCreatedFiles()
{
m_recordedAudioFiles.clear();
m_derivedAudioFiles.clear();
}
AudioFile *
AudioFileManager::createDerivedAudioFile(AudioFileId source,
const char *prefix)
{
MutexLock lock (&_audioFileManagerLock);
AudioFile *sourceFile = getAudioFile(source);
if (!sourceFile) return 0;
AudioFileId newId = getFirstUnusedID();
TQString fileName = "";
std::string sourceBase = sourceFile->getShortFilename();
if (sourceBase.length() > 4 && sourceBase.substr(0, 3) == "rg-") {
sourceBase = sourceBase.substr(3);
}
if (sourceBase.length() > 15) sourceBase = sourceBase.substr(0, 15);
while (fileName == "") {
fileName = TQString("%1-%2-%3-%4.wav")
.arg(prefix)
.arg(sourceBase.c_str())
.arg(TQDateTime::currentDateTime().toString("yyyyMMdd-hhmmss"))
.arg(newId + 1);
if (TQFile(m_audioPath.c_str() + fileName).exists()) {
fileName = "";
++newId;
}
}
// insert file into vector
WAVAudioFile *aF = 0;
try {
aF = new WAVAudioFile(newId,
fileName.ascii(),
(m_audioPath.c_str() + fileName).ascii());
m_audioFiles.push_back(aF);
m_derivedAudioFiles.insert(aF);
} catch (SoundFile::BadSoundFileException e) {
delete aF;
throw BadAudioPathException(e);
}
return aF;
}
AudioFileId
AudioFileManager::importURL(const KURL &url, int sampleRate)
{
if (url.isLocalFile()) return importFile(url.path().ascii(), sampleRate);
std::cerr << "AudioFileManager::importURL("<< url.prettyURL().ascii() << ", " << sampleRate << ")" << std::endl;
emit setOperationName(i18n("Downloading file %1").arg(url.prettyURL()));
TQString localPath = "";
if (!TDEIO::NetAccess::download(url, localPath)) {
KMessageBox::error(0, i18n("Cannot download file %1").arg(url.prettyURL()));
throw SoundFile::BadSoundFileException(url.prettyURL().ascii());
}
AudioFileId id = 0;
try {
id = importFile(localPath.ascii(), sampleRate);
} catch (BadAudioPathException ape) {
TDEIO::NetAccess::removeTempFile(localPath);
throw ape;
} catch (SoundFile::BadSoundFileException bse) {
TDEIO::NetAccess::removeTempFile(localPath);
throw bse;
}
return id;
}
bool
AudioFileManager::fileNeedsConversion(const std::string &fileName,
int sampleRate)
{
TDEProcess *proc = new TDEProcess();
*proc << "rosegarden-audiofile-importer";
if (sampleRate > 0) {
*proc << "-r";
*proc << TQString("%1").arg(sampleRate);
}
*proc << "-w";
*proc << fileName.c_str();
proc->start(TDEProcess::Block, TDEProcess::NoCommunication);
int es = proc->exitStatus();
delete proc;
if (es == 0 || es == 1) { // 1 == "other error" -- wouldn't be able to convert
return false;
}
return true;
}
AudioFileId
AudioFileManager::importFile(const std::string &fileName, int sampleRate)
{
MutexLock lock (&_audioFileManagerLock);
std::cerr << "AudioFileManager::importFile("<< fileName << ", " << sampleRate << ")" << std::endl;
TDEProcess *proc = new TDEProcess();
*proc << "rosegarden-audiofile-importer";
if (sampleRate > 0) {
*proc << "-r";
*proc << TQString("%1").arg(sampleRate);
}
*proc << "-w";
*proc << fileName.c_str();
proc->start(TDEProcess::Block, TDEProcess::NoCommunication);
int es = proc->exitStatus();
delete proc;
if (es == 0) {
AudioFileId id = addFile(fileName);
m_expectedSampleRate = sampleRate;
return id;
}
if (es == 2) {
emit setOperationName(i18n("Converting audio file..."));
} else if (es == 3) {
emit setOperationName(i18n("Resampling audio file..."));
} else if (es == 4) {
emit setOperationName(i18n("Converting and resampling audio file..."));
} else {
emit setOperationName(i18n("Importing audio file..."));
}
AudioFileId newId = getFirstUnusedID();
TQString targetName = "";
TQString sourceBase = TQFileInfo(fileName.c_str()).baseName();
if (sourceBase.length() > 3 && sourceBase.startsWith("rg-")) {
sourceBase = sourceBase.right(sourceBase.length() - 3);
}
if (sourceBase.length() > 15) sourceBase = sourceBase.left(15);
while (targetName == "") {
targetName = TQString("conv-%2-%3-%4.wav")
.arg(sourceBase)
.arg(TQDateTime::currentDateTime().toString("yyyyMMdd-hhmmss"))
.arg(newId + 1);
if (TQFile(m_audioPath.c_str() + targetName).exists()) {
targetName = "";
++newId;
}
}
m_importProcess = new TDEProcess;
*m_importProcess << "rosegarden-audiofile-importer";
if (sampleRate > 0) {
*m_importProcess << "-r";
*m_importProcess << TQString("%1").arg(sampleRate);
}
*m_importProcess << "-c";
*m_importProcess << fileName.c_str();
*m_importProcess << (m_audioPath.c_str() + targetName);
m_importProcess->start(TDEProcess::NotifyOnExit, TDEProcess::NoCommunication);
while (m_importProcess->isRunning()) {
kapp->processEvents(100);
}
if (!m_importProcess->normalExit()) {
// interrupted
throw SoundFile::BadSoundFileException(fileName, "Import cancelled");
}
es = m_importProcess->exitStatus();
delete m_importProcess;
m_importProcess = 0;
if (es) {
std::cerr << "audio file importer failed" << std::endl;
throw SoundFile::BadSoundFileException(fileName, i18n("Failed to convert or resample audio file on import").ascii());
} else {
std::cerr << "audio file importer succeeded" << std::endl;
}
// insert file into vector
WAVAudioFile *aF = 0;
aF = new WAVAudioFile(newId,
targetName.ascii(),
(m_audioPath.c_str() + targetName).ascii());
m_audioFiles.push_back(aF);
m_derivedAudioFiles.insert(aF);
// Don't catch SoundFile::BadSoundFileException
m_expectedSampleRate = sampleRate;
return aF->getId();
}
void
AudioFileManager::slotStopImport()
{
if (m_importProcess) {
m_importProcess->kill(SIGTERM);
sleep(1);
m_importProcess->kill(SIGKILL);
}
}
AudioFile*
AudioFileManager::getLastAudioFile()
{
MutexLock lock (&_audioFileManagerLock)
;
std::vector<AudioFile*>::iterator it = m_audioFiles.begin();
AudioFile* audioFile = 0;
while (it != m_audioFiles.end()) {
audioFile = (*it);
it++;
}
return audioFile;
}
std::string
AudioFileManager::substituteHomeForTilde(const std::string &path)
{
std::string rS = path;
std::string homePath = std::string(getenv("HOME"));
// if path length is less than homePath then just return unchanged
if (rS.length() < homePath.length())
return rS;
// if the first section matches the path then substitute
if (rS.substr(0, homePath.length()) == homePath) {
rS.erase(0, homePath.length());
rS = "~" + rS;
}
return rS;
}
std::string
AudioFileManager::substituteTildeForHome(const std::string &path)
{
std::string rS = path;
std::string homePath = std::string(getenv("HOME"));
if (rS.substr(0, 2) == std::string("~/")) {
rS.erase(0, 1); // erase tilde and prepend HOME env
rS = homePath + rS;
}
return rS;
}
// Export audio files and assorted bits and bobs - make sure
// that we store the files in a format that's user independent
// so that people can pack up and swap their songs (including
// audio files) and shift them about easily.
//
std::string
AudioFileManager::toXmlString()
{
MutexLock lock (&_audioFileManagerLock)
;
std::stringstream audioFiles;
std::string audioPath = substituteHomeForTilde(m_audioPath);
audioFiles << "<audiofiles";
if (m_expectedSampleRate != 0) {
audioFiles << " expectedRate=\"" << m_expectedSampleRate << "\"";
}
audioFiles << ">" << std::endl;
audioFiles << " <audioPath value=\""
<< audioPath << "\"/>" << std::endl;
std::string fileName;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin(); it != m_audioFiles.end(); ++it) {
fileName = (*it)->getFilename();
// attempt two substitutions - If the prefix to the filename
// is the same as the audio path then we can dock the prefix
// as it'll be added again next time. If the path doesn't
// have the audio path in it but has our home directory in it
// then swap this out for a tilde '~'
//
#ifdef DEBUG_AUDIOFILEMANAGER
std::cout << "DIR = " << getDirectory(fileName) << " : "
" PATH = " << m_audioPath << std::endl;
#endif
if (getDirectory(fileName) == m_audioPath)
fileName = getShortFilename(fileName);
else
fileName = substituteHomeForTilde(fileName);
audioFiles << " <audio id=\""
<< (*it)->getId()
<< "\" file=\""
<< fileName
<< "\" label=\""
<< encode((*it)->getName())
<< "\"/>" << std::endl;
}
audioFiles << "</audiofiles>" << std::endl;
#if (__GNUC__ < 3)
audioFiles << std::ends;
#else
audioFiles << std::endl;
#endif
return audioFiles.str();
}
// Generate preview peak files or peak chunks according
// to file type.
//
void
AudioFileManager::generatePreviews()
{
MutexLock lock (&_audioFileManagerLock)
;
#ifdef DEBUG_AUDIOFILEMANAGER
std::cout << "AudioFileManager::generatePreviews - "
<< "for " << m_audioFiles.size() << " files"
<< std::endl;
#endif
// Generate peaks if we need to
//
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin(); it != m_audioFiles.end(); ++it) {
if (!m_peakManager.hasValidPeaks(*it))
m_peakManager.generatePeaks(*it, 1);
}
}
// Attempt to stop a preview
//
void
AudioFileManager::slotStopPreview()
{
MutexLock lock (&_audioFileManagerLock);
m_peakManager.stopPreview();
}
// Generate a preview for a specific audio file - say if
// one has just been added to the AudioFileManager.
// Also used for generating previews if the file has been
// modified.
//
bool
AudioFileManager::generatePreview(AudioFileId id)
{
MutexLock lock (&_audioFileManagerLock)
;
AudioFile *audioFile = getAudioFile(id);
if (audioFile == 0)
return false;
if (!m_peakManager.hasValidPeaks(audioFile))
m_peakManager.generatePeaks(audioFile, 1);
return true;
}
AudioFile*
AudioFileManager::getAudioFile(AudioFileId id)
{
MutexLock lock (&_audioFileManagerLock)
;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin();
it != m_audioFiles.end();
it++) {
if ((*it)->getId() == id)
return (*it);
}
return 0;
}
std::vector<float>
AudioFileManager::getPreview(AudioFileId id,
const RealTime &startTime,
const RealTime &endTime,
int width,
bool withMinima)
{
MutexLock lock (&_audioFileManagerLock)
;
AudioFile *audioFile = getAudioFile(id);
if (audioFile == 0) {
return std::vector<float>();
}
if (!m_peakManager.hasValidPeaks(audioFile)) {
std::cerr << "AudioFileManager::getPreview: No peaks for audio file " << audioFile->getFilename() << std::endl;
throw PeakFileManager::BadPeakFileException
(audioFile->getFilename(), __FILE__, __LINE__);
}
return m_peakManager.getPreview(audioFile,
startTime,
endTime,
width,
withMinima);
}
void
AudioFileManager::drawPreview(AudioFileId id,
const RealTime &startTime,
const RealTime &endTime,
TQPixmap *pixmap)
{
MutexLock lock (&_audioFileManagerLock)
;
AudioFile *audioFile = getAudioFile(id);
if (!audioFile)
return ;
if (!m_peakManager.hasValidPeaks(audioFile)) {
std::cerr << "AudioFileManager::getPreview: No peaks for audio file " << audioFile->getFilename() << std::endl;
throw PeakFileManager::BadPeakFileException
(audioFile->getFilename(), __FILE__, __LINE__);
}
std::vector<float> values = m_peakManager.getPreview
(audioFile,
startTime,
endTime,
pixmap->width(),
false);
TQPainter painter(pixmap);
pixmap->fill(kapp->palette().color(TQPalette::Active,
TQColorGroup::Base));
painter.setPen(kapp->palette().color(TQPalette::Active,
TQColorGroup::Dark));
if (values.size() == 0) {
#ifdef DEBUG_AUDIOFILEMANAGER
std::cerr << "AudioFileManager::drawPreview - "
<< "no preview values returned!" << std::endl;
#endif
return ;
}
float yStep = pixmap->height() / 2;
int channels = audioFile->getChannels();
float ch1Value, ch2Value;
if (channels == 0) {
#ifdef DEBUG_AUDIOFILEMANAGER
std::cerr << "AudioFileManager::drawPreview - "
<< "no channels in audio file!" << std::endl;
#endif
return ;
}
// Render pixmap
//
for (int i = 0; i < pixmap->width(); i++) {
// Always get two values for our pixmap no matter how many
// channels in AudioFile as that's all we can display.
//
if (channels == 1) {
ch1Value = values[i];
ch2Value = values[i];
} else {
ch1Value = values[i * channels];
ch2Value = values[i * channels + 1];
}
painter.drawLine(i, static_cast<int>(yStep - ch1Value * yStep),
i, static_cast<int>(yStep + ch2Value * yStep));
}
}
void
AudioFileManager::drawHighlightedPreview(AudioFileId id,
const RealTime &startTime,
const RealTime &endTime,
const RealTime &highlightStart,
const RealTime &highlightEnd,
TQPixmap *pixmap)
{
MutexLock lock (&_audioFileManagerLock)
;
AudioFile *audioFile = getAudioFile(id);
if (!audioFile)
return ;
if (!m_peakManager.hasValidPeaks(audioFile)) {
std::cerr << "AudioFileManager::getPreview: No peaks for audio file " << audioFile->getFilename() << std::endl;
throw PeakFileManager::BadPeakFileException
(audioFile->getFilename(), __FILE__, __LINE__);
}
std::vector<float> values = m_peakManager.getPreview
(audioFile,
startTime,
endTime,
pixmap->width(),
false);
int startWidth = (int)(double(pixmap->width()) * (highlightStart /
(endTime - startTime)));
int endWidth = (int)(double(pixmap->width()) * (highlightEnd /
(endTime - startTime)));
TQPainter painter(pixmap);
pixmap->fill(kapp->palette().color(TQPalette::Active,
TQColorGroup::Base));
float yStep = pixmap->height() / 2;
int channels = audioFile->getChannels();
float ch1Value, ch2Value;
// Render pixmap
//
for (int i = 0; i < pixmap->width(); ++i) {
if ((i * channels + (channels - 1)) >= int(values.size()))
break;
// Always get two values for our pixmap no matter how many
// channels in AudioFile as that's all we can display.
//
if (channels == 1) {
ch1Value = values[i];
ch2Value = values[i];
} else {
ch1Value = values[i * channels];
ch2Value = values[i * channels + 1];
}
if (i < startWidth || i > endWidth)
painter.setPen(kapp->palette().color(TQPalette::Active,
TQColorGroup::Mid));
else
painter.setPen(kapp->palette().color(TQPalette::Active,
TQColorGroup::Dark));
painter.drawLine(i, static_cast<int>(yStep - ch1Value * yStep),
i, static_cast<int>(yStep + ch2Value * yStep));
}
}
void
AudioFileManager::print()
{
MutexLock lock (&_audioFileManagerLock)
;
#ifdef DEBUG_AUDIOFILEMANAGER
std::cout << "AudioFileManager - " << m_audioFiles.size() << " entr";
if (m_audioFiles.size() == 1)
std::cout << "y";
else
std::cout << "ies";
std::cout << std::endl << std::endl;
std::vector<AudioFile*>::iterator it;
for (it = m_audioFiles.begin(); it != m_audioFiles.end(); ++it) {
std::cout << (*it)->getId() << " : " << (*it)->getName()
<< " : \"" << (*it)->getFilename() << "\"" << std::endl;
}
#endif
}
std::vector<SplitPointPair>
AudioFileManager::getSplitPoints(AudioFileId id,
const RealTime &startTime,
const RealTime &endTime,
int threshold,
const RealTime &minTime)
{
MutexLock lock (&_audioFileManagerLock)
;
AudioFile *audioFile = getAudioFile(id);
if (audioFile == 0)
return std::vector<SplitPointPair>();
return m_peakManager.getSplitPoints(audioFile,
startTime,
endTime,
threshold,
minTime);
}
std::set<int>
AudioFileManager::getActualSampleRates() const
{
std::set<int> rates;
for (std::vector<AudioFile *>::const_iterator i = m_audioFiles.begin();
i != m_audioFiles.end(); ++i) {
unsigned int sr = (*i)->getSampleRate();
if (sr != 0) rates.insert(int(sr));
}
return rates;
}
}
#include "AudioFileManager.moc"