|
|
|
// -*- c-basic-offset: 4 -*-
|
|
|
|
|
|
|
|
/*
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
// Accepts a file handle positioned somewhere in sample data (could
|
|
|
|
// be at the start) along with the necessary meta information for
|
|
|
|
// decoding (channels, bits per sample) and turns the sample data
|
|
|
|
// into peak data and generates a BWF format peak chunk file. This
|
|
|
|
// file can exist by itself (in the case this is being generated
|
|
|
|
// by a WAV) or be accomodated inside a BWF format file.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
#include <tqobject.h>
|
|
|
|
|
|
|
|
#include "PeakFileManager.h"
|
|
|
|
#include "AudioFile.h"
|
|
|
|
#include "RealTime.h"
|
|
|
|
#include "PeakFile.h"
|
|
|
|
|
|
|
|
namespace Rosegarden
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
PeakFileManager::PeakFileManager():
|
|
|
|
m_updatePercentage(0),
|
|
|
|
m_currentPeakFile(0)
|
|
|
|
{}
|
|
|
|
|
|
|
|
PeakFileManager::~PeakFileManager()
|
|
|
|
{}
|
|
|
|
|
|
|
|
// Inserts PeakFile based on AudioFile if it doesn't already exist
|
|
|
|
bool
|
|
|
|
PeakFileManager::insertAudioFile(AudioFile *audioFile)
|
|
|
|
{
|
|
|
|
std::vector<PeakFile*>::iterator it;
|
|
|
|
|
|
|
|
for (it = m_peakFiles.begin(); it != m_peakFiles.end(); it++) {
|
|
|
|
if ((*it)->getAudioFile()->getId() == audioFile->getId())
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
std::cout << "PeakFileManager::insertAudioFile - creating peak file "
|
|
|
|
<< m_peakFiles.size() + 1
|
|
|
|
<< " for \"" << audioFile->getFilename()
|
|
|
|
<< "\"" << std::endl;
|
|
|
|
*/
|
|
|
|
|
|
|
|
// Insert
|
|
|
|
m_peakFiles.push_back(new PeakFile(audioFile));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Removes peak file from PeakFileManager - doesn't affect audioFile
|
|
|
|
//
|
|
|
|
bool
|
|
|
|
PeakFileManager::removeAudioFile(AudioFile *audioFile)
|
|
|
|
{
|
|
|
|
std::vector<PeakFile*>::iterator it;
|
|
|
|
|
|
|
|
for (it = m_peakFiles.begin(); it != m_peakFiles.end(); it++) {
|
|
|
|
if ((*it)->getAudioFile()->getId() == audioFile->getId()) {
|
|
|
|
if (m_currentPeakFile == *it)
|
|
|
|
m_currentPeakFile = 0;
|
|
|
|
delete *it;
|
|
|
|
m_peakFiles.erase(it);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Auto-insert PeakFile into manager if it doesn't already exist
|
|
|
|
//
|
|
|
|
PeakFile*
|
|
|
|
PeakFileManager::getPeakFile(AudioFile *audioFile)
|
|
|
|
{
|
|
|
|
std::vector<PeakFile*>::iterator it;
|
|
|
|
PeakFile *ptr = 0;
|
|
|
|
|
|
|
|
while (ptr == 0) {
|
|
|
|
for (it = m_peakFiles.begin(); it != m_peakFiles.end(); it++)
|
|
|
|
if ((*it)->getAudioFile()->getId() == audioFile->getId())
|
|
|
|
ptr = *it;
|
|
|
|
|
|
|
|
// If nothing is found then insert and retry
|
|
|
|
//
|
|
|
|
if (ptr == 0) {
|
|
|
|
// Insert - if we fail we return as empty
|
|
|
|
//
|
|
|
|
if (insertAudioFile(audioFile) == false)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Does a given AudioFile have a valid peak file or peak chunk?
|
|
|
|
//
|
|
|
|
bool
|
|
|
|
PeakFileManager::hasValidPeaks(AudioFile *audioFile)
|
|
|
|
{
|
|
|
|
if (audioFile->getType() == WAV) {
|
|
|
|
// Check external peak file
|
|
|
|
PeakFile *peakFile = getPeakFile(audioFile);
|
|
|
|
|
|
|
|
if (peakFile == 0) {
|
|
|
|
#ifdef DEBUG_PEAKFILEMANAGER
|
|
|
|
std::cerr << "PeakFileManager::hasValidPeaks - no peak file found"
|
|
|
|
<< std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// If it doesn't open and parse correctly
|
|
|
|
if (peakFile->open() == false)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// or if the data is old or invalid
|
|
|
|
if (peakFile->isValid() == false)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
} else if (audioFile->getType() == BWF) {
|
|
|
|
// check internal peak chunk
|
|
|
|
} else {
|
|
|
|
#ifdef DEBUG_PEAKFILEMANAGER
|
|
|
|
std::cout << "PeakFileManager::hasValidPeaks - unsupported file type"
|
|
|
|
<< std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate the peak file. Checks to see if peak file exists
|
|
|
|
// already and if so if it's up to date. If it isn't then we
|
|
|
|
// regenerate.
|
|
|
|
//
|
|
|
|
void
|
|
|
|
PeakFileManager::generatePeaks(AudioFile *audioFile,
|
|
|
|
unsigned short updatePercentage)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG_PEAKFILEMANAGER
|
|
|
|
std::cout << "PeakFileManager::generatePeaks - generating peaks for \""
|
|
|
|
<< audioFile->getFilename() << "\"" << std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (audioFile->getType() == WAV) {
|
|
|
|
m_currentPeakFile = getPeakFile(audioFile);
|
|
|
|
|
|
|
|
TQObject::connect(m_currentPeakFile, TQT_SIGNAL(setProgress(int)),
|
|
|
|
this, TQT_SIGNAL(setProgress(int)));
|
|
|
|
|
|
|
|
// Just write out a peak file
|
|
|
|
//
|
|
|
|
if (m_currentPeakFile->write(updatePercentage) == false) {
|
|
|
|
std::cerr << "Can't write peak file for " << audioFile->getFilename() << " - no preview generated" << std::endl;
|
|
|
|
throw BadPeakFileException
|
|
|
|
(audioFile->getFilename(), __FILE__, __LINE__);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The m_currentPeakFile might have been cancelled (see stopPreview())
|
|
|
|
//
|
|
|
|
if (m_currentPeakFile) {
|
|
|
|
// close writes out important things
|
|
|
|
m_currentPeakFile->close();
|
|
|
|
m_currentPeakFile->disconnect();
|
|
|
|
}
|
|
|
|
} else if (audioFile->getType() == BWF) {
|
|
|
|
// write the file out and incorporate the peak chunk
|
|
|
|
} else {
|
|
|
|
#ifdef DEBUG_PEAKFILEMANAGER
|
|
|
|
std::cerr << "PeakFileManager::generatePeaks - unsupported file type"
|
|
|
|
<< std::endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return ;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_currentPeakFile = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<float>
|
|
|
|
PeakFileManager::getPreview(AudioFile *audioFile,
|
|
|
|
const RealTime &startTime,
|
|
|
|
const RealTime &endTime,
|
|
|
|
int width,
|
|
|
|
bool showMinima)
|
|
|
|
{
|
|
|
|
std::vector<float> rV;
|
|
|
|
|
|
|
|
// If we've got no channels then the audio file hasn't
|
|
|
|
// completed (recording) - so don't generate a preview
|
|
|
|
//
|
|
|
|
if (audioFile->getChannels() == 0)
|
|
|
|
return rV;
|
|
|
|
|
|
|
|
if (audioFile->getType() == WAV) {
|
|
|
|
PeakFile *peakFile = getPeakFile(audioFile);
|
|
|
|
|
|
|
|
// just write out a peak file
|
|
|
|
try {
|
|
|
|
peakFile->open();
|
|
|
|
rV = peakFile->getPreview(startTime,
|
|
|
|
endTime,
|
|
|
|
width,
|
|
|
|
showMinima);
|
|
|
|
} catch (SoundFile::BadSoundFileException e) {
|
|
|
|
#ifdef DEBUG_PEAKFILEMANAGER
|
|
|
|
std::cout << "PeakFileManager::getPreview "
|
|
|
|
<< "\"" << e << "\"" << std::endl;
|
|
|
|
#else
|
|
|
|
|
|
|
|
;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
throw BadPeakFileException(e);
|
|
|
|
}
|
|
|
|
} else if (audioFile->getType() == BWF) {
|
|
|
|
// write the file out and incorporate the peak chunk
|
|
|
|
}
|
|
|
|
#ifdef DEBUG_PEAKFILEMANAGER
|
|
|
|
else {
|
|
|
|
std::cerr << "PeakFileManager::getPreview - unsupported file type"
|
|
|
|
<< std::endl;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return rV;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PeakFileManager::clear()
|
|
|
|
{
|
|
|
|
std::vector<PeakFile*>::iterator it;
|
|
|
|
|
|
|
|
for (it = m_peakFiles.begin(); it != m_peakFiles.end(); it++)
|
|
|
|
delete (*it);
|
|
|
|
|
|
|
|
m_peakFiles.erase(m_peakFiles.begin(), m_peakFiles.end());
|
|
|
|
|
|
|
|
m_currentPeakFile = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<SplitPointPair>
|
|
|
|
PeakFileManager::getSplitPoints(AudioFile *audioFile,
|
|
|
|
const RealTime &startTime,
|
|
|
|
const RealTime &endTime,
|
|
|
|
int threshold,
|
|
|
|
const RealTime &minTime)
|
|
|
|
{
|
|
|
|
PeakFile *peakFile = getPeakFile(audioFile);
|
|
|
|
|
|
|
|
if (peakFile == 0)
|
|
|
|
return std::vector<SplitPointPair>();
|
|
|
|
|
|
|
|
return peakFile->getSplitPoints(startTime,
|
|
|
|
endTime,
|
|
|
|
threshold,
|
|
|
|
minTime);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
PeakFileManager::stopPreview()
|
|
|
|
{
|
|
|
|
if (m_currentPeakFile) {
|
|
|
|
// Stop processing
|
|
|
|
//
|
|
|
|
TQString fileName = TQString(m_currentPeakFile->getFilename().data());
|
|
|
|
m_currentPeakFile->setProcessingPeaks(false);
|
|
|
|
m_currentPeakFile->disconnect();
|
|
|
|
|
|
|
|
TQFile file(fileName);
|
|
|
|
bool removed = file.remove();
|
|
|
|
|
|
|
|
#ifdef DEBUG_PEAKFILEMANAGER
|
|
|
|
|
|
|
|
if (removed) {
|
|
|
|
std::cout << "PeakFileManager::stopPreview() - removed preview"
|
|
|
|
<< std::endl;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
//delete m_currentPeakFile;
|
|
|
|
m_currentPeakFile = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#include "PeakFileManager.moc"
|