moodbar.cpp

来自「Amarok是一款在LINUX或其他类UNIX操作系统中运行的音频播放器软件。 」· C++ 代码 · 共 1,387 行 · 第 1/4 页

CPP
1,387
字号
                QColor::Hsv ) );            paint.drawPoint(x, y);            paint.drawPoint(x, height - 1 - y);          }      }    m_mutex.unlock();    return m_pixmap;}#define NUM_HUES 12// Read the .mood file.  Returns true if the read was successful// and changes the state to Loaded; returns false and leaves the// state untouched otherwise.//// This is based on Gav's original code.  We do the mood altering// (AmarokConfig::AlterMood()) here, as well as calculating the// hue-based sort.  All displayed moodbars will be reset() when// the config is changed, so there's no harm in doing it here.//// This method must be called with the instance locked.boolMoodbar::readFile( void ){    if( !AmarokConfig::showMoodbar() )      return false;    if( m_state == Loaded )      return true;    QString path = moodFilename( m_bundle->url() );    if( path.isEmpty() )      return false;    debug() << "Moodbar::readFile: Trying to read " << path << endl;    QFile moodFile( path );    if( !QFile::exists( path )  ||        !moodFile.open( IO_ReadOnly ) )      {        // If the user has changed his/her preference about where to        // store the mood files, he/she might have the .mood file        // in the other place, so we should check there before giving        // up.        QString path2 = moodFilename( m_bundle->url(),                                      !AmarokConfig::moodsWithMusic() );        moodFile.setName( path2 );        if( !QFile::exists( path2 )  ||            !moodFile.open( IO_ReadOnly ) )          return false;        debug() << "Moodbar::readFile: Found a file at " << path2                << " instead, using that and copying." << endl;        moodFile.close();        if( !copyFile( path2, path ) )          return false;        moodFile.setName( path );        if( !moodFile.open( IO_ReadOnly ) )          return false;      }    int r, g, b, samples = moodFile.size() / 3;    debug() << "Moodbar::readFile: File " << path            << " opened. Proceeding to read contents... s=" << samples << endl;    // This would be bad.    if( samples == 0 )      {        debug() << "Moodbar::readFile: File " << moodFile.name()                << " is corrupted, removing." << endl;        moodFile.remove();        return false;      }    int huedist[360], mx = 0; // For alterMood    int modalHue[NUM_HUES];   // For m_hueSort    int h, s, v;    memset( modalHue, 0, sizeof( modalHue ) );    memset( huedist, 0, sizeof( huedist ) );    // Read the file, keeping track of some histograms    for( int i = 0; i < samples; i++ )      {        r = moodFile.getch();        g = moodFile.getch();        b = moodFile.getch();        m_data.push_back( QColor( CLAMP( 0, r, 255 ),                                  CLAMP( 0, g, 255 ),                                  CLAMP( 0, b, 255 ), QColor::Rgb ) );        // Make a histogram of hues        m_data.last().getHsv( &h, &s, &v );        modalHue[CLAMP( 0, h * NUM_HUES / 360, NUM_HUES - 1 )] += v;        if( h < 0 ) h = 0;  else h = h % 360;        huedist[h]++;      }    // Make moodier -- copied straight from Gav Wood's code    // Here's an explanation of the algorithm:    //    // The "input" hue for each bar is mapped to a hue between    // rangeStart and (rangeStart + rangeDelta).  The mapping is    // determined by the hue histogram, huedist[], which is calculated    // above by putting each sample into one of 360 hue bins.  The    // mapping is such that if your histogram is concentrated on a few    // hues that are close together, then these hues are separated,    // and the space between spikes in the hue histogram is    // compressed.  Here we consider a hue value to be a "spike" in    // the hue histogram if the number of samples in that bin is    // greater than the threshold variable.    //    // As an example, suppose we have 100 samples, and that    //    threshold = 10  rangeStart = 0  rangeDelta = 288    // Suppose that we have 10 samples at each of 99,100,101, and 200.    // Suppose that there are 20 samples < 99, 20 between 102 and 199,    // and 20 above 201, with no spikes.  There will be five hues in    // the output, at hues 0, 72, 144, 216, and 288, containing the    // following number of samples:    //     0:   20 + 10 = 30   (range 0   - 99 )    //     72:            10   (range 100 - 100)    //     144:           10   (range 101 - 101)    //     216: 10 + 20 = 30   (range 102 - 200)    //     288:           20   (range 201 - 359)    // The hues are now much more evenly distributed.    //    // After the hue redistribution is calculated, the saturation and    // value are scaled by sat and val, respectively, which are percentage    // values.    if( AmarokConfig::makeMoodier() )      {        // Explanation of the parameters:        //        //   threshold: A hue value is considered to be a "spike" in the        //     histogram if it's above this value.  Setting this value        //     higher will tend to make the hue distribution more uniform        //        //   rangeStart, rangeDelta: output hues will be more or less        //     evenly spaced between rangeStart and (rangeStart + rangeDelta)        //        //   sat, val: the saturation and value are scaled by these integral        //     percentage values        int threshold, rangeStart, rangeDelta, sat, val;        int total = 0;        memset( modalHue, 0, sizeof( modalHue ) );  // Recalculate this        switch( AmarokConfig::alterMood() )          {          case 1: // Angry            threshold  = samples / 360 * 9;            rangeStart = 45;            rangeDelta = -45;            sat        = 200;            val        = 100;            break;          case 2: // Frozen            threshold  = samples / 360 * 1;            rangeStart = 140;            rangeDelta = 160;            sat        = 50;            val        = 100;            break;          default: // Happy            threshold  = samples / 360 * 2;            rangeStart = 0;            rangeDelta = 359;            sat        = 150;            val        = 250;          }        debug() << "ReadMood: Applying filter t=" << threshold                << ", rS=" << rangeStart << ", rD=" << rangeDelta                << ", s=" << sat << "%, v=" << val << "%" << endl;        // On average, huedist[i] = samples / 360.  This counts the        // number of samples over the threshold, which is usually        // 1, 2, 9, etc. times the average samples in each bin.        // The total determines how many output hues there are,        // evenly spaced between rangeStart and rangeStart + rangeDelta.        for( int i = 0; i < 360; i++ )          if( huedist[i] > threshold )            total++;        if( total < 360 && total > 0 )          {            // Remap the hue values to be between rangeStart and            // rangeStart + rangeDelta.  Every time we see an input hue            // above the threshold, increment the output hue by            // (1/total) * rangeDelta.            for( int i = 0, n = 0; i < 360; i++ )              huedist[i] = ( ( huedist[i] > threshold ? n++ : n )                             * rangeDelta / total + rangeStart ) % 360;            // Now huedist is a hue mapper: huedist[h] is the new hue value            // for a bar with hue h            for(uint i = 0; i < m_data.size(); i++)              {                m_data[i].getHsv( &h, &s, &v );                if( h < 0 ) h = 0;  else h = h % 360;                m_data[i].setHsv( CLAMP( 0, huedist[h], 359 ),                                  CLAMP( 0, s * sat / 100, 255 ),                                  CLAMP( 0, v * val / 100, 255 ) );                modalHue[CLAMP(0, huedist[h] * NUM_HUES / 360, NUM_HUES - 1)]                  += (v * val / 100);              }          }      }    // Calculate m_hueSort.  This is a 3-digit number in base NUM_HUES,    // where the most significant digit is the first strongest hue, the    // second digit is the second strongest hue, and the third digit    // is the third strongest.  This code was written by Gav Wood.    m_hueSort = 0;    mx = 0;    for( int i = 1; i < NUM_HUES; i++ )      if( modalHue[i] > modalHue[mx] )        mx = i;    m_hueSort = mx * NUM_HUES * NUM_HUES;    modalHue[mx] = 0;    mx = 0;    for( int i = 1; i < NUM_HUES; i++ )      if( modalHue[i] > modalHue[mx] )        mx = i;    m_hueSort += mx * NUM_HUES;    modalHue[mx] = 0;    mx = 0;    for( int i = 1; i < NUM_HUES; i++ )      if( modalHue[i] > modalHue[mx] )        mx = i;    m_hueSort += mx;    debug() << "Moodbar::readFile: All done." << endl;    moodFile.close();    m_state = Loaded;    return true;}// Returns where the mood file for this bundle should be located,// based on the user preferences.  If no location can be determined,// return QString::null.QStringMoodbar::moodFilename( const KURL &url ){  return moodFilename( url, AmarokConfig::moodsWithMusic() );}QStringMoodbar::moodFilename( const KURL &url, bool withMusic ){    // No need to lock the object    QString path;    if( withMusic )      {        path = url.path();        path.truncate(path.findRev('.'));        if (path.isEmpty())  // Weird...          return QString();        path += ".mood";        int slash = path.findRev('/') + 1;        QString dir  = path.left(slash);        QString file = path.right(path.length() - slash);        path = dir + '.' + file;      }    else      {        // The moodbar file is {device id},{relative path}.mood}        int deviceid = MountPointManager::instance()->getIdForUrl( url );        KURL relativePath;        MountPointManager::instance()->getRelativePath( deviceid,            url, relativePath );        path = relativePath.path();        path.truncate(path.findRev('.'));        if (path.isEmpty())  // Weird...          return QString();        path = QString::number( deviceid ) + ','          + path.replace('/', ',') + ".mood";        // Creates the path if necessary        path = ::locateLocal( "data", "amarok/moods/" + path );      }    return path;}// Quick-n-dirty -->synchronous<-- file copy (the GUI needs its// moodbars immediately!)boolMoodbar::copyFile( const QString &srcPath, const QString &dstPath ){  QFile file( srcPath );  if( !file.open( IO_ReadOnly ) )    return false;  QByteArray contents = file.readAll();  file.close();  file.setName( dstPath );  if( !file.open( IO_WriteOnly | IO_Truncate ) )    return false;  bool res = ( uint( file.writeBlock( contents ) ) == contents.size() );  file.close();  return res;}// Can we find the moodbar program?boolMoodbar::executableExists( void ){  return !(KStandardDirs::findExe( "moodbar" ).isNull());}#include "moodbar.moc"

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?