-
Notifications
You must be signed in to change notification settings - Fork 341
/
visualize.h
314 lines (247 loc) · 7.64 KB
/
visualize.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
/*
visualize.h
(c) 2003 Thor Sigvaldason and Isaac Richards
Closely based on code from mq3 by Brad Hughes
Part of the mythTV project
music visualizers
*/
#ifndef VISUALIZE_H
#define VISUALIZE_H
// C++ headers
#include <QVector>
#include <vector>
// MythTV headers
#include <visual.h>
#include <musicmetadata.h>
#include <mythbaseexp.h>
// MythMusic headers
#include "constants.h"
#include "config.h"
#include <complex>
extern "C" {
#ifdef FFTW3_SUPPORT
#include <fftw3.h>
#define myth_fftw_float double /* need to use different plan function to change */
#define fftw_real myth_fftw_float
#define myth_fftw_complex std::complex<myth_fftw_float>
#if (myth_fftw_float == double)
#define myth_fftw_complex_cast fftw_complex
#elif (myth_fftw_float == float)
#define myth_fftw_complex_cast fftwf_complex
#endif
#endif
}
#define SAMPLES_DEFAULT_SIZE 512
class MainVisual;
class VisualNode
{
public:
VisualNode(short *l, short *r, unsigned long n, unsigned long o)
: left(l), right(r), length(n), offset(o)
{
// left and right are allocated and then passed to this class
// the code that allocated left and right should give up all ownership
}
~VisualNode()
{
delete [] left;
delete [] right;
}
short *left, *right;
unsigned long length, offset;
};
class VisualBase
{
public:
VisualBase(bool screensaverenable = false);
virtual ~VisualBase(void);
// return true if the output should stop
virtual bool process( VisualNode *node ) = 0;
// this is called on nodes that will not be displayed :: Not needed for most visualizations
// (i.e. between the displayed frames, if you need the whole audio stream)
virtual bool processUndisplayed( VisualNode * )
{
return true; // By default this does nothing : Ignore the in-between chunks of audio data
};
virtual bool draw( QPainter *, const QColor & ) = 0;
virtual void resize( const QSize &size ) = 0;
virtual void handleKeyPress(const QString &action) = 0;
virtual int getDesiredFPS(void) { return m_fps; }
// Override this if you need the potential of capturing more data than the default
virtual unsigned long getDesiredSamples(void) { return SAMPLES_DEFAULT_SIZE; }
void drawWarning(QPainter *p, const QColor &back, const QSize &color, QString warning, int fontsize = 28);
protected:
int m_fps;
bool m_xscreensaverenable;
};
class VisFactory
{
public:
VisFactory() {m_pNextVisFactory = g_pVisFactories; g_pVisFactories = this;}
virtual ~VisFactory() {}
const VisFactory* next() const {return m_pNextVisFactory;}
virtual const QString &name(void) const = 0;
virtual VisualBase* create(MainVisual *parent, const QString &pluginName) const = 0;
virtual uint plugins(QStringList *list) const = 0;
static const VisFactory* VisFactories() {return g_pVisFactories;}
protected:
static VisFactory* g_pVisFactories;
VisFactory* m_pNextVisFactory;
};
class StereoScope : public VisualBase
{
public:
StereoScope();
virtual ~StereoScope();
void resize( const QSize &size );
bool process( VisualNode *node );
bool draw( QPainter *p, const QColor &back );
void handleKeyPress(const QString &action) {(void) action;}
protected:
QColor startColor, targetColor;
vector<double> magnitudes;
QSize size;
bool const rubberband;
double const falloff;
};
class MonoScope : public StereoScope
{
public:
MonoScope();
virtual ~MonoScope();
bool process( VisualNode *node );
bool draw( QPainter *p, const QColor &back );
};
class LogScale
{
public:
LogScale(int = 0, int = 0);
~LogScale();
int scale() const { return s; }
int range() const { return r; }
void setMax(int, int);
int operator[](int);
private:
int *indices;
int s, r;
};
#ifdef FFTW3_SUPPORT
class Spectrum : public VisualBase
{
// This class draws bars (up and down)
// based on the magnitudes at various
// frequencies in the audio data.
public:
Spectrum();
virtual ~Spectrum();
virtual void resize(const QSize &size);
bool process(VisualNode *node);
virtual bool draw(QPainter *p, const QColor &back = Qt::black);
void handleKeyPress(const QString &action) {(void) action;}
protected:
inline double clamp(double cur, double max, double min);
QColor startColor, targetColor;
QVector<QRect> rects;
QVector<double> magnitudes;
QSize size;
LogScale scale;
double scaleFactor, falloff;
int analyzerBarWidth;
fftw_plan lplan, rplan;
myth_fftw_float *lin, *rin;
myth_fftw_complex *lout, *rout;
};
class Squares : public Spectrum
{
public:
Squares();
virtual ~Squares();
void resize (const QSize &newsize);
bool draw(QPainter *p, const QColor &back = Qt::black);
void handleKeyPress(const QString &action) {(void) action;}
private:
void drawRect(QPainter *p, QRect *rect, int i, int c, int w, int h);
QSize size;
MainVisual *pParent;
int fake_height;
int number_of_squares;
};
#endif // FFTW3_SUPPORT
class Piano : public VisualBase
{
// This class draws bars (up and down)
// based on the magnitudes at piano pitch
// frequencies in the audio data.
#define PIANO_AUDIO_SIZE 4096
#define PIANO_N 88
#define piano_audio float
#define goertzel_data float
#define PIANO_RMS_NEGLIGIBLE .001
#define PIANO_SPECTRUM_SMOOTHING 0.95
#define PIANO_MIN_VOL -10
#define PIANO_KEYPRESS_TOO_LIGHT .2
typedef struct piano_key_data {
goertzel_data q1, q2, coeff, magnitude;
goertzel_data max_magnitude_seen;
// This keeps track of the samples processed for each note
// Low notes require a lot of samples to be correctly identified
// Higher ones are displayed quicker
int samples_processed;
int samples_process_before_display_update;
bool is_black_note; // These are painted on top of white notes, and have different colouring
} piano_key_data;
public:
Piano();
virtual ~Piano();
virtual void resize(const QSize &size);
bool process(VisualNode *node);
// These functions are new, since we need to inspect all the data
bool processUndisplayed(VisualNode *node);
unsigned long getDesiredSamples(void);
virtual bool draw(QPainter *p, const QColor &back = Qt::black);
void handleKeyPress(const QString &action) {(void) action;}
protected:
inline double clamp(double cur, double max, double min);
bool process_all_types(VisualNode *node, bool this_will_be_displayed);
void zero_analysis(void);
QColor whiteStartColor, whiteTargetColor, blackStartColor, blackTargetColor;
vector<QRect> rects;
QSize size;
unsigned long offset_processed;
piano_key_data *piano_data;
piano_audio *audio_data;
vector<double> magnitude;
};
class AlbumArt : public VisualBase
{
public:
AlbumArt(void);
virtual ~AlbumArt();
void resize(const QSize &size);
bool process(VisualNode *node = 0);
bool draw(QPainter *p, const QColor &back = Qt::black);
void handleKeyPress(const QString &action);
private:
bool needsUpdate(void);
void findFrontCover(void);
bool cycleImage(void);
QSize m_size, m_cursize;
ImageType m_currImageType;
QImage m_image;
MusicMetadata *m_currentMetadata;
QDateTime m_lastCycle;
};
class Blank : public VisualBase
{
// This draws ... well ... nothing
public:
Blank();
virtual ~Blank();
void resize(const QSize &size);
bool process(VisualNode *node = 0);
bool draw(QPainter *p, const QColor &back = Qt::black);
void handleKeyPress(const QString &action) {(void) action;}
private:
QSize size;
};
#endif // __visualize_h