1
/***************************************************************************
2
 *   Copyright (c) 1998-2000 Peter Alm, Mikael Alm, Olle Hallnas           *
3
 *                 Thomas Nilsson and 4Front Technologies                  *
4
 *             (c) 2004 Mark Kretschmann <markey@web.de>                   *
5
 *             (c) 2005 Markus Brueffer <markus@brueffer.de>               *
6
 *                                                                         *
7
 *   This program is free software; you can redistribute it and/or modify  *
8
 *   it under the terms of the GNU General Public License as published by  *
9
 *   the Free Software Foundation; either version 2 of the License, or     *
10
 *   (at your option) any later version.                                   *
11
 *                                                                         *
12
 *   This program is distributed in the hope that it will be useful,       *
13
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15
 *   GNU General Public License for more details.                          *
16
 *                                                                         *
17
 *   You should have received a copy of the GNU General Public License     *
18
 *   along with this program; if not, write to the                         *
19
 *   Free Software Foundation, Inc.,                                       *
20
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
21
 ***************************************************************************/
22
23
/***************************************************************************
24
  Graphical spline display for equalizer
25
  Based on code from XMMS
26
***************************************************************************/
27
28
#include "equalizergraph.h"
29
30
#include "amarokconfig.h"
31
32
#include <QPainter>
33
#include <QPixmap>
34
#include <QVector>
35
36
37
EqualizerGraph::EqualizerGraph( QWidget* parent )
38
    : QWidget( parent, Qt::WNoAutoErase )
39
    , m_backgroundPixmap( new QPixmap() )
40
{}
41
42
43
EqualizerGraph::~EqualizerGraph()
44
{
45
    delete m_backgroundPixmap;
46
}
47
48
49
/////////////////////////////////////////////////////////////////////////////////////
50
// PROTECTED
51
/////////////////////////////////////////////////////////////////////////////////////
52
53
void
54
EqualizerGraph::resizeEvent( QResizeEvent* )
55
{
56
    drawBackground();
57
}
58
59
QSize
60
EqualizerGraph::sizeHint() const
61
{
62
   return QSize( 100, 60 );
63
}
64
65
void
66
EqualizerGraph::paintEvent( QPaintEvent* )
67
{
68
    QPainter p( this );
69
    p.drawPixmap( 0, 0, *m_backgroundPixmap );
70
71
    // Draw middle line
72
    int middleLineY = (int) ( ( height() - 1 ) / 2.0 + AmarokConfig::equalizerPreamp() * ( height() - 1 ) / 200.0 );
73
    QPen pen( colorGroup().dark(), 0, Qt::DotLine);
74
    p.setPen( pen );
75
    p.drawLine( 8, middleLineY, width() - 1, middleLineY );
76
77
    QColor color( colorGroup().highlight() );
78
    int h, s, v;
79
    color.getHsv( &h, &s, &v );
80
81
    int i, y, ymin, ymax, py = 0;
82
    float x[NUM_BANDS], yf[NUM_BANDS];
83
    float gains[NUM_BANDS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0};
84
85
    // Don't calculate 0 and NUM_BANDS-1 for accuracy reasons
86
    for ( i = 1; i < NUM_BANDS -1 ; i++)
87
        x[i] = ( width() - 8 ) * i / ( NUM_BANDS -1 ) + 8;
88
    x[ 0 ] = 8;
89
    x[ NUM_BANDS - 1 ] = width() - 1;
90
91
    if ( AmarokConfig::equalizerEnabled() )
92
        for ( i = 0; i < NUM_BANDS; i++ )
93
            gains[i] = ( height() - 1 ) * AmarokConfig::equalizerGains()[i] / 200.0;
94
95
    init_spline( x, gains, NUM_BANDS, yf );
96
97
    for ( i = 8; i < width(); ++i ) {
98
        y = (int) ( ( height() - 1 ) / 2 - eval_spline( x, gains, yf, NUM_BANDS, i ) );
99
100
        if ( y < 0 )
101
            y = 0;
102
103
        if ( y > height() - 1 )
104
            y = height() - 1;
105
106
        if ( i == 8 )
107
            py = y;
108
109
        if ( y < py ) {
110
            ymin = y;
111
            ymax = py;
112
        } else {
113
            ymin = py;
114
            ymax = y;
115
        }
116
117
        py = y;
118
        for ( y = ymin; y <= ymax; ++y ) {
119
            // Absolute carthesian coordinate
120
            s = y - ( height() - 1 ) / 2;
121
            s = QABS(s);
122
123
            // Normalise to a base of 256
124
            // short for: s / ( ( height() / 2.0 ) * 255;
125
            s = (int) ( s * 510.0 / height() );
126
127
            color.setHsv( h, 255 - s, v );
128
            p.setPen( color );
129
130
            p.drawPoint( i, y );
131
        }
132
    }
133
}
134
135
136
/////////////////////////////////////////////////////////////////////////////////////
137
// PRIVATE
138
/////////////////////////////////////////////////////////////////////////////////////
139
140
void
141
EqualizerGraph::drawBackground()
142
{
143
    m_backgroundPixmap->resize( size() );
144
145
    m_backgroundPixmap->fill( colorGroup().background().dark( 105 ) );
146
    QPainter p( m_backgroundPixmap );
147
148
    // Erase background for scale
149
    p.fillRect( 0, 0, 7, height() -1, colorGroup().background());
150
151
    // Draw scale
152
    p.setPen( colorGroup().shadow() );
153
    p.drawLine( 7, 0, 7, height() - 1 );
154
    p.drawLine( 0, 0, 7, 0 );
155
    p.drawLine( 0, height() / 2 - 1, 7, height() / 2 - 1 );
156
    p.drawLine( 0, height() - 1, 7, height() - 1 );
157
}
158
159
160
void
161
EqualizerGraph::init_spline( float* x, float* y, int n, float* y2 )
162
{
163
    int i, k;
164
    float p, qn, sig, un;
165
    QVector<float> u(n * sizeof(float));
166
167
    y2[ 0 ] = u[ 0 ] = 0.0;
168
169
    for ( i = 1; i < n - 1; ++i ) {
170
        sig = ( (float)x[i] - x[i-1] ) / ( (float)x[i+1] - x[i-1] );
171
        p = sig * y2[i-1] + 2.0;
172
        y2[i] = ( sig - 1.0 ) / p;
173
        u[i] = ( ( (float)y[i+1] - y[i] ) / ( x[i+1] - x[i] ) ) - ( ( (float)y[i] - y[i-1] ) / ( x[i] - x[i-1] ) );
174
        u[i] = ( 6.0 * u[i] / ( x[i+1] - x[i-1] ) - sig * u[i-1] ) / p;
175
    }
176
    qn = un = 0.0;
177
178
    y2[n-1] = ( un - qn * u[n-2] ) / ( qn * y2[n-2] + 1.0 );
179
    for ( k = n - 2; k >= 0; --k )
180
        y2[k] = y2[k] * y2[k+1] + u[k];
181
}
182
183
184
float
185
EqualizerGraph::eval_spline( float xa[], float ya[], float y2a[], int n, float x )
186
{
187
    int klo, khi, k;
188
    float h, b, a;
189
190
    klo = 0;
191
    khi = n - 1;
192
    while ( khi - klo > 1 ) {
193
        k = ( khi + klo ) >> 1;
194
        if ( xa[k] > x )
195
            khi = k;
196
        else
197
            klo = k;
198
    }
199
    h = xa[khi] - xa[klo];
200
    a = ( xa[khi] - x ) / h;
201
    b = ( x - xa[klo] ) / h;
202
    return ( a * ya[klo] + b * ya[khi] + ( ( a*a*a - a ) * y2a[klo] + ( b*b*b - b ) * y2a[khi] ) * ( h*h ) / 6.0 );
203
}