1 /***************************************************************************
2 * Copyright (C) 2008-2009 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
21 #include "visualizer.h"
23 #ifdef ENABLE_VISUALIZER
33 using Global::myScreen
;
34 using Global::MainStartY
;
35 using Global::MainHeight
;
37 Visualizer
*myVisualizer
= new Visualizer
;
39 const unsigned Visualizer::Samples
= 2048;
41 const unsigned Visualizer::FFTResults
= Samples
/2+1;
42 #endif // HAVE_FFTW3_H
44 void Visualizer::Init()
46 w
= new Window(0, MainStartY
, COLS
, MainHeight
, "", Config
.main_color
, brNone
);
47 w
->SetTimeout(Config
.visualizer_fifo_path
.empty() ? ncmpcpp_window_timeout
: 40 /* this gives us 25 fps */);
51 itsFreqsMagnitude
= new unsigned[FFTResults
];
52 itsInput
= static_cast<double *>(fftw_malloc(sizeof(double)*Samples
));
53 itsOutput
= static_cast<fftw_complex
*>(fftw_malloc(sizeof(fftw_complex
)*FFTResults
));
54 itsPlan
= fftw_plan_dft_r2c_1d(Samples
, itsInput
, itsOutput
, FFTW_ESTIMATE
);
55 # endif // HAVE_FFTW3_H
60 void Visualizer::SwitchTo()
76 Global::RedrawHeader
= 1;
79 void Visualizer::Resize()
81 w
->Resize(COLS
, MainHeight
);
82 w
->MoveTo(0, MainStartY
);
86 std::basic_string
<my_char_t
> Visualizer::Title()
88 return U("Music visualizer");
91 void Visualizer::Update()
96 // if mpd is stopped, clear the screen
103 // it supports only PCM in format 44100:16:1
104 static int16_t buf
[Samples
];
105 ssize_t data
= read(itsFifo
, buf
, sizeof(buf
));
106 if (data
< 0) // no data available in fifo
111 Config
.visualizer_use_wave
? DrawSoundWave(buf
, data
) : DrawFrequencySpectrum(buf
, data
);
113 DrawSoundWave(buf
, data
);
114 # endif // HAVE_FFTW3_H
118 void Visualizer::SpacePressed()
121 Config
.visualizer_use_wave
= !Config
.visualizer_use_wave
;
122 ShowMessage("Visualization type: %s", Config
.visualizer_use_wave
? "Sound wave" : "Frequency spectrum");
123 # endif // HAVE_FFTW3_H
126 void Visualizer::DrawSoundWave(int16_t *buf
, ssize_t data
)
128 const int samples_per_col
= data
/sizeof(int16_t)/COLS
;
129 const int half_height
= MainHeight
/2;
131 double prev_point_pos
= 0;
132 for (int i
= 0; i
< COLS
; ++i
)
134 double point_pos
= 0;
135 for (int j
= 0; j
< samples_per_col
; ++j
)
136 point_pos
+= buf
[i
*samples_per_col
+j
];
137 point_pos
/= samples_per_col
;
138 point_pos
/= std::numeric_limits
<int16_t>::max();
139 point_pos
*= half_height
;
140 *w
<< XY(i
, half_height
+point_pos
) << '`';
141 if (i
&& abs(prev_point_pos
-point_pos
) > 2)
143 // if gap is too big. intermediate values are needed
144 // since without them all we see are blinking points
145 const int breakpoint
= std::max(prev_point_pos
, point_pos
);
146 const int half
= (prev_point_pos
+point_pos
)/2;
147 for (int k
= std::min(prev_point_pos
, point_pos
)+1; k
< breakpoint
; k
+= 2)
148 *w
<< XY(i
-(k
< half
), half_height
+k
) << '`';
150 prev_point_pos
= point_pos
;
152 *w
<< fmtAltCharsetEnd
;
156 void Visualizer::DrawFrequencySpectrum(int16_t *buf
, ssize_t data
)
159 std::fill(buf
+data
/sizeof(int16_t), buf
+Samples
, 0);
160 for (unsigned i
= 0; i
< Samples
; ++i
)
161 itsInput
[i
] = buf
[i
];
163 fftw_execute(itsPlan
);
165 // count magnitude of each frequency and scale it to fit the screen
166 for (unsigned i
= 0; i
< FFTResults
; ++i
)
167 itsFreqsMagnitude
[i
] = sqrt(itsOutput
[i
][0]*itsOutput
[i
][0] + itsOutput
[i
][1]*itsOutput
[i
][1])/1e5
*LINES
/5;
169 const int freqs_per_col
= FFTResults
/COLS
/* cut bandwidth a little to achieve better look */ * 4/5;
170 for (int i
= 0; i
< COLS
; ++i
)
172 size_t bar_height
= 0;
173 for (int j
= 0; j
< freqs_per_col
; ++j
)
174 bar_height
+= itsFreqsMagnitude
[i
*freqs_per_col
+j
];
175 bar_height
= std::min(bar_height
/freqs_per_col
, MainHeight
);
176 mvwvline(w
->Raw(), MainHeight
-bar_height
, i
, 0, bar_height
);
179 #endif // HAVE_FFTW3_H
181 void Visualizer::SetFD()
183 if (itsFifo
< 0 && (itsFifo
= open(Config
.visualizer_fifo_path
.c_str(), O_RDONLY
| O_NONBLOCK
)) < 0)
184 ShowMessage("Couldn't open \"%s\" for reading PCM data: %s", Config
.visualizer_fifo_path
.c_str(), strerror(errno
));
187 void Visualizer::ResetFD()
192 #endif // ENABLE_VISUALIZER