@ -37,23 +37,20 @@ using Global::MainHeight;
Visualizer * myVisualizer = new Visualizer ;
const unsigned Visualizer : : Samples = 2048 ;
# ifdef HAVE_FFTW3_H
const unsigned Visualizer : : FFTResults = Samples / 2 + 1 ;
# endif // HAVE_FFTW3_H
int Visualizer : : WindowTimeout = 1000 / 25 ; /* 25 fps */
const int Visualizer : : WindowTimeout = 1000 / 25 ; /* 25 fps */
void Visualizer : : Init ( )
{
w = new Window ( 0 , MainStartY , COLS , MainHeight , " " , Config . visualizer_color , brNone ) ;
ResetFD ( ) ;
itsSamples = Config . visualizer_in_stereo ? 4096 : 2048 ;
# ifdef HAVE_FFTW3_H
itsFreqsMagnitude = new unsigned [ FFTResults ] ;
itsInput = static_cast < double * > ( fftw_malloc ( sizeof ( double ) * Samples ) ) ;
itsOutput = static_cast < fftw_complex * > ( fftw_malloc ( sizeof ( fftw_complex ) * FFTResults ) ) ;
itsPlan = fftw_plan_dft_r2c_1d ( Samples , itsInput , itsOutput , FFTW_ESTIMATE ) ;
itsFFTResults = itsSamples / 2 + 1 ;
itsFreqsMagnitude = new unsigned [ itsFFTResults ] ;
itsInput = static_cast < double * > ( fftw_malloc ( sizeof ( double ) * itsSamples ) ) ;
itsOutput = static_cast < fftw_complex * > ( fftw_malloc ( sizeof ( fftw_complex ) * itsFFTResults ) ) ;
itsPlan = fftw_plan_dft_r2c_1d ( itsSamples , itsInput , itsOutput , FFTW_ESTIMATE ) ;
# endif // HAVE_FFTW3_H
FindOutputID ( ) ;
@ -106,8 +103,8 @@ void Visualizer::Update()
if ( itsFifo < 0 )
return ;
// it supports only PCM in format 44100:16:1
static int16_t buf [ Samples ] ;
// PCM in format 44100:16:1 (for mono visualization) and 44100:16:2 (for stereo visualization) is supported
int16_t buf [ its Samples] ;
ssize_t data = read ( itsFifo , buf , sizeof ( buf ) ) ;
if ( data < 0 ) // no data available in fifo
return ;
@ -120,12 +117,30 @@ void Visualizer::Update()
gettimeofday ( & itsTimer , 0 ) ;
}
w - > Clear ( ) ;
void ( Visualizer : : * draw ) ( int16_t * , ssize_t , size_t , size_t ) ;
# ifdef HAVE_FFTW3_H
Config . visualizer_use_wave ? DrawSoundWave ( buf , data ) : DrawFrequencySpectrum ( buf , data ) ;
# else
DrawSoundWave ( buf , data ) ;
if ( ! Config . visualizer_use_wave )
draw = & Visualizer : : DrawFrequencySpectrum ;
else
# endif // HAVE_FFTW3_H
draw = & Visualizer : : DrawSoundWave ;
w - > Clear ( ) ;
if ( Config . visualizer_in_stereo )
{
ssize_t bytes_read = data / sizeof ( int16_t ) ;
int16_t buf_left [ bytes_read / 2 ] , buf_right [ bytes_read / 2 ] ;
for ( ssize_t i = 0 , j = 0 ; i < bytes_read ; i + = 2 , + + j )
{
buf_left [ j ] = buf [ i ] ;
buf_right [ j ] = buf [ i + 1 ] ;
}
size_t half_height = MainHeight / 2 ;
( this - > * draw ) ( buf_left , data / 2 , 0 , half_height ) ;
( this - > * draw ) ( buf_right , data / 2 , half_height + ( draw = = & Visualizer : : DrawSoundWave ? 1 : 0 ) , half_height + ( draw ! = & Visualizer : : DrawSoundWave ? 1 : 0 ) ) ;
}
else
( this - > * draw ) ( buf , data , 0 , MainHeight ) ;
w - > Refresh ( ) ;
}
@ -137,10 +152,10 @@ void Visualizer::SpacePressed()
# endif // HAVE_FFTW3_H
}
void Visualizer : : DrawSoundWave ( int16_t * buf , ssize_t data )
void Visualizer : : DrawSoundWave ( int16_t * buf , ssize_t data , size_t y_offset , size_t height )
{
const int samples_per_col = data / sizeof ( int16_t ) / COLS ;
const int half_height = MainH eight/ 2 ;
const int half_height = h eight/ 2 ;
* w < < fmtAltCharset ;
double prev_point_pos = 0 ;
for ( int i = 0 ; i < COLS ; + + i )
@ -151,7 +166,7 @@ void Visualizer::DrawSoundWave(int16_t *buf, ssize_t data)
point_pos / = samples_per_col ;
point_pos / = std : : numeric_limits < int16_t > : : max ( ) ;
point_pos * = half_height ;
* w < < XY ( i , half_height + point_pos ) < < ' ` ' ;
* w < < XY ( i , y_offset + half_height + point_pos ) < < ' ` ' ;
if ( i & & abs ( prev_point_pos - point_pos ) > 2 )
{
// if gap is too big. intermediate values are needed
@ -159,7 +174,7 @@ void Visualizer::DrawSoundWave(int16_t *buf, ssize_t data)
const int breakpoint = std : : max ( prev_point_pos , point_pos ) ;
const int half = ( prev_point_pos + point_pos ) / 2 ;
for ( int k = std : : min ( prev_point_pos , point_pos ) + 1 ; k < breakpoint ; k + = 2 )
* w < < XY ( i - ( k < half ) , half_height + k ) < < ' ` ' ;
* w < < XY ( i - ( k < half ) , y_offset + half_height + k ) < < ' ` ' ;
}
prev_point_pos = point_pos ;
}
@ -167,27 +182,27 @@ void Visualizer::DrawSoundWave(int16_t *buf, ssize_t data)
}
# ifdef HAVE_FFTW3_H
void Visualizer : : DrawFrequencySpectrum ( int16_t * buf , ssize_t data )
void Visualizer : : DrawFrequencySpectrum ( int16_t * buf , ssize_t data , size_t y_offset , size_t height )
{
// zero old values
std : : fill ( buf + data / sizeof ( int16_t ) , buf + Samples , 0 ) ;
for ( unsigned i = 0 ; i < Samples ; + + i )
std : : fill ( buf + data / sizeof ( int16_t ) , buf + data / 2 , 0 ) ;
for ( unsigned i = 0 ; i < data / 2 ; + + i )
itsInput [ i ] = buf [ i ] ;
fftw_execute ( itsPlan ) ;
// count magnitude of each frequency and scale it to fit the screen
for ( unsigned i = 0 ; i < FFTResults ; + + i )
itsFreqsMagnitude [ i ] = sqrt ( itsOutput [ i ] [ 0 ] * itsOutput [ i ] [ 0 ] + itsOutput [ i ] [ 1 ] * itsOutput [ i ] [ 1 ] ) / 1e5 * LINES / 5 ;
for ( unsigned i = 0 ; i < its FFTResults; + + i )
itsFreqsMagnitude [ i ] = sqrt ( itsOutput [ i ] [ 0 ] * itsOutput [ i ] [ 0 ] + itsOutput [ i ] [ 1 ] * itsOutput [ i ] [ 1 ] ) / 1e5 * height / 5 ;
const int freqs_per_col = FFTResults / COLS /* cut bandwidth a little to achieve better look */ * 4 / 5 ;
const int freqs_per_col = its FFTResults/ COLS /* cut bandwidth a little to achieve better look */ * 4 / 5 ;
for ( int i = 0 ; i < COLS ; + + i )
{
size_t bar_height = 0 ;
for ( int j = 0 ; j < freqs_per_col ; + + j )
bar_height + = itsFreqsMagnitude [ i * freqs_per_col + j ] ;
bar_height = std : : min ( bar_height / freqs_per_col , MainH eight) ;
mvwvline ( w - > Raw ( ) , MainH eight- bar_height , i , 0 , bar_height ) ;
bar_height = std : : min ( bar_height / freqs_per_col , h eight) ;
mvwvline ( w - > Raw ( ) , y_offset > 0 ? y_offset : h eight- bar_height , i , 0 , bar_height ) ;
}
}
# endif // HAVE_FFTW3_H