2010-11-18 00:32:46 +01:00
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
2011-01-01 17:04:25 +01:00
// Copyright (C) 2004-2011 LoRd_MuldeR <MuldeR2@GMX.de>
2010-11-18 00:32:46 +01:00
//
// 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.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
# include "Thread_Process.h"
# include "Global.h"
2010-11-19 21:11:54 +01:00
# include "Model_AudioFile.h"
2010-11-18 00:32:46 +01:00
# include "Model_Progress.h"
2010-11-20 02:14:22 +01:00
# include "Encoder_Abstract.h"
2010-12-01 23:14:47 +01:00
# include "Decoder_Abstract.h"
2010-12-19 00:50:22 +01:00
# include "Filter_Abstract.h"
# include "Filter_Downmix.h"
2011-05-06 17:51:49 +02:00
# include "Filter_Resample.h"
2011-12-22 00:06:34 +01:00
# include "Tool_WaveProperties.h"
2010-12-01 23:14:47 +01:00
# include "Registry_Decoder.h"
2010-11-20 02:14:22 +01:00
# include "Model_Settings.h"
2010-11-18 00:32:46 +01:00
2010-11-19 21:11:54 +01:00
# include <QUuid>
# include <QFileInfo>
2010-11-20 02:14:22 +01:00
# include <QDir>
2010-11-20 22:14:10 +01:00
# include <QMutex>
# include <QMutexLocker>
2011-03-20 23:32:11 +01:00
# include <QDate>
2010-11-19 21:11:54 +01:00
2010-11-18 00:32:46 +01:00
# include <limits.h>
# include <time.h>
2011-05-06 17:51:49 +02:00
# include <stdlib.h>
# define DIFF(X,Y) ((X > Y) ? (X-Y) : (Y-X))
2011-12-22 18:36:41 +01:00
# define IS_WAVE(X) ((X.formatContainerType().compare("Wave", Qt::CaseInsensitive) == 0) && (X.formatAudioType().compare("PCM", Qt::CaseInsensitive) == 0))
2011-08-05 15:41:19 +02:00
# define STRDEF(STR,DEF) ((!STR.isEmpty()) ? STR : DEF)
2010-11-18 00:32:46 +01:00
2010-11-20 22:14:10 +01:00
QMutex * ProcessThread : : m_mutex_genFileName = NULL ;
2010-11-18 00:32:46 +01:00
////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////
2011-02-25 22:03:39 +01:00
ProcessThread : : ProcessThread ( const AudioFileModel & audioFile , const QString & outputDirectory , const QString & tempDirectory , AbstractEncoder * encoder , const bool prependRelativeSourcePath )
2010-11-19 21:11:54 +01:00
:
m_audioFile ( audioFile ) ,
2010-11-20 02:14:22 +01:00
m_outputDirectory ( outputDirectory ) ,
2011-02-25 22:03:39 +01:00
m_tempDirectory ( tempDirectory ) ,
2010-11-20 02:14:22 +01:00
m_encoder ( encoder ) ,
2010-11-19 21:11:54 +01:00
m_jobId ( QUuid : : createUuid ( ) ) ,
2010-12-14 01:25:13 +01:00
m_prependRelativeSourcePath ( prependRelativeSourcePath ) ,
2011-08-04 23:26:38 +02:00
m_renamePattern ( " <BaseName> " ) ,
2011-12-22 00:06:34 +01:00
m_aborted ( false ) ,
m_propDetect ( new WaveProperties ( ) )
2010-11-18 00:32:46 +01:00
{
2010-11-20 22:14:10 +01:00
if ( m_mutex_genFileName )
{
m_mutex_genFileName = new QMutex ;
}
2010-11-20 02:14:22 +01:00
connect ( m_encoder , SIGNAL ( statusUpdated ( int ) ) , this , SLOT ( handleUpdate ( int ) ) , Qt : : DirectConnection ) ;
2010-11-22 21:45:00 +01:00
connect ( m_encoder , SIGNAL ( messageLogged ( QString ) ) , this , SLOT ( handleMessage ( QString ) ) , Qt : : DirectConnection ) ;
2010-12-01 23:14:47 +01:00
2011-12-22 00:06:34 +01:00
connect ( m_propDetect , SIGNAL ( statusUpdated ( int ) ) , this , SLOT ( handleUpdate ( int ) ) , Qt : : DirectConnection ) ;
connect ( m_propDetect , SIGNAL ( messageLogged ( QString ) ) , this , SLOT ( handleMessage ( QString ) ) , Qt : : DirectConnection ) ;
2010-12-01 23:14:47 +01:00
m_currentStep = UnknownStep ;
2010-11-18 00:32:46 +01:00
}
ProcessThread : : ~ ProcessThread ( void )
{
2010-12-01 23:14:47 +01:00
while ( ! m_tempFiles . isEmpty ( ) )
{
2010-12-21 01:09:25 +01:00
lamexp_remove_file ( m_tempFiles . takeFirst ( ) ) ;
2010-12-01 23:14:47 +01:00
}
2011-01-25 23:12:56 +01:00
while ( ! m_filters . isEmpty ( ) )
{
delete m_filters . takeFirst ( ) ;
}
2010-11-20 02:14:22 +01:00
LAMEXP_DELETE ( m_encoder ) ;
2011-12-22 00:06:34 +01:00
LAMEXP_DELETE ( m_propDetect ) ;
2010-11-18 00:32:46 +01:00
}
2011-05-06 17:51:49 +02:00
////////////////////////////////////////////////////////////
// Thread Entry Point
////////////////////////////////////////////////////////////
2010-11-18 00:32:46 +01:00
void ProcessThread : : run ( )
2010-11-26 00:29:53 +01:00
{
try
{
processFile ( ) ;
}
catch ( . . . )
{
fflush ( stdout ) ;
fflush ( stderr ) ;
2010-12-22 01:01:01 +01:00
fprintf ( stderr , " \n GURU MEDITATION !!! \n " ) ;
2010-11-26 00:29:53 +01:00
FatalAppExit ( 0 , L " Unhandeled exception error, application will exit! " ) ;
TerminateProcess ( GetCurrentProcess ( ) , - 1 ) ;
}
}
void ProcessThread : : processFile ( )
2010-11-18 00:32:46 +01:00
{
m_aborted = false ;
2010-12-01 23:14:47 +01:00
bool bSuccess = true ;
2010-12-19 00:50:22 +01:00
2010-11-18 22:37:35 +01:00
qDebug ( " Process thread %s has started. " , m_jobId . toString ( ) . toLatin1 ( ) . constData ( ) ) ;
2011-01-02 01:09:05 +01:00
emit processStateInitialized ( m_jobId , QFileInfo ( m_audioFile . filePath ( ) ) . fileName ( ) , tr ( " Starting... " ) , ProgressModel : : JobRunning ) ;
2011-07-26 22:17:14 +02:00
handleMessage ( QString ( ) . sprintf ( " LameXP v%u.%02u (Build #%u), compiled on %s at %s " , lamexp_version_major ( ) , lamexp_version_minor ( ) , lamexp_version_build ( ) , lamexp_version_date ( ) . toString ( Qt : : ISODate ) . toLatin1 ( ) . constData ( ) , lamexp_version_time ( ) ) ) ;
2011-03-20 23:32:11 +01:00
handleMessage ( " \n ------------------------------- \n " ) ;
2010-11-18 00:32:46 +01:00
2010-12-01 23:14:47 +01:00
//Generate output file name
2010-11-21 21:51:22 +01:00
QString outFileName = generateOutFileName ( ) ;
if ( outFileName . isEmpty ( ) )
2010-11-20 02:14:22 +01:00
{
2011-01-02 01:09:05 +01:00
emit processStateChanged ( m_jobId , tr ( " Not found! " ) , ProgressModel : : JobFailed ) ;
2010-11-25 18:09:31 +01:00
emit processStateFinished ( m_jobId , outFileName , false ) ;
return ;
}
2011-05-06 17:51:49 +02:00
2010-12-01 23:14:47 +01:00
QString sourceFile = m_audioFile . filePath ( ) ;
2011-12-22 00:06:34 +01:00
//------------------
2010-12-01 23:14:47 +01:00
//Decode source file
2011-12-22 00:06:34 +01:00
//------------------
2011-01-25 23:12:56 +01:00
if ( ! m_filters . isEmpty ( ) | | ! m_encoder - > isFormatSupported ( m_audioFile . formatContainerType ( ) , m_audioFile . formatContainerProfile ( ) , m_audioFile . formatAudioType ( ) , m_audioFile . formatAudioProfile ( ) , m_audioFile . formatAudioVersion ( ) ) )
2010-11-25 18:09:31 +01:00
{
2010-12-01 23:14:47 +01:00
m_currentStep = DecodingStep ;
AbstractDecoder * decoder = DecoderRegistry : : lookup ( m_audioFile . formatContainerType ( ) , m_audioFile . formatContainerProfile ( ) , m_audioFile . formatAudioType ( ) , m_audioFile . formatAudioProfile ( ) , m_audioFile . formatAudioVersion ( ) ) ;
if ( decoder )
{
QString tempFile = generateTempFileName ( ) ;
connect ( decoder , SIGNAL ( statusUpdated ( int ) ) , this , SLOT ( handleUpdate ( int ) ) , Qt : : DirectConnection ) ;
connect ( decoder , SIGNAL ( messageLogged ( QString ) ) , this , SLOT ( handleMessage ( QString ) ) , Qt : : DirectConnection ) ;
bSuccess = decoder - > decode ( sourceFile , tempFile , & m_aborted ) ;
2011-05-15 18:54:40 +02:00
LAMEXP_DELETE ( decoder ) ;
2010-12-01 23:14:47 +01:00
if ( bSuccess )
{
sourceFile = tempFile ;
handleMessage ( " \n ------------------------------- \n " ) ;
2011-12-22 18:36:41 +01:00
m_audioFile . setFormatContainerType ( QString : : fromLatin1 ( " Wave " ) ) ;
m_audioFile . setFormatAudioType ( QString : : fromLatin1 ( " PCM " ) ) ;
2010-12-01 23:14:47 +01:00
}
}
else
{
2011-01-02 01:09:05 +01:00
handleMessage ( QString ( " %1 \n %2 \n \n %3 \t %4 \n %5 \t %6 " ) . arg ( tr ( " The format of this file is NOT supported: " ) , m_audioFile . filePath ( ) , tr ( " Container Format: " ) , m_audioFile . formatContainerInfo ( ) , tr ( " Audio Format: " ) , m_audioFile . formatAudioCompressInfo ( ) ) ) ;
emit processStateChanged ( m_jobId , tr ( " Unsupported! " ) , ProgressModel : : JobFailed ) ;
2010-12-01 23:14:47 +01:00
emit processStateFinished ( m_jobId , outFileName , false ) ;
return ;
}
2011-12-22 18:36:41 +01:00
}
2011-12-21 01:23:21 +01:00
2011-12-22 18:36:41 +01:00
//------------------------------------
//Update audio properties after decode
//------------------------------------
if ( bSuccess & & IS_WAVE ( m_audioFile ) )
{
if ( m_encoder - > supportedSamplerates ( ) | | m_encoder - > supportedBitdepths ( ) | | m_encoder - > requiresDownmix ( ) )
2011-12-21 01:23:21 +01:00
{
2011-12-22 18:36:41 +01:00
m_currentStep = AnalyzeStep ;
bSuccess = m_propDetect - > detect ( sourceFile , & m_audioFile , & m_aborted ) ;
if ( bSuccess )
2011-12-22 00:06:34 +01:00
{
2011-12-22 18:36:41 +01:00
handleMessage ( " \n ------------------------------- \n " ) ;
2011-12-22 00:06:34 +01:00
2011-12-22 18:36:41 +01:00
//Do we need to take care if Stereo downmix?
if ( m_encoder - > requiresDownmix ( ) )
2011-12-22 00:06:34 +01:00
{
2011-12-22 18:36:41 +01:00
insertDownmixFilter ( ) ;
}
//Do we need to take care of downsampling the input?
if ( m_encoder - > supportedSamplerates ( ) | | m_encoder - > supportedBitdepths ( ) )
{
insertDownsampleFilter ( ) ;
2011-12-22 00:06:34 +01:00
}
}
2011-12-21 01:23:21 +01:00
}
}
2011-12-22 00:06:34 +01:00
//-----------------------
2011-08-07 14:04:17 +02:00
//Apply all audio filters
2011-12-22 00:06:34 +01:00
//-----------------------
2011-08-07 14:04:17 +02:00
if ( bSuccess )
2010-12-19 00:50:22 +01:00
{
2011-08-07 14:04:17 +02:00
while ( ! m_filters . isEmpty ( ) )
2010-12-19 00:50:22 +01:00
{
2011-08-07 14:04:17 +02:00
QString tempFile = generateTempFileName ( ) ;
AbstractFilter * poFilter = m_filters . takeFirst ( ) ;
m_currentStep = FilteringStep ;
2010-12-19 00:50:22 +01:00
connect ( poFilter , SIGNAL ( statusUpdated ( int ) ) , this , SLOT ( handleUpdate ( int ) ) , Qt : : DirectConnection ) ;
connect ( poFilter , SIGNAL ( messageLogged ( QString ) ) , this , SLOT ( handleMessage ( QString ) ) , Qt : : DirectConnection ) ;
2011-08-07 14:04:17 +02:00
if ( poFilter - > apply ( sourceFile , tempFile , & m_aborted ) )
2010-12-19 00:50:22 +01:00
{
sourceFile = tempFile ;
}
2011-08-07 14:04:17 +02:00
handleMessage ( " \n ------------------------------- \n " ) ;
delete poFilter ;
}
2010-12-19 00:50:22 +01:00
}
2011-12-22 00:06:34 +01:00
//-----------------
2010-12-01 23:14:47 +01:00
//Encode audio file
2011-12-22 00:06:34 +01:00
//-----------------
2010-12-01 23:14:47 +01:00
if ( bSuccess )
{
m_currentStep = EncodingStep ;
bSuccess = m_encoder - > encode ( sourceFile , m_audioFile , outFileName , & m_aborted ) ;
}
2010-11-20 02:14:22 +01:00
2010-12-01 23:14:47 +01:00
//Make sure output file exists
2010-11-20 02:14:22 +01:00
if ( bSuccess )
2010-11-18 00:32:46 +01:00
{
2010-11-20 22:14:10 +01:00
QFileInfo fileInfo ( outFileName ) ;
bSuccess = fileInfo . exists ( ) & & fileInfo . isFile ( ) & & ( fileInfo . size ( ) > 0 ) ;
2010-11-18 00:32:46 +01:00
}
2011-11-16 22:56:32 +01:00
QThread : : msleep ( 500 ) ;
2010-12-01 23:14:47 +01:00
//Report result
2011-01-02 01:09:05 +01:00
emit processStateChanged ( m_jobId , ( bSuccess ? tr ( " Done. " ) : ( m_aborted ? tr ( " Aborted! " ) : tr ( " Failed! " ) ) ) , ( bSuccess ? ProgressModel : : JobComplete : ProgressModel : : JobFailed ) ) ;
2010-11-20 22:14:10 +01:00
emit processStateFinished ( m_jobId , outFileName , bSuccess ) ;
2010-11-18 22:37:35 +01:00
qDebug ( " Process thread is done. " ) ;
2010-11-18 00:32:46 +01:00
}
2010-11-20 02:14:22 +01:00
////////////////////////////////////////////////////////////
// SLOTS
////////////////////////////////////////////////////////////
void ProcessThread : : handleUpdate ( int progress )
{
2011-11-16 22:56:32 +01:00
//printf("Progress: %d\n", progress);
2010-12-01 23:14:47 +01:00
switch ( m_currentStep )
{
case EncodingStep :
2011-01-02 01:09:05 +01:00
emit processStateChanged ( m_jobId , QString ( " %1 (%2%) " ).arg(tr( " Encoding " ), QString::number(progress)), ProgressModel::JobRunning) ;
2010-12-19 00:50:22 +01:00
break ;
2011-12-22 00:06:34 +01:00
case AnalyzeStep :
emit processStateChanged ( m_jobId , QString ( " %1 (%2%) " ).arg(tr( " Analyzing " ), QString::number(progress)), ProgressModel::JobRunning) ;
break ;
2010-12-19 00:50:22 +01:00
case FilteringStep :
2011-01-02 01:09:05 +01:00
emit processStateChanged ( m_jobId , QString ( " %1 (%2%) " ).arg(tr( " Filtering " ), QString::number(progress)), ProgressModel::JobRunning) ;
2010-12-01 23:14:47 +01:00
break ;
case DecodingStep :
2011-01-02 01:09:05 +01:00
emit processStateChanged ( m_jobId , QString ( " %1 (%2%) " ).arg(tr( " Decoding " ), QString::number(progress)), ProgressModel::JobRunning) ;
2010-12-01 23:14:47 +01:00
break ;
}
2010-11-20 02:14:22 +01:00
}
2010-11-22 21:45:00 +01:00
void ProcessThread : : handleMessage ( const QString & line )
{
emit processMessageLogged ( m_jobId , line ) ;
}
2010-11-20 02:14:22 +01:00
////////////////////////////////////////////////////////////
// PRIVAE FUNCTIONS
////////////////////////////////////////////////////////////
QString ProcessThread : : generateOutFileName ( void )
{
2010-11-20 22:14:10 +01:00
QMutexLocker lock ( m_mutex_genFileName ) ;
2010-11-20 02:14:22 +01:00
int n = 1 ;
2010-11-21 21:51:22 +01:00
QFileInfo sourceFile ( m_audioFile . filePath ( ) ) ;
if ( ! sourceFile . exists ( ) | | ! sourceFile . isFile ( ) )
{
2011-01-02 01:09:05 +01:00
handleMessage ( QString ( " %1 \n %2 " ) . arg ( tr ( " The source audio file could not be found: " ) , sourceFile . absoluteFilePath ( ) ) ) ;
2010-11-25 18:09:31 +01:00
return QString ( ) ;
}
QFile readTest ( sourceFile . canonicalFilePath ( ) ) ;
if ( ! readTest . open ( QIODevice : : ReadOnly ) )
{
2011-01-02 01:09:05 +01:00
handleMessage ( QString ( " %1 \n %2 " ) . arg ( tr ( " The source audio file could not be opened for reading: " ) , readTest . fileName ( ) ) ) ;
2010-11-21 21:51:22 +01:00
return QString ( ) ;
}
2010-11-25 18:09:31 +01:00
else
{
readTest . close ( ) ;
}
2010-11-20 02:14:22 +01:00
2010-11-21 21:51:22 +01:00
QString baseName = sourceFile . completeBaseName ( ) ;
QDir targetDir ( m_outputDirectory . isEmpty ( ) ? sourceFile . canonicalPath ( ) : m_outputDirectory ) ;
2010-12-14 01:25:13 +01:00
if ( m_prependRelativeSourcePath & & ! m_outputDirectory . isEmpty ( ) )
{
QDir rootDir = sourceFile . dir ( ) ;
while ( ! rootDir . isRoot ( ) )
{
if ( ! rootDir . cdUp ( ) ) break ;
}
targetDir . setPath ( QString ( " %1/%2 " ) . arg ( targetDir . absolutePath ( ) , QFileInfo ( rootDir . relativeFilePath ( sourceFile . canonicalFilePath ( ) ) ) . path ( ) ) ) ;
}
2010-11-21 21:51:22 +01:00
if ( ! targetDir . exists ( ) )
{
targetDir . mkpath ( " . " ) ;
if ( ! targetDir . exists ( ) )
{
2011-01-02 01:09:05 +01:00
handleMessage ( QString ( " %1 \n %2 " ) . arg ( tr ( " The target output directory doesn't exist and could NOT be created: " ) , targetDir . absolutePath ( ) ) ) ;
2010-11-21 21:51:22 +01:00
return QString ( ) ;
}
}
2010-12-07 22:58:28 +01:00
QFile writeTest ( QString ( " %1/.%2 " ) . arg ( targetDir . canonicalPath ( ) , lamexp_rand_str ( ) ) ) ;
2010-11-25 18:09:31 +01:00
if ( ! writeTest . open ( QIODevice : : ReadWrite ) )
{
2011-01-02 01:09:05 +01:00
handleMessage ( QString ( " %1 \n %2 " ) . arg ( tr ( " The target output directory is NOT writable: " ) , targetDir . absolutePath ( ) ) ) ;
2010-11-25 18:09:31 +01:00
return QString ( ) ;
}
else
{
writeTest . close ( ) ;
writeTest . remove ( ) ;
}
2011-08-04 23:26:38 +02:00
QString fileName = m_renamePattern ;
2011-08-05 15:41:19 +02:00
fileName . replace ( " <BaseName> " , STRDEF ( baseName , tr ( " Unknown File Name " ) ) , Qt : : CaseInsensitive ) ;
2011-08-04 23:26:38 +02:00
fileName . replace ( " <TrackNo> " , QString ( ) . sprintf ( " %02d " , m_audioFile . filePosition ( ) ) , Qt : : CaseInsensitive ) ;
2011-08-05 15:41:19 +02:00
fileName . replace ( " <Title> " , STRDEF ( m_audioFile . fileName ( ) , tr ( " Unknown Title " ) ) , Qt : : CaseInsensitive ) ;
fileName . replace ( " <Artist> " , STRDEF ( m_audioFile . fileArtist ( ) , tr ( " Unknown Artist " ) ) , Qt : : CaseInsensitive ) ;
fileName . replace ( " <Album> " , STRDEF ( m_audioFile . fileAlbum ( ) , tr ( " Unknown Album " ) ) , Qt : : CaseInsensitive ) ;
2011-08-04 23:26:38 +02:00
fileName . replace ( " <Year> " , QString ( ) . sprintf ( " %04d " , m_audioFile . fileYear ( ) ) , Qt : : CaseInsensitive ) ;
2011-08-05 15:41:19 +02:00
fileName . replace ( " <Comment> " , STRDEF ( m_audioFile . fileComment ( ) , tr ( " Unknown Comment " ) ) , Qt : : CaseInsensitive ) ;
2011-08-04 23:26:38 +02:00
fileName = lamexp_clean_filename ( fileName ) . simplified ( ) ;
QString outFileName = QString ( " %1/%2.%3 " ) . arg ( targetDir . canonicalPath ( ) , fileName , m_encoder - > extension ( ) ) ;
2010-11-20 02:14:22 +01:00
while ( QFileInfo ( outFileName ) . exists ( ) )
{
2011-08-04 23:26:38 +02:00
outFileName = QString ( " %1/%2 (%3).%4 " ) . arg ( targetDir . canonicalPath ( ) , fileName , QString : : number ( + + n ) , m_encoder - > extension ( ) ) ;
2010-11-20 02:14:22 +01:00
}
2010-11-20 22:14:10 +01:00
QFile placeholder ( outFileName ) ;
if ( placeholder . open ( QIODevice : : WriteOnly ) )
{
placeholder . close ( ) ;
}
2010-11-20 02:14:22 +01:00
return outFileName ;
}
2010-12-01 23:14:47 +01:00
QString ProcessThread : : generateTempFileName ( void )
{
QMutexLocker lock ( m_mutex_genFileName ) ;
2011-02-25 22:03:39 +01:00
QString tempFileName = QString ( " %1/%2.wav " ) . arg ( m_tempDirectory , lamexp_rand_str ( ) ) ;
2010-12-01 23:14:47 +01:00
while ( QFileInfo ( tempFileName ) . exists ( ) )
{
2011-02-25 22:03:39 +01:00
tempFileName = QString ( " %1/%2.wav " ) . arg ( m_tempDirectory , lamexp_rand_str ( ) ) ;
2010-12-01 23:14:47 +01:00
}
QFile file ( tempFileName ) ;
if ( file . open ( QFile : : ReadWrite ) )
{
file . close ( ) ;
}
m_tempFiles < < tempFileName ;
return tempFileName ;
}
2011-05-06 17:51:49 +02:00
void ProcessThread : : insertDownsampleFilter ( void )
{
2011-12-22 18:36:41 +01:00
int targetSampleRate = 0 ;
int targetBitDepth = 0 ;
/* Adjust sample rate */
if ( m_encoder - > supportedSamplerates ( ) & & m_audioFile . formatAudioSamplerate ( ) )
2011-05-06 17:51:49 +02:00
{
2011-12-22 18:36:41 +01:00
bool applyDownsampling = true ;
//Check if downsampling filter is already in the chain
for ( int i = 0 ; i < m_filters . count ( ) ; i + + )
2011-05-06 17:51:49 +02:00
{
2011-12-22 18:36:41 +01:00
if ( dynamic_cast < ResampleFilter * > ( m_filters . at ( i ) ) )
{
qWarning ( " Encoder requires downsampling, but user has already set resamling filter! " ) ;
handleMessage ( " WARNING: Encoder may need resampling, but already using resample filter. Encoding *may* fail! \n " ) ;
applyDownsampling = false ;
}
2011-05-06 17:51:49 +02:00
}
2011-12-22 18:36:41 +01:00
//Now determine the target sample rate, if required
if ( applyDownsampling )
{
const unsigned int * supportedRates = m_encoder - > supportedSamplerates ( ) ;
const unsigned int inputRate = m_audioFile . formatAudioSamplerate ( ) ;
unsigned int currentDiff = UINT_MAX , minimumDiff = UINT_MAX , bestRate = UINT_MAX ;
//Find the most suitable supported sampling rate
for ( int i = 0 ; supportedRates [ i ] ; i + + )
{
currentDiff = DIFF ( inputRate , supportedRates [ i ] ) ;
if ( currentDiff < minimumDiff )
{
bestRate = supportedRates [ i ] ;
minimumDiff = currentDiff ;
if ( ! ( minimumDiff > 0 ) ) break ;
}
}
if ( bestRate ! = inputRate )
{
targetSampleRate = ( bestRate ! = UINT_MAX ) ? bestRate : supportedRates [ 0 ] ;
}
}
}
/* Adjust bit depth (word size) */
if ( m_encoder - > supportedBitdepths ( ) & & m_audioFile . formatAudioBitdepth ( ) )
2011-05-06 17:51:49 +02:00
{
2011-12-22 18:36:41 +01:00
const unsigned int * supportedBPS = m_encoder - > supportedBitdepths ( ) ;
const unsigned int inputBPS = m_audioFile . formatAudioBitdepth ( ) ;
unsigned int currentDiff = UINT_MAX , minimumDiff = UINT_MAX , bestBPS = UINT_MAX ;
2011-05-06 17:51:49 +02:00
2011-12-22 18:36:41 +01:00
//Find the most suitable supported bit depth
for ( int i = 0 ; supportedBPS [ i ] ; i + + )
2011-05-06 17:51:49 +02:00
{
2011-12-22 18:36:41 +01:00
currentDiff = DIFF ( inputBPS , supportedBPS [ i ] ) ;
2011-05-06 17:51:49 +02:00
if ( currentDiff < minimumDiff )
{
2011-12-22 18:36:41 +01:00
bestBPS = supportedBPS [ i ] ;
2011-05-06 17:51:49 +02:00
minimumDiff = currentDiff ;
if ( ! ( minimumDiff > 0 ) ) break ;
}
}
2011-12-22 18:36:41 +01:00
if ( bestBPS ! = inputBPS )
2011-05-06 17:51:49 +02:00
{
2011-12-22 18:36:41 +01:00
targetBitDepth = ( bestBPS ! = UINT_MAX ) ? bestBPS : supportedBPS [ 0 ] ;
2011-05-06 17:51:49 +02:00
}
}
2011-12-22 18:36:41 +01:00
/* Insert the filter */
if ( targetSampleRate | | targetBitDepth )
{
m_filters . append ( new ResampleFilter ( targetSampleRate , targetBitDepth ) ) ;
}
2011-12-21 01:23:21 +01:00
}
2011-08-06 18:56:09 +02:00
void ProcessThread : : insertDownmixFilter ( void )
{
bool applyDownmixing = true ;
//Check if downmixing filter is already in the chain
for ( int i = 0 ; i < m_filters . count ( ) ; i + + )
{
if ( dynamic_cast < DownmixFilter * > ( m_filters . at ( i ) ) )
{
qWarning ( " Encoder requires Stereo downmix, but user has already forced downmix! " ) ;
applyDownmixing = false ;
}
}
2011-08-27 21:28:20 +02:00
2011-08-06 18:56:09 +02:00
//Now add the downmixing filter, if needed
if ( applyDownmixing )
{
2011-08-27 21:28:20 +02:00
unsigned int channels = m_audioFile . formatAudioChannels ( ) ;
if ( ( channels = = 0 ) | | ( channels > 2 ) )
{
2011-12-22 18:36:41 +01:00
m_filters . append ( new DownmixFilter ( ) ) ;
2011-08-27 21:28:20 +02:00
}
2011-08-06 18:56:09 +02:00
}
}
2011-05-06 17:51:49 +02:00
////////////////////////////////////////////////////////////
// PUBLIC FUNCTIONS
////////////////////////////////////////////////////////////
2011-01-25 23:12:56 +01:00
void ProcessThread : : addFilter ( AbstractFilter * filter )
{
m_filters . append ( filter ) ;
}
2011-08-04 23:26:38 +02:00
void ProcessThread : : setRenamePattern ( const QString & pattern )
{
2011-08-05 02:33:32 +02:00
QString newPattern = pattern . simplified ( ) ;
if ( ! newPattern . isEmpty ( ) ) m_renamePattern = newPattern ;
2011-08-04 23:26:38 +02:00
}
2010-11-18 00:32:46 +01:00
////////////////////////////////////////////////////////////
// EVENTS
////////////////////////////////////////////////////////////
2011-11-16 22:56:32 +01:00
/*NONE*/