File indexing completed on 2025-01-05 04:25:41

0001 /****************************************************************************************
0002  * Copyright (c) 2004 Enrico Ros <eros.kde@email.it>                                    *
0003  *                                                                                      *
0004  * This program is free software; you can redistribute it and/or modify it under        *
0005  * the terms of the GNU General Public License as published by the Free Software        *
0006  * Foundation; either version 2 of the License, or (at your option) any later           *
0007  * version.                                                                             *
0008  *                                                                                      *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY      *
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A      *
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.             *
0012  *                                                                                      *
0013  * You should have received a copy of the GNU General Public License along with         *
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.                           *
0015  ****************************************************************************************/
0016 
0017 #include "DiscoAnalyzer.h"
0018 
0019 #include <QImage>
0020 #include <QStandardPaths>
0021 
0022 #include <cmath>
0023 #include <cstdlib>
0024 #include <sys/time.h>
0025 
0026 
0027 DiscoAnalyzer::DiscoAnalyzer( QWidget *parent ):
0028     Analyzer::Base( parent )
0029 {
0030     setObjectName( "Disco" );
0031 
0032     m_dotTexture = bindTexture( QImage( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/dot.png" ) ) );
0033     m_w1Texture = bindTexture( QImage( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/wirl1.png" ) ) );
0034     m_w2Texture = bindTexture( QImage( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/wirl2.png" ) ) );
0035 
0036     m_show.paused = true;
0037     m_show.pauseTimer = 0.0;
0038     m_show.rotDegrees = 0.0;
0039     m_frame.rotDegrees = 0.0;
0040 }
0041 
0042 DiscoAnalyzer::~DiscoAnalyzer()
0043 {
0044     deleteTexture( m_dotTexture );
0045     deleteTexture( m_w1Texture );
0046     deleteTexture( m_w2Texture );
0047 }
0048 
0049 void DiscoAnalyzer::demo()
0050 {
0051     static int t = 0;
0052     static bool forward = true;
0053 
0054     QVector<float> s( 200 );
0055     const double dt = double( t ) / 200;
0056 
0057     for( int i = 0; i < s.size(); ++i )
0058         s[i] = dt * ( sin( M_PI + ( i * M_PI ) / s.size() ) + 1.0 );
0059 
0060     analyze( s );
0061 
0062     if( t == 0 )
0063         forward = true;
0064     if( t == 200 )
0065         forward = false;
0066 
0067     t = forward ? t + 2 : t - 2;
0068 }
0069 
0070 void DiscoAnalyzer::initializeGL()
0071 {
0072     // Set a smooth shade model
0073     glShadeModel( GL_SMOOTH );
0074 
0075     // Disable depth test (all is drawn on a 2d plane)
0076     glDisable( GL_DEPTH_TEST );
0077 
0078     // Set blend parameters for 'composting alpha'
0079     glBlendFunc( GL_SRC_ALPHA, GL_ONE );                        //superpose
0080     //glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );        //fade
0081     glEnable( GL_BLEND );
0082 
0083     // Clear frame with a black background
0084     glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
0085     glClear( GL_COLOR_BUFFER_BIT );
0086 }
0087 
0088 void DiscoAnalyzer::resizeGL( int w, int h )
0089 {
0090     // Setup screen. We're going to manually do the perspective projection
0091     glViewport( 0, 0, ( GLint )w, ( GLint )h );
0092     glMatrixMode( GL_PROJECTION );
0093     glLoadIdentity();
0094     glOrtho( -10.0f, 10.0f, -10.0f, 10.0f, -5.0f, 5.0f );
0095 
0096     // Get the aspect ratio of the screen to draw 'cicular' particles
0097     const float ratio = ( float )w / ( float )h,
0098           eqPixH = 60,
0099           eqPixW = 80;
0100     if( ratio >= ( 4.0 / 3.0 ) )
0101     {
0102         m_unitX = 10.0 / ( eqPixH * ratio );
0103         m_unitY = 10.0 / eqPixH;
0104     }
0105     else
0106     {
0107         m_unitX = 10.0 / eqPixW;
0108         m_unitY = 10.0 / ( eqPixW / ratio );
0109     }
0110 
0111     // Get current timestamp.
0112     timeval tv;
0113     gettimeofday( &tv, NULL );
0114     m_show.timeStamp = ( double )tv.tv_sec + ( double )tv.tv_usec / 1000000.0;
0115 }
0116 
0117 void DiscoAnalyzer::analyze( const QVector<float> &s )
0118 {
0119     bool haveNoData = s.empty();
0120 
0121     // if we're going into pause mode, clear timers.
0122     if( !m_show.paused && haveNoData )
0123         m_show.pauseTimer = 0.0;
0124 
0125     // if we have got data, interpolate it (asking myself why I'm doing it here..)
0126     if( !( m_show.paused = haveNoData ) )
0127     {
0128         int bands = s.size(),
0129             lowbands = bands / 4,
0130             hibands = bands / 3,
0131             midbands = bands - lowbands - hibands; Q_UNUSED( midbands );
0132         float currentEnergy = 0,
0133               currentMeanBand = 0,
0134               maxValue = 0;
0135         for( int i = 0; i < bands; i++ )
0136         {
0137             float value = s[i];
0138             currentEnergy += value;
0139             currentMeanBand += ( float )i * value;
0140             if( value > maxValue )
0141                 maxValue = value;
0142         }
0143         m_frame.silence = currentEnergy < 0.001;
0144         if( !m_frame.silence )
0145         {
0146             m_frame.meanBand = 100.0 * currentMeanBand / ( currentEnergy * bands );
0147             currentEnergy = 100.0 * currentEnergy / ( float )bands;
0148             m_frame.dEnergy = currentEnergy - m_frame.energy;
0149             m_frame.energy = currentEnergy;
0150 //            printf( "%d  [%f :: %f ]\t%f \n", bands, frame.energy, frame.meanBand, maxValue         );
0151         }
0152         else
0153             m_frame.energy = 0.0;
0154     }
0155 }
0156 
0157 void DiscoAnalyzer::paintGL()
0158 {
0159 
0160 }
0161 
0162 void DiscoAnalyzer::drawDot( float x, float y, float size )
0163 {
0164     float sizeX = size * m_unitX,
0165           sizeY = size * m_unitY,
0166           pLeft = x - sizeX,
0167           pTop = y + sizeY,
0168           pRight = x + sizeX,
0169           pBottom = y - sizeY;
0170     glTexCoord2f( 0, 0 );        // Bottom Left
0171     glVertex2f( pLeft, pBottom );
0172     glTexCoord2f( 0, 1 );        // Top Left
0173     glVertex2f( pLeft, pTop );
0174     glTexCoord2f( 1, 1 );        // Top Right
0175     glVertex2f( pRight, pTop );
0176     glTexCoord2f( 1, 0 );        // Bottom Right
0177     glVertex2f( pRight, pBottom );
0178 }
0179 
0180 void DiscoAnalyzer::drawFullDot( float r, float g, float b, float a )
0181 {
0182     glBindTexture( GL_TEXTURE_2D, m_dotTexture );
0183     glEnable( GL_TEXTURE_2D );
0184     glColor4f( r, g, b, a );
0185     glBegin( GL_TRIANGLE_STRIP );
0186     glTexCoord2f( 1.0, 1.0 );
0187     glVertex2f( 10.0f, 10.0f );
0188     glTexCoord2f( 0.0, 1.0 );
0189     glVertex2f( -10.0f, 10.0f );
0190     glTexCoord2f( 1.0, 0.0 );
0191     glVertex2f( 10.0f, -10.0f );
0192     glTexCoord2f( 0.0 , 0.0 );
0193     glVertex2f( -10.0f, -10.0f );
0194     glEnd();
0195     glDisable( GL_TEXTURE_2D );
0196 }
0197 
0198 
0199 void DiscoAnalyzer::setTextureMatrix( float rot, float scale )
0200 {
0201     glMatrixMode( GL_TEXTURE );
0202     glLoadIdentity();
0203     if( rot != 0.0 || scale != 0.0 )
0204     {
0205         glTranslatef( 0.5f, 0.5f, 0.0f );
0206         glRotatef( rot, 0.0f, 0.0f, 1.0f );
0207         glScalef( scale, scale, 1.0f );
0208         glTranslatef( -0.5f, -0.5f, 0.0f );
0209     }
0210     glMatrixMode( GL_MODELVIEW );
0211 }
0212