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 + -
显示快捷键?