File indexing completed on 2024-05-05 04:48:36

0001 /****************************************************************************************
0002  * Copyright (c) 2004 Frederik Holljen <fh@ez.no>                                       *
0003  * Copyright (c) 2004,2005 Max Howell <max.howell@methylblue.com>                       *
0004  * Copyright (c) 2004-2013 Mark Kretschmann <kretschmann@kde.org>                       *
0005  * Copyright (c) 2006,2008 Ian Monroe <ian@monroe.nu>                                   *
0006  * Copyright (c) 2008 Jason A. Donenfeld <Jason@zx2c4.com>                              *
0007  * Copyright (c) 2009 Nikolaj Hald Nielsen <nhn@kde.org>                                *
0008  * Copyright (c) 2009 Artur Szymiec <artur.szymiec@gmail.com>                           *
0009  * Copyright (c) 2013 Anmol Ahuja <darthcodus@gmail.com>                                *
0010  *                                                                                      *
0011  * This program is free software; you can redistribute it and/or modify it under        *
0012  * the terms of the GNU General Public License as published by the Free Software        *
0013  * Foundation; either version 2 of the License, or (at your option) any later           *
0014  * version.                                                                             *
0015  *                                                                                      *
0016  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0017  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0018  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0019  *                                                                                      *
0020  * You should have received a copy of the GNU General Public License along with         *
0021  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0022  ****************************************************************************************/
0023 
0024 #define DEBUG_PREFIX "EqualizerController"
0025 
0026 #include "playback/EqualizerController.h"
0027 
0028 #include "amarokconfig.h"
0029 #include "core/support/Debug.h"
0030 #include "equalizer/EqualizerPresets.h"
0031 
0032 #include <KLocalizedString>
0033 
0034 #include <phonon/BackendCapabilities>
0035 #include <phonon/EffectParameter>
0036 
0037 EqualizerController::EqualizerController( QObject *object )
0038 : QObject( object )
0039 {}
0040 
0041 EqualizerController::~EqualizerController()
0042 {}
0043 
0044 //////////////////////////////////////////////////////////////////////////////////////////
0045 // PUBLIC
0046 //////////////////////////////////////////////////////////////////////////////////////////
0047 
0048 void
0049 EqualizerController::initialize( const Phonon::Path &path )
0050 {
0051     DEBUG_BLOCK
0052     m_path = path;
0053     delete m_equalizer.data();
0054 
0055     using namespace Phonon;
0056 
0057     // Add an equalizer effect if available
0058     const QList<EffectDescription> effects = BackendCapabilities::availableAudioEffects();
0059     QRegExp equalizerRegExp( QStringLiteral( "equalizer.*%1.*bands" ).arg( s_equalizerBandsNum ),
0060                              Qt::CaseInsensitive );
0061     foreach( const EffectDescription &description, effects )
0062     {
0063         if( !description.name().contains( equalizerRegExp ) )
0064             continue;
0065 
0066         QScopedPointer<Effect> equalizer( new Effect( description, this ) );
0067         int parameterCount = equalizer->parameters().count();
0068         if( parameterCount == s_equalizerBandsNum || parameterCount == s_equalizerBandsNum + 1 )
0069         {
0070             debug() << "Established Phonon equalizer effect with" << parameterCount
0071                     << "parameters.";
0072             m_equalizer = equalizer.take(); // accept the effect
0073             eqUpdate();
0074             break;
0075         }
0076         else
0077         {
0078             QStringList paramNames;
0079             foreach( const EffectParameter &param, equalizer->parameters() )
0080                 paramNames << param.name();
0081             warning() << "Phonon equalizer effect" << description.name() << "with description"
0082                       << description.description() << "has" << parameterCount << "parameters ("
0083                       << paramNames << ") - which is unexpected. Trying other effects.";
0084         }
0085     }
0086 }
0087 
0088 //////////////////////////////////////////////////////////////////////////////////////////
0089 // PUBLIC
0090 //////////////////////////////////////////////////////////////////////////////////////////
0091 
0092 bool
0093 EqualizerController::isEqSupported() const
0094 {
0095     // If effect was created it means we have equalizer support
0096     return m_equalizer;
0097 }
0098 
0099 double
0100 EqualizerController::eqMaxGain() const
0101 {
0102    if( !m_equalizer )
0103        return 100;
0104    QList<Phonon::EffectParameter> equalizerParameters = m_equalizer->parameters();
0105    if( equalizerParameters.isEmpty() )
0106        return 100.0;
0107    double mScale;
0108    mScale = ( qAbs(equalizerParameters.at(0).maximumValue().toDouble() )
0109               + qAbs( equalizerParameters.at(0).minimumValue().toDouble() ) );
0110    mScale /= 2.0;
0111    return mScale;
0112 }
0113 
0114 QStringList
0115 EqualizerController::eqBandsFreq() const
0116 {
0117     // This will extract the bands frequency values from effect parameter name
0118     // as long as they follow the rules:
0119     // eq-preamp parameter will contain 'pre-amp' string
0120     // bands parameters are described using schema 'xxxHz'
0121     QStringList bandFrequencies;
0122     if( !m_equalizer )
0123         return bandFrequencies;
0124     QList<Phonon::EffectParameter> equalizerParameters = m_equalizer->parameters();
0125     if( equalizerParameters.isEmpty() )
0126         return bandFrequencies;
0127     QRegExp rx( "\\d+(?=Hz)" );
0128     foreach( const Phonon::EffectParameter &mParam, equalizerParameters )
0129     {
0130         if( mParam.name().contains( rx ) )
0131         {
0132             if( rx.cap( 0 ).toInt() < 1000 )
0133                 bandFrequencies << i18n( "%0\nHz" ).arg( rx.cap( 0 ) );
0134             else
0135                 bandFrequencies << i18n( "%0\nkHz" ).arg( QString::number( rx.cap( 0 ).toInt()/1000 ) );
0136         }
0137         else
0138             bandFrequencies << mParam.name();
0139     }
0140     return bandFrequencies;
0141 }
0142 
0143 void
0144 EqualizerController::eqUpdate()
0145 {
0146     DEBUG_BLOCK
0147     // if equalizer not present simply return
0148     if( !m_equalizer )
0149         return;
0150     // check if equalizer should be disabled ??
0151     QList<int> equalizerParametersCfg;
0152     if( AmarokConfig::equalizerMode() <= 0 )
0153     {
0154         // Remove effect from path
0155         if( m_path.effects().indexOf( m_equalizer.data() ) != -1 )
0156             m_path.removeEffect( m_equalizer.data() );
0157     }
0158     else
0159     {
0160         // Set equalizer parameter according to the gains from settings
0161         QList<Phonon::EffectParameter> equalizerParameters = m_equalizer->parameters();
0162         equalizerParametersCfg = AmarokConfig::equalizerGains();
0163 
0164         QListIterator<int> equalizerParametersIt( equalizerParametersCfg );
0165         double scaledVal; // Scaled value to set from universal -100 - 100 range to plugin scale
0166         // Checking if preamp is present in equalizer parameters
0167         if( equalizerParameters.size() == s_equalizerBandsNum )
0168         {
0169             // If pre-amp is not present then skip the first element of equalizer gain
0170             if( equalizerParametersIt.hasNext() )
0171                 equalizerParametersIt.next();
0172         }
0173         foreach( const Phonon::EffectParameter &mParam, equalizerParameters )
0174         {
0175             scaledVal = equalizerParametersIt.hasNext() ? equalizerParametersIt.next() : 0;
0176             scaledVal *= qAbs(mParam.maximumValue().toDouble() )
0177                          + qAbs( mParam.minimumValue().toDouble() );
0178             scaledVal /= 200.0;
0179             m_equalizer->setParameterValue( mParam, scaledVal );
0180         }
0181         // Insert effect into path if needed
0182         if( m_path.effects().indexOf( m_equalizer.data() ) == -1 )
0183         {
0184             if( !m_path.effects().isEmpty() )
0185             {
0186                 m_path.insertEffect( m_equalizer.data(), m_path.effects().first() );
0187             }
0188             else
0189             {
0190                 m_path.insertEffect( m_equalizer.data() );
0191             }
0192         }
0193     }
0194     Q_EMIT gainsChanged( equalizerParametersCfg );
0195 }
0196 
0197 QString
0198 EqualizerController::equalizerPreset() const
0199 {
0200     int index = AmarokConfig::equalizerMode() - 1;
0201     if( index > 0 )
0202         return EqualizerPresets::eqGlobalList()[index];
0203     else
0204         return QString();
0205 }
0206 
0207 void
0208 EqualizerController::applyEqualizerPresetByIndex( int index )
0209 {
0210     if( index > -1 )
0211     {
0212         AmarokConfig::setEqualizerMode( index + 1 );
0213         AmarokConfig::setEqualizerGains( EqualizerPresets::eqCfgGetPresetVal( EqualizerPresets::eqGlobalTranslatedList().value( index ) ) );
0214     }
0215     else
0216         AmarokConfig::setEqualizerMode( 0 );
0217 
0218     eqUpdate();
0219     Q_EMIT presetApplied( index );
0220 }
0221 
0222 void
0223 EqualizerController::applyEqualizerPresetByName( const QString &name )
0224 {
0225     DEBUG_BLOCK
0226     const int index = EqualizerPresets::eqGlobalTranslatedList().indexOf( name );
0227     applyEqualizerPresetByIndex( index > 0 ? index : 0 );
0228 }
0229 
0230 void
0231 EqualizerController::savePreset( const QString &name, const QList<int> &gains )
0232 {
0233     EqualizerPresets::eqCfgSetPresetVal( name, gains );
0234     Q_EMIT presetsChanged( name );
0235 }
0236 
0237 bool
0238 EqualizerController::deletePreset( const QString &name )
0239 {
0240     if( !EqualizerPresets::eqCfgDeletePreset( name ) )
0241         return false;
0242 
0243     Q_EMIT presetsChanged( name );
0244     return true;
0245 }
0246 
0247 void
0248 EqualizerController::setGains( const QList<int> &gains )
0249 {
0250     AmarokConfig::setEqualizerGains( gains );
0251     eqUpdate();
0252 }
0253 
0254 QList<int>
0255 EqualizerController::gains() const
0256 {
0257     return AmarokConfig::equalizerGains();
0258 }
0259 
0260 bool
0261 EqualizerController::enabled()
0262 {
0263     return AmarokConfig::equalizerMode() > 0;
0264 }