1 /*
2 Copyright (C) 2008 Remon Sijrier
3 Copyright (C) 2006 Nicola Doebelin
4
5 This file is part of Traverso
6
7 Traverso 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 Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
21 */
22
23 #include "SpectralMeterWidget.h"
24
25 #include <Config.h>
26 #include <Information.h>
27 #include <PluginChain.h>
28 #include <SpectralMeter.h>
29 #include <Command.h>
30 #include <Project.h>
31 #include <AudioDevice.h>
32 #include <Sheet.h>
33 #include <Themer.h>
34
35 #include <QFileDialog>
36 #include <QInputDialog>
37 #include <QTextStream>
38
39 #include <math.h>
40 #include <limits.h>
41
42 // Always put me below _all_ includes, this is needed
43 // in case we run with memory leak detection enabled!
44 #include "Debugger.h"
45
46 #define SMOOTH_FACTOR 0.98
47 #define DB_FLOOR -140.0
48
49 static const float DEFAULT_VAL = -999.0f;
50 static const uint MAX_SAMPLES = UINT_MAX;
51
52
SpectralMeterWidget(QWidget * parent)53 SpectralMeterWidget::SpectralMeterWidget(QWidget* parent)
54 : MeterWidget(parent, new SpectralMeterView(this))
55 {
56 PENTERCONS;
57 }
58
59
SpectralMeterView(SpectralMeterWidget * widget)60 SpectralMeterView::SpectralMeterView(SpectralMeterWidget* widget)
61 : MeterView(widget)
62 {
63
64 m_config = 0;
65 load_configuration();
66
67 upper_freq_log = log10(upper_freq);
68 lower_freq_log = log10(lower_freq);
69 sample_rate = audiodevice().get_sample_rate();
70 show_average = false;
71 update_average = true;
72 sample_weight = 1;
73
74 QFontMetrics fm(themer()->get_font("FFTMeter:fontscale:label"));
75 margin_l = 5;
76 margin_r = fm.width("-XX") + 5;
77 margin_t = fm.ascent()/2 + 5;
78 margin_b = fm.ascent() + fm.descent() + 10;
79
80
81 for (int i = 0; i < 4; ++i) {
82 m_freq_labels.push_back(10.0f * pow(10.0,i));
83 m_freq_labels.push_back(20.0f * pow(10.0,i));
84 m_freq_labels.push_back(30.0f * pow(10.0,i));
85 m_freq_labels.push_back(40.0f * pow(10.0,i));
86 m_freq_labels.push_back(50.0f * pow(10.0,i));
87 m_freq_labels.push_back(60.0f * pow(10.0,i));
88 m_freq_labels.push_back(70.0f * pow(10.0,i));
89 m_freq_labels.push_back(80.0f * pow(10.0,i));
90 m_freq_labels.push_back(90.0f * pow(10.0,i));
91 }
92 }
93
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)94 void SpectralMeterView::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
95 {
96 Q_UNUSED(option);
97 Q_UNUSED(widget);
98
99 painter->drawPixmap(0, 0, bgPixmap);
100
101 // draw the bars
102 if (m_spectrum.size()) {
103 QRect rect;
104 QBrush brush(themer()->get_color("FFTMeter:foreground"), Qt::SolidPattern);
105 painter->setClipRegion(m_rect);
106 painter->setBrush(brush);
107 painter->setPen(Qt::NoPen);
108
109 int spc = 0;
110 if (num_bands < 64) spc = 1;
111
112 // draw the freq bands
113 for (uint i = 0; i < (uint)m_spectrum.size(); ++i) {
114 if (m_bands.at(i+1) < lower_db) {
115 continue;
116 }
117
118 rect.setTopLeft(QPoint((int)freq2xpos(m_bands.at(i)) + spc, (int)db2ypos(m_spectrum.at(i))));
119 rect.setBottomRight(QPoint((int)freq2xpos(m_bands.at(i+1)) - spc, (int)db2ypos(DB_FLOOR)));
120 painter->drawRect(rect);
121 }
122
123 // draw the average line if requested
124 if (show_average) {
125 painter->setPen(themer()->get_color("FFTMeter:curve:average"));
126 QPoint pt;
127 QPoint po((int)m_map_idx2xpos.at(0), (int)db2ypos(m_avg_db.at(0)));
128 for (uint i = 0; i < (uint)m_avg_db.size(); ++i) {
129 pt.setX((int)m_map_idx2xpos.at(i));
130 pt.setY((int)db2ypos(m_avg_db.at(i)));
131 painter->drawLine(po, pt);
132 po = pt;
133 }
134 }
135 }
136 }
137
resize()138 void SpectralMeterView::resize()
139 {
140 PENTER;
141
142 prepareGeometryChange();
143
144
145 // Make the axis labels disappear when the widget becomes too small
146 int x = 0, y = 0, w = m_widget->width(), h = m_widget->height();
147 m_boundingRect = QRectF(0, 0, w, h);
148
149 if (m_widget->width() >= 200) {
150 x = margin_l;
151 w -= (margin_l + margin_r);
152 }
153
154 if (m_widget->height() >= 120) {
155 y = margin_t;
156 h -= (margin_t + margin_b);
157 }
158
159
160 m_rect.setRect(x, y, w, h);
161
162 // update the vectors mapping indices and frequencies to widget coordinates
163 update_freq_map();
164
165 // re-draw the background pixmap
166 update_background();
167 }
168
update_background()169 void SpectralMeterView::update_background()
170 {
171 // draw the background image
172 bgPixmap = QPixmap((int)m_boundingRect.width(), (int)m_boundingRect.height());
173 bgPixmap.fill(themer()->get_color("FFTMeter:margin"));
174
175 QPainter painter(&bgPixmap);
176 painter.fillRect(m_rect, themer()->get_color("FFTMeter:background"));
177 painter.setFont(themer()->get_font("FFTMeter:fontscale:label"));
178 QFontMetrics fm(themer()->get_font("FFTMeter:fontscale:label"));
179
180 QString spm;
181
182 // draw horizontal lines + labels
183 for (float i = upper_db; i >= lower_db; i -= 10.0f) {
184 float f = db2ypos(i);
185
186 painter.setPen(themer()->get_color("FFTMeter:grid"));
187 painter.drawLine(QPointF(m_rect.x(), f), QPointF(m_rect.right(), f));
188
189 painter.setPen(themer()->get_color("FFTMeter:text"));
190 spm.sprintf("%2.0f", i);
191 painter.drawText(m_rect.right() + 1, (int)f + fm.ascent()/2, spm);
192 }
193
194 // draw frequency labels and tickmarks
195 float last_pos = 1.0;
196 for (int i = 0; i < m_freq_labels.size(); ++i) {
197 // check if we have space to draw the labels by checking if the
198 // m_rect is borderless
199 if (!m_rect.top()) {
200 break;
201 }
202
203 float f = freq2xpos(m_freq_labels.at(i));
204
205 // check if the freq is in the visible range
206 if (!f) {
207 continue;
208 }
209
210 spm.sprintf("%2.0f", m_freq_labels.at(i));
211 float s = (float)fm.width(spm)/2.0f;
212
213
214 // draw text only if there is enough space for it
215 if (((f - s) > last_pos) && ((f + s) < float(m_boundingRect.width()-1))) {
216 painter.setPen(themer()->get_color("FFTMeter:text"));
217 painter.drawText(QPointF(f - s, m_boundingRect.height() - fm.descent() - 3), spm);
218 last_pos = f + s + 1.0;
219 painter.setPen(themer()->get_color("FFTMeter:tickmarks:main"));
220 } else {
221 painter.setPen(themer()->get_color("FFTMeter:tickmarks:sub"));
222 }
223
224 painter.drawLine(QPointF(f, m_rect.bottom()), QPointF(f, m_rect.bottom() + 3));
225 }
226 }
227
update_data()228 void SpectralMeterView::update_data()
229 {
230 if (!m_meter) {
231 return;
232 }
233
234 // if no data was available, return, so we _only_ update the widget when
235 // it needs to be!
236
237 int ret = ((SpectralMeter*)m_meter)->get_data(specl, specr);
238
239 // switch off the update of the average curve if silence is played back.
240 if (ret == -1) {
241 update_average = false;
242 } else {
243 update_average = true;
244 }
245
246 // do nothing if the buffer is not ready.
247 if (ret == 0) {
248 return;
249 }
250
251 // process the data
252 reduce_bands();
253
254 // paint the widget
255 update();
256 }
257
set_sheet(Sheet * sheet)258 void SpectralMeterView::set_sheet(Sheet *sheet)
259 {
260 MeterView::set_sheet(sheet);
261
262 if ( ! m_sheet ) {
263 return;
264 }
265
266 PluginChain* chain = m_sheet->get_plugin_chain();
267 sample_rate = audiodevice().get_sample_rate();
268
269 foreach(Plugin* plugin, chain->get_plugin_list()) {
270 m_meter = qobject_cast<SpectralMeter*>(plugin);
271
272 if (m_meter) {
273 return;
274 }
275 }
276
277 m_meter = new SpectralMeter();
278 m_meter->init();
279 Command::process_command(chain->add_plugin(m_meter, false));
280 }
281
reduce_bands()282 void SpectralMeterView::reduce_bands()
283 {
284 // check if we have to update some variables
285 if ((m_spectrum.size() != (int)num_bands)
286 || (fft_size != (uint)qMin(specl.size(), specr.size()))
287 || ((uint)m_map_idx2freq.size() != fft_size)) {
288 update_layout();
289 }
290
291 // calculate the sample weight for the average curve
292 double sweight = 1.0 / (double)sample_weight;
293 double oweight = 1.0 - sweight;
294
295 // loop through the freq bands and determine the db-values
296 for (int i = 0; i < m_spectrum.size(); ++i) {
297 float val = freq2db(m_bands.at(i), m_bands.at(i+1));
298 float hist = DB_FLOOR + (m_spectrum.at(i) - DB_FLOOR) * SMOOTH_FACTOR;
299 m_spectrum[i] = qMax(val, hist);
300 }
301
302 // fill the average sample curve
303 if (show_average && update_average) {
304 for (int i = 0; i < m_avg_db.size(); ++i) {
305 float val = 5.0 * (log10(specl.at(i) * specr.at(i)) + xfactor);
306 float v = val * sweight + m_avg_db.at(i) * oweight;
307 m_avg_db[i] = v;
308 }
309
310 // progress the sample weighting for the average curve
311 if (sample_weight < (MAX_SAMPLES - 1)) {
312 ++sample_weight;
313 }
314 }
315 }
316
317 // call this function if the size, number of bands, ranges etc. changed.
318 // it re-calculates some variables
update_layout()319 void SpectralMeterView::update_layout()
320 {
321 // recalculate a couple of variables
322 fft_size = qMin(specl.size(), specr.size()); // number of frequencies (size of the FFT)
323 xfactor = 4.0f * log10(2.0f / float(fft_size)); // a constant factor for conversion to dB
324 upper_freq_log = log10(upper_freq);
325 lower_freq_log = log10(lower_freq);
326 freq_step = (upper_freq_log - lower_freq_log)/(num_bands);
327 sample_weight = 1;
328
329 // recreate the vector containing the levels and frequency bands
330 m_spectrum.fill(DEFAULT_VAL, num_bands);
331 m_avg_db.fill(DEFAULT_VAL, fft_size);
332
333 // recreate the vector containing border frequencies of the freq bands
334 m_bands.clear();
335 for (uint i = 0; i <= num_bands; ++i) {
336 m_bands.push_back(pow(10.0, lower_freq_log + i*freq_step));
337 }
338
339 // update related stuff
340 update_freq_map();
341 }
342
343 // converts db-values into widget y-coordinates
db2ypos(float f)344 float SpectralMeterView::db2ypos(float f)
345 {
346 return ((f - upper_db) * m_rect.height()/(lower_db - upper_db)) + m_rect.top();
347 }
348
349 // converts frequencies into widget x-coordinates
freq2xpos(float f)350 float SpectralMeterView::freq2xpos(float f)
351 {
352 if ((f < lower_freq) || (f > upper_freq)) {
353 return 0.0;
354 }
355
356 float d = log10(f) - lower_freq_log;
357 return (float)m_rect.x() + d * m_rect.width() / (upper_freq_log - lower_freq_log);
358 }
359
360 // determines the highest db value for frequency rang fl-fu. Does all the interpolation etc.
freq2db(float fl,float fu)361 float SpectralMeterView::freq2db(float fl, float fu)
362 {
363 float lfreq = qMin(fl, fu);
364 float ufreq = qMax(fl, fu);
365 float fidxl = lfreq * (2.0f * fft_size) / (float)sample_rate;
366 float fidxu = ufreq * (2.0f * fft_size) / (float)sample_rate;
367
368 int idxl = int(floor(fidxl - 1.0f));
369 int idxu = int(ceil(fidxu - 1.0f));
370
371 if (idxl < 0) {
372 idxl = 0;
373 }
374
375 if ((uint)idxu >= fft_size) {
376 idxu = fft_size - 1;
377 }
378
379 // distinguishing some cases to save cpu cycles.
380
381 // if we're outside the range covered by the FFT, return DB_FLOOR
382 if (idxu <= 0) {
383 return DB_FLOOR;
384 }
385 if (idxl >= (int)fft_size) {
386 return DB_FLOOR;
387 }
388
389 // they are the same (which shouldn't happen)
390 if (idxu - idxl == 0) {
391 return DB_FLOOR;
392 }
393
394 // if we have exactly one bin in the freq range, return it's db-value and exit
395 if (idxu - idxl == 2) {
396 return 5.0f * (log10(specl.at(idxl + 1) * specr.at(idxl + 1)) + xfactor);
397 }
398
399 // if no bin is in between, we have to interpolate in order to get an accurate value
400 if (idxu - idxl == 1) {
401 float v = fidxu - fidxl;
402 float dbvl = specl.at(idxl) * specr.at(idxl);
403 float dbvu = specl.at(idxu) * specr.at(idxu);
404 return 5.0 * (log10(dbvl + v * (dbvu - dbvl)) + xfactor);
405 }
406
407 // if several bins are in between, search the highest db value
408 float val = 0.0;
409 for (int i = idxl; i <=idxu; ++i) {
410 val = qMax(val, specl.at(i) * specr.at(i));
411 }
412
413 return 5.0 * (log10(val) + xfactor);
414 }
415
416 // updates a vector mapping fft indices (0, ..., fft_size) to widget x-positions
417 // and one mapping fft indices to frequency
update_freq_map()418 void SpectralMeterView::update_freq_map()
419 {
420 m_map_idx2xpos.clear();
421 m_map_idx2freq.clear();
422 for (uint i = 0; i < fft_size; ++i) {
423 float freq = float(i+1) * (float)sample_rate / (2.0f * fft_size);
424 m_map_idx2freq.push_back(freq);
425 m_map_idx2xpos.push_back(freq2xpos(freq));
426 }
427 }
428
429 // opens the properties dialog
edit_properties()430 Command* SpectralMeterView::edit_properties()
431 {
432 if (!m_meter) {
433 return 0;
434 }
435
436 if (!m_config) {
437 m_config = new SpectralMeterConfigWidget(m_widget);
438 connect(m_config, SIGNAL(configChanged()), this, SLOT(load_configuration()));
439 }
440
441 m_config->show();
442
443 return 0;
444 }
445
446 // is called upon closing the properties dialog
load_configuration()447 void SpectralMeterView::load_configuration()
448 {
449 upper_freq = config().get_property("SpectralMeter", "UpperFrequenty", 22050).toInt();
450 lower_freq = config().get_property("SpectralMeter", "LowerFrequenty", 20).toInt();
451 num_bands = config().get_property("SpectralMeter", "NumberOfBands", 16).toInt();
452 upper_db = config().get_property("SpectralMeter", "UpperdB", 0).toInt();
453 lower_db = config().get_property("SpectralMeter", "LowerdB", -90).toInt();
454 show_average = config().get_property("SpectralMeter", "ShowAvarage", 0).toInt();
455
456 if (m_meter) {
457 ((SpectralMeter*)m_meter)->set_fr_size(config().get_property("SpectralMeter", "FFTSize", 2048).toInt());
458 ((SpectralMeter*)m_meter)->set_windowing_function(config().get_property("SpectralMeter", "WindowingFunction", 1).toInt());
459 ((SpectralMeter*)m_meter)->init();
460 }
461
462 update_layout();
463 }
464
set_mode()465 Command* SpectralMeterView::set_mode()
466 {
467 show_average = !show_average;
468 update_layout();
469 return 0;
470 }
471
reset()472 Command* SpectralMeterView::reset()
473 {
474 sample_weight = 1;
475 return 0;
476 }
477
screen_capture()478 Command* SpectralMeterView::screen_capture( )
479 {
480 QImage image(m_widget->size(), QImage::Format_RGB32);
481 QPainter painter(&image);
482 m_widget->render(&painter);
483
484 QString fn = QFileDialog::getSaveFileName (0, tr("Screen Capture file name"), QDir::homePath());
485
486 // if aborted exit here
487 if (fn.isEmpty()) {
488 return 0;
489 }
490
491 if ( ! image.save(fn, "PNG")) {
492 info().warning(tr("FFT: Unable to write captured image to hard disk"));
493 }
494
495 return 0;
496 }
497
export_avarage_curve()498 Command* SpectralMeterView::export_avarage_curve()
499 {
500 // check if all requirements are met
501 if ((!show_average) || (!m_project)) {
502 printf("No average data available.\n");
503 info().warning(tr("FFT: No avarage curve used, not data to export!"));
504 info().information(tr("FFT: Enable avarage curve with < M > to generate data"));
505 return 0;
506 }
507
508 // check if there actually is data to export
509 int s = qMin(m_map_idx2freq.size(), m_avg_db.size());
510 if (!s) {
511 printf("No average data available.\n");
512 info().warning(tr("FFT: No avarage data to export!"));
513 return 0;
514 }
515
516 QStringList oFormats;
517
518 QString formatA = "plain text";
519 QString formatB = "XMGrace";
520
521 oFormats.append(formatA);
522 oFormats.append(formatB);
523
524 bool ok;
525 QString format = QInputDialog::getItem( 0, tr("Select output format"), tr("Output format:"),
526 oFormats, 0, false, &ok );
527
528 if (!ok) {
529 printf("Aborted.");
530 return 0;
531 }
532
533 QString fn = QFileDialog::getSaveFileName (0, tr("Export average dB curve"), m_project->get_root_dir());
534
535 // if aborted exit here
536 if (fn.isEmpty()) {
537 return 0;
538 }
539
540 QFile file(fn);
541
542 // check if the selected file can be opened for writing
543 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
544 printf("Could not open file for writing.");
545 return 0;
546 }
547
548 QTextStream out(&file);
549 QString separator = " ";
550 QString str;
551
552 if (format == formatA) {
553 // export the data in text format
554 for (int i = 0; i < s; ++i) {
555 out << str.sprintf("%.6f %.6f\n", m_map_idx2freq.at(i), m_avg_db.at(i));
556 }
557
558 return 0;
559 }
560
561 if (format == formatB) {
562 // export the data in XMGrace format
563 out << get_xmgr_string();
564 return 0;
565 }
566
567 return 0;
568 }
569
get_xmgr_string()570 QString SpectralMeterView::get_xmgr_string()
571 {
572 QString s = "# Grace project file\n";
573 s += "#\n";
574 s += "@version 50120\n";
575 s += "@page size 842, 594\n";
576 s += "@page scroll 5\%\n";
577 s += "@page inout 5\%\n";
578 s += "@link page off\n";
579 s += "@map font 39 to \"Courier\", \"Courier\"\n";
580 s += "@map font 40 to \"Courier-Bold\", \"Courier-Bold\"\n";
581 s += "@map font 11 to \"Courier-BoldOblique\", \"Courier-BoldOblique\"\n";
582 s += "@map font 9 to \"Courier-Oblique\", \"Courier-Oblique\"\n";
583 s += "@map font 4 to \"Helvetica\", \"Helvetica\"\n";
584 s += "@map font 6 to \"Helvetica-Bold\", \"Helvetica-Bold\"\n";
585 s += "@map font 7 to \"Helvetica-BoldOblique\", \"Helvetica-BoldOblique\"\n";
586 s += "@map font 15 to \"Helvetica-Narrow\", \"Helvetica-Narrow\"\n";
587 s += "@map font 16 to \"Helvetica-Narrow-Bold\", \"Helvetica-Narrow-Bold\"\n";
588 s += "@map font 17 to \"Helvetica-Narrow-BoldOblique\", \"Helvetica-Narrow-BoldOblique\"\n";
589 s += "@map font 18 to \"Helvetica-Narrow-Oblique\", \"Helvetica-Narrow-Oblique\"\n";
590 s += "@map font 5 to \"Helvetica-Oblique\", \"Helvetica-Oblique\"\n";
591 s += "@map font 20 to \"NewCenturySchlbk-Bold\", \"NewCenturySchlbk-Bold\"\n";
592 s += "@map font 21 to \"NewCenturySchlbk-BoldItalic\", \"NewCenturySchlbk-BoldItalic\"\n";
593 s += "@map font 22 to \"NewCenturySchlbk-Italic\", \"NewCenturySchlbk-Italic\"\n";
594 s += "@map font 23 to \"NewCenturySchlbk-Roman\", \"NewCenturySchlbk-Roman\"\n";
595 s += "@map font 24 to \"Palatino-Bold\", \"Palatino-Bold\"\n";
596 s += "@map font 25 to \"Palatino-BoldItalic\", \"Palatino-BoldItalic\"\n";
597 s += "@map font 26 to \"Palatino-Italic\", \"Palatino-Italic\"\n";
598 s += "@map font 27 to \"Palatino-Roman\", \"Palatino-Roman\"\n";
599 s += "@map font 12 to \"Symbol\", \"Symbol\"\n";
600 s += "@map font 2 to \"Times-Bold\", \"Times-Bold\"\n";
601 s += "@map font 3 to \"Times-BoldItalic\", \"Times-BoldItalic\"\n";
602 s += "@map font 1 to \"Times-Italic\", \"Times-Italic\"\n";
603 s += "@map font 0 to \"Times-Roman\", \"Times-Roman\"\n";
604 s += "@map font 33 to \"ZapfChancery-MediumItalic\", \"ZapfChancery-MediumItalic\"\n";
605 s += "@map font 13 to \"ZapfDingbats\", \"ZapfDingbats\"\n";
606 s += "@map font 35 to \"CharterBT-Bold\", \"CharterBT-Bold\"\n";
607 s += "@map font 36 to \"CharterBT-BoldItalic\", \"CharterBT-BoldItalic\"\n";
608 s += "@map font 37 to \"CharterBT-Italic\", \"CharterBT-Italic\"\n";
609 s += "@map font 38 to \"CharterBT-Roman\", \"CharterBT-Roman\"\n";
610 s += "@map font 41 to \"Courier-BoldItalic\", \"Courier-BoldItalic\"\n";
611 s += "@map font 42 to \"Courier-Italic\", \"Courier-Italic\"\n";
612 s += "@map font 43 to \"Hershey-Gothic-English\", \"Hershey-Gothic-English\"\n";
613 s += "@map font 44 to \"Hershey-Gothic-German\", \"Hershey-Gothic-German\"\n";
614 s += "@map font 45 to \"Hershey-Gothic-Italian\", \"Hershey-Gothic-Italian\"\n";
615 s += "@map font 46 to \"Hershey-Plain-Duplex\", \"Hershey-Plain-Duplex\"\n";
616 s += "@map font 47 to \"Hershey-Plain-Duplex-Italic\", \"Hershey-Plain-Duplex-Italic\"\n";
617 s += "@map font 48 to \"Hershey-Plain-Triplex\", \"Hershey-Plain-Triplex\"\n";
618 s += "@map font 49 to \"Hershey-Plain-Triplex-Italic\", \"Hershey-Plain-Triplex-Italic\"\n";
619 s += "@map font 50 to \"Hershey-Script-Complex\", \"Hershey-Script-Complex\"\n";
620 s += "@map font 51 to \"Hershey-Script-Simplex\", \"Hershey-Script-Simplex\"\n";
621 s += "@map font 52 to \"LuxiMono\", \"LuxiMono\"\n";
622 s += "@map font 53 to \"LuxiMono-Bold\", \"LuxiMono-Bold\"\n";
623 s += "@map font 54 to \"LuxiMono-BoldOblique\", \"LuxiMono-BoldOblique\"\n";
624 s += "@map font 55 to \"LuxiMono-Oblique\", \"LuxiMono-Oblique\"\n";
625 s += "@map font 56 to \"LuxiSans\", \"LuxiSans\"\n";
626 s += "@map font 57 to \"LuxiSans-Bold\", \"LuxiSans-Bold\"\n";
627 s += "@map font 58 to \"LuxiSans-BoldOblique\", \"LuxiSans-BoldOblique\"\n";
628 s += "@map font 59 to \"LuxiSans-Oblique\", \"LuxiSans-Oblique\"\n";
629 s += "@map font 60 to \"LuxiSerif\", \"LuxiSerif\"\n";
630 s += "@map font 61 to \"LuxiSerif-Bold\", \"LuxiSerif-Bold\"\n";
631 s += "@map font 62 to \"LuxiSerif-BoldOblique\", \"LuxiSerif-BoldOblique\"\n";
632 s += "@map font 63 to \"LuxiSerif-Oblique\", \"LuxiSerif-Oblique\"\n";
633 s += "@map font 64 to \"Utopia-Bold\", \"Utopia-Bold\"\n";
634 s += "@map font 65 to \"Utopia-BoldItalic\", \"Utopia-BoldItalic\"\n";
635 s += "@map font 66 to \"Utopia-Italic\", \"Utopia-Italic\"\n";
636 s += "@map font 67 to \"Utopia-Regular\", \"Utopia-Regular\"\n";
637 s += "@map color 0 to (255, 255, 255), \"white\"\n";
638 s += "@map color 1 to (0, 0, 0), \"black\"\n";
639 s += "@map color 2 to (255, 0, 0), \"red\"\n";
640 s += "@map color 3 to (0, 255, 0), \"green\"\n";
641 s += "@map color 4 to (0, 0, 255), \"blue\"\n";
642 s += "@map color 5 to (255, 255, 0), \"yellow\"\n";
643 s += "@map color 6 to (188, 143, 143), \"brown\"\n";
644 s += "@map color 7 to (220, 220, 220), \"grey\"\n";
645 s += "@map color 8 to (148, 0, 211), \"violet\"\n";
646 s += "@map color 9 to (0, 255, 255), \"cyan\"\n";
647 s += "@map color 10 to (255, 0, 255), \"magenta\"\n";
648 s += "@map color 11 to (255, 165, 0), \"orange\"\n";
649 s += "@map color 12 to (114, 33, 188), \"indigo\"\n";
650 s += "@map color 13 to (103, 7, 72), \"maroon\"\n";
651 s += "@map color 14 to (64, 224, 208), \"turquoise\"\n";
652 s += "@map color 15 to (0, 139, 0), \"green4\"\n";
653 s += "@reference date 0\n";
654 s += "@date wrap off\n";
655 s += "@date wrap year 1950\n";
656 s += "@default linewidth 1.0\n";
657 s += "@default linestyle 1\n";
658 s += "@default color 1\n";
659 s += "@default pattern 1\n";
660 s += "@default font 0\n";
661 s += "@default char size 1.000000\n";
662 s += "@default symbol size 1.000000\n";
663 s += "@default sformat \"\%.8g\"\n";
664 s += "@background color 0\n";
665 s += "@page background fill on\n";
666 s += "@timestamp off\n";
667 s += "@timestamp 0.03, 0.03\n";
668 s += "@timestamp color 1\n";
669 s += "@timestamp rot 0\n";
670 s += "@timestamp font 0\n";
671 s += "@timestamp char size 1.000000\n";
672 s += "@timestamp def \"Sun Jan 21 12:56:47 2007\"\n";
673 s += "@r0 off\n";
674 s += "@link r0 to g0\n";
675 s += "@r0 type above\n";
676 s += "@r0 linestyle 1\n";
677 s += "@r0 linewidth 1.0\n";
678 s += "@r0 color 1\n";
679 s += "@r0 line 0, 0, 0, 0\n";
680 s += "@r1 off\n";
681 s += "@link r1 to g0\n";
682 s += "@r1 type above\n";
683 s += "@r1 linestyle 1\n";
684 s += "@r1 linewidth 1.0\n";
685 s += "@r1 color 1\n";
686 s += "@r1 line 0, 0, 0, 0\n";
687 s += "@r2 off\n";
688 s += "@link r2 to g0\n";
689 s += "@r2 type above\n";
690 s += "@r2 linestyle 1\n";
691 s += "@r2 linewidth 1.0\n";
692 s += "@r2 color 1\n";
693 s += "@r2 line 0, 0, 0, 0\n";
694 s += "@r3 off\n";
695 s += "@link r3 to g0\n";
696 s += "@r3 type above\n";
697 s += "@r3 linestyle 1\n";
698 s += "@r3 linewidth 1.0\n";
699 s += "@r3 color 1\n";
700 s += "@r3 line 0, 0, 0, 0\n";
701 s += "@r4 off\n";
702 s += "@link r4 to g0\n";
703 s += "@r4 type above\n";
704 s += "@r4 linestyle 1\n";
705 s += "@r4 linewidth 1.0\n";
706 s += "@r4 color 1\n";
707 s += "@r4 line 0, 0, 0, 0\n";
708 s += "@g0 on\n";
709 s += "@g0 hidden false\n";
710 s += "@g0 type XY\n";
711 s += "@g0 stacked false\n";
712 s += "@g0 bar hgap 0.000000\n";
713 s += "@g0 fixedpoint off\n";
714 s += "@g0 fixedpoint type 0\n";
715 s += "@g0 fixedpoint xy 0.000000, 0.000000\n";
716 s += "@g0 fixedpoint format general general\n";
717 s += "@g0 fixedpoint prec 6, 6\n";
718 s += "@with g0\n";
719 s += "@ world 20, -90, 20000, 0\n";
720 s += "@ stack world 0, 0, 0, 0\n";
721 s += "@ znorm 1\n";
722 s += "@ view 0.130000, 0.120000, 1.300000, 0.920000\n";
723 s += "@ title \"\"\n";
724 s += "@ title font 0\n";
725 s += "@ title size 1.500000\n";
726 s += "@ title color 1\n";
727 s += "@ subtitle \"\"\n";
728 s += "@ subtitle font 0\n";
729 s += "@ subtitle size 1.000000\n";
730 s += "@ subtitle color 1\n";
731 s += "@ xaxes scale Logarithmic\n";
732 s += "@ yaxes scale Normal\n";
733 s += "@ xaxes invert off\n";
734 s += "@ yaxes invert off\n";
735 s += "@ xaxis on\n";
736 s += "@ xaxis type zero false\n";
737 s += "@ xaxis offset 0.000000 , 0.000000\n";
738 s += "@ xaxis bar on\n";
739 s += "@ xaxis bar color 1\n";
740 s += "@ xaxis bar linestyle 1\n";
741 s += "@ xaxis bar linewidth 1.0\n";
742 s += "@ xaxis label \"Frequency (Hz)\"\n";
743 s += "@ xaxis label layout para\n";
744 s += "@ xaxis label place auto\n";
745 s += "@ xaxis label char size 1.000000\n";
746 s += "@ xaxis label font 0\n";
747 s += "@ xaxis label color 1\n";
748 s += "@ xaxis label place normal\n";
749 s += "@ xaxis tick on\n";
750 s += "@ xaxis tick major 10\n";
751 s += "@ xaxis tick minor ticks 9\n";
752 s += "@ xaxis tick default 6\n";
753 s += "@ xaxis tick place rounded true\n";
754 s += "@ xaxis tick in\n";
755 s += "@ xaxis tick major size 0.500000\n";
756 s += "@ xaxis tick major color 1\n";
757 s += "@ xaxis tick major linewidth 1.0\n";
758 s += "@ xaxis tick major linestyle 1\n";
759 s += "@ xaxis tick major grid on\n";
760 s += "@ xaxis tick minor color 1\n";
761 s += "@ xaxis tick minor linewidth 1.0\n";
762 s += "@ xaxis tick minor linestyle 2\n";
763 s += "@ xaxis tick minor grid on\n";
764 s += "@ xaxis tick minor size 0.250000\n";
765 s += "@ xaxis ticklabel on\n";
766 s += "@ xaxis ticklabel format general\n";
767 s += "@ xaxis ticklabel prec 5\n";
768 s += "@ xaxis ticklabel formula \"\"\n";
769 s += "@ xaxis ticklabel append \"\"\n";
770 s += "@ xaxis ticklabel prepend \"\"\n";
771 s += "@ xaxis ticklabel angle 0\n";
772 s += "@ xaxis ticklabel skip 0\n";
773 s += "@ xaxis ticklabel stagger 0\n";
774 s += "@ xaxis ticklabel place normal\n";
775 s += "@ xaxis ticklabel offset auto\n";
776 s += "@ xaxis ticklabel offset 0.000000 , 0.010000\n";
777 s += "@ xaxis ticklabel start type auto\n";
778 s += "@ xaxis ticklabel start 0.000000\n";
779 s += "@ xaxis ticklabel stop type auto\n";
780 s += "@ xaxis ticklabel stop 0.000000\n";
781 s += "@ xaxis ticklabel char size 0.750000\n";
782 s += "@ xaxis ticklabel font 0\n";
783 s += "@ xaxis ticklabel color 1\n";
784 s += "@ xaxis tick place both\n";
785 s += "@ xaxis tick spec type both\n";
786 s += "@ xaxis tick spec 37\n";
787 s += "@ xaxis tick major 0, 10\n";
788 s += "@ xaxis ticklabel 0, \"10\"\n";
789 s += "@ xaxis tick major 1, 20\n";
790 s += "@ xaxis ticklabel 1, \"20\"\n";
791 s += "@ xaxis tick minor 2, 30\n";
792 s += "@ xaxis tick minor 3, 40\n";
793 s += "@ xaxis tick major 4, 50\n";
794 s += "@ xaxis ticklabel 4, \"50\"\n";
795 s += "@ xaxis tick minor 5, 60\n";
796 s += "@ xaxis tick minor 6, 70\n";
797 s += "@ xaxis tick minor 7, 80\n";
798 s += "@ xaxis tick minor 8, 90\n";
799 s += "@ xaxis tick major 9, 100\n";
800 s += "@ xaxis ticklabel 9, \"100\"\n";
801 s += "@ xaxis tick major 10, 200\n";
802 s += "@ xaxis ticklabel 10, \"200\"\n";
803 s += "@ xaxis tick minor 11, 300\n";
804 s += "@ xaxis tick minor 12, 400\n";
805 s += "@ xaxis tick major 13, 500\n";
806 s += "@ xaxis ticklabel 13, \"500\"\n";
807 s += "@ xaxis tick minor 14, 600\n";
808 s += "@ xaxis tick minor 15, 700\n";
809 s += "@ xaxis tick minor 16, 800\n";
810 s += "@ xaxis tick minor 17, 900\n";
811 s += "@ xaxis tick major 18, 1000\n";
812 s += "@ xaxis ticklabel 18, \"1000\"\n";
813 s += "@ xaxis tick major 19, 2000\n";
814 s += "@ xaxis ticklabel 19, \"2000\"\n";
815 s += "@ xaxis tick minor 20, 3000\n";
816 s += "@ xaxis tick minor 21, 4000\n";
817 s += "@ xaxis tick major 22, 5000\n";
818 s += "@ xaxis ticklabel 22, \"5000\"\n";
819 s += "@ xaxis tick minor 23, 6000\n";
820 s += "@ xaxis tick minor 24, 7000\n";
821 s += "@ xaxis tick minor 25, 8000\n";
822 s += "@ xaxis tick minor 26, 9000\n";
823 s += "@ xaxis tick major 27, 10000\n";
824 s += "@ xaxis ticklabel 27, \"10000\"\n";
825 s += "@ xaxis tick major 28, 20000\n";
826 s += "@ xaxis ticklabel 28, \"20000\"\n";
827 s += "@ xaxis tick minor 29, 30000\n";
828 s += "@ xaxis tick minor 30, 40000\n";
829 s += "@ xaxis tick minor 31, 50000\n";
830 s += "@ xaxis tick minor 32, 60000\n";
831 s += "@ xaxis tick minor 33, 70000\n";
832 s += "@ xaxis tick minor 34, 80000\n";
833 s += "@ xaxis tick minor 35, 90000\n";
834 s += "@ xaxis tick minor 36, 100000\n";
835 s += "@ xaxis ticklabel 36, \"1e+05\"\n";
836 s += "@ yaxis on\n";
837 s += "@ yaxis type zero false\n";
838 s += "@ yaxis offset 0.000000 , 0.000000\n";
839 s += "@ yaxis bar on\n";
840 s += "@ yaxis bar color 1\n";
841 s += "@ yaxis bar linestyle 1\n";
842 s += "@ yaxis bar linewidth 1.0\n";
843 s += "@ yaxis label \"Level (dB)\"\n";
844 s += "@ yaxis label layout para\n";
845 s += "@ yaxis label place auto\n";
846 s += "@ yaxis label char size 1.000000\n";
847 s += "@ yaxis label font 0\n";
848 s += "@ yaxis label color 1\n";
849 s += "@ yaxis label place normal\n";
850 s += "@ yaxis tick on\n";
851 s += "@ yaxis tick major 10\n";
852 s += "@ yaxis tick minor ticks 1\n";
853 s += "@ yaxis tick default 6\n";
854 s += "@ yaxis tick place rounded true\n";
855 s += "@ yaxis tick in\n";
856 s += "@ yaxis tick major size 0.500000\n";
857 s += "@ yaxis tick major color 1\n";
858 s += "@ yaxis tick major linewidth 1.0\n";
859 s += "@ yaxis tick major linestyle 1\n";
860 s += "@ yaxis tick major grid on\n";
861 s += "@ yaxis tick minor color 1\n";
862 s += "@ yaxis tick minor linewidth 1.0\n";
863 s += "@ yaxis tick minor linestyle 2\n";
864 s += "@ yaxis tick minor grid on\n";
865 s += "@ yaxis tick minor size 0.250000\n";
866 s += "@ yaxis ticklabel on\n";
867 s += "@ yaxis ticklabel format general\n";
868 s += "@ yaxis ticklabel prec 5\n";
869 s += "@ yaxis ticklabel formula \"\"\n";
870 s += "@ yaxis ticklabel append \"\"\n";
871 s += "@ yaxis ticklabel prepend \"\"\n";
872 s += "@ yaxis ticklabel angle 0\n";
873 s += "@ yaxis ticklabel skip 0\n";
874 s += "@ yaxis ticklabel stagger 0\n";
875 s += "@ yaxis ticklabel place normal\n";
876 s += "@ yaxis ticklabel offset auto\n";
877 s += "@ yaxis ticklabel offset 0.000000 , 0.010000\n";
878 s += "@ yaxis ticklabel start type auto\n";
879 s += "@ yaxis ticklabel start 0.000000\n";
880 s += "@ yaxis ticklabel stop type auto\n";
881 s += "@ yaxis ticklabel stop 0.000000\n";
882 s += "@ yaxis ticklabel char size 0.750000\n";
883 s += "@ yaxis ticklabel font 0\n";
884 s += "@ yaxis ticklabel color 1\n";
885 s += "@ yaxis tick place both\n";
886 s += "@ yaxis tick spec type none\n";
887 s += "@ altxaxis off\n";
888 s += "@ altyaxis off\n";
889 s += "@ legend on\n";
890 s += "@ legend loctype view\n";
891 s += "@ legend 0.84941423, 0.8\n";
892 s += "@ legend box color 1\n";
893 s += "@ legend box pattern 1\n";
894 s += "@ legend box linewidth 1.0\n";
895 s += "@ legend box linestyle 1\n";
896 s += "@ legend box fill color 0\n";
897 s += "@ legend box fill pattern 1\n";
898 s += "@ legend font 0\n";
899 s += "@ legend char size 1.000000\n";
900 s += "@ legend color 1\n";
901 s += "@ legend length 4\n";
902 s += "@ legend vgap 1\n";
903 s += "@ legend hgap 1\n";
904 s += "@ legend invert false\n";
905 s += "@ frame type 0\n";
906 s += "@ frame linestyle 1\n";
907 s += "@ frame linewidth 1.0\n";
908 s += "@ frame color 1\n";
909 s += "@ frame pattern 1\n";
910 s += "@ frame background color 0\n";
911 s += "@ frame background pattern 0\n";
912 s += "@ s0 hidden false\n";
913 s += "@ s0 type xy\n";
914 s += "@ s0 symbol 9\n";
915 s += "@ s0 symbol size 0.500000\n";
916 s += "@ s0 symbol color 2\n";
917 s += "@ s0 symbol pattern 1\n";
918 s += "@ s0 symbol fill color 2\n";
919 s += "@ s0 symbol fill pattern 0\n";
920 s += "@ s0 symbol linewidth 1.0\n";
921 s += "@ s0 symbol linestyle 1\n";
922 s += "@ s0 symbol char 65\n";
923 s += "@ s0 symbol char font 0\n";
924 s += "@ s0 symbol skip 0\n";
925 s += "@ s0 line type 1\n";
926 s += "@ s0 line linestyle 1\n";
927 s += "@ s0 line linewidth 2.0\n";
928 s += "@ s0 line color 1\n";
929 s += "@ s0 line pattern 1\n";
930 s += "@ s0 baseline type 0\n";
931 s += "@ s0 baseline off\n";
932 s += "@ s0 dropline off\n";
933 s += "@ s0 fill type 0\n";
934 s += "@ s0 fill rule 0\n";
935 s += "@ s0 fill color 1\n";
936 s += "@ s0 fill pattern 1\n";
937 s += "@ s0 avalue off\n";
938 s += "@ s0 avalue type 2\n";
939 s += "@ s0 avalue char size 1.000000\n";
940 s += "@ s0 avalue font 0\n";
941 s += "@ s0 avalue color 1\n";
942 s += "@ s0 avalue rot 0\n";
943 s += "@ s0 avalue format general\n";
944 s += "@ s0 avalue prec 3\n";
945 s += "@ s0 avalue prepend \"\"\n";
946 s += "@ s0 avalue append \"\"\n";
947 s += "@ s0 avalue offset 0.000000 , 0.000000\n";
948 s += "@ s0 errorbar off\n";
949 s += "@ s0 errorbar place both\n";
950 s += "@ s0 errorbar color 2\n";
951 s += "@ s0 errorbar pattern 1\n";
952 s += "@ s0 errorbar size 1.000000\n";
953 s += "@ s0 errorbar linewidth 1.0\n";
954 s += "@ s0 errorbar linestyle 1\n";
955 s += "@ s0 errorbar riser linewidth 1.0\n";
956 s += "@ s0 errorbar riser linestyle 1\n";
957 s += "@ s0 errorbar riser clip off\n";
958 s += "@ s0 errorbar riser clip length 0.100000\n";
959 s += "@ s0 comment \"Exported from Traverso\"\n";
960 s += "@ s0 legend \"\"\n";
961 s += "@target G0.S0\n";
962 s += "@type xy\n";
963
964 int n = qMin(m_map_idx2freq.size(), m_avg_db.size());
965 QString str;
966
967 for (int i = 0; i < n; ++i) {
968 s += str.sprintf("%.6f %.6f\n", m_map_idx2freq.at(i), m_avg_db.at(i));
969 }
970
971 s += "&\n";
972
973 return s;
974 }
975
976
977 /*******************************************/
978 /* SpectralMeterConfWidget */
979 /*******************************************/
980
SpectralMeterConfigWidget(QWidget * parent)981 SpectralMeterConfigWidget::SpectralMeterConfigWidget( QWidget * parent )
982 : QDialog(parent)
983 {
984 setupUi(this);
985 groupBoxAdvanced->hide();
986
987 load_configuration();
988
989 connect(buttonAdvanced, SIGNAL(toggled(bool)), this, SLOT(advancedButton_toggled(bool)));
990 }
991
on_buttonApply_clicked()992 void SpectralMeterConfigWidget::on_buttonApply_clicked()
993 {
994 save_configuration();
995 emit configChanged();
996 }
997
on_buttonClose_clicked()998 void SpectralMeterConfigWidget::on_buttonClose_clicked( )
999 {
1000 hide();
1001 }
1002
advancedButton_toggled(bool b)1003 void SpectralMeterConfigWidget::advancedButton_toggled(bool b)
1004 {
1005 if (b) {
1006 groupBoxAdvanced->show();
1007 } else {
1008 groupBoxAdvanced->hide();
1009 }
1010 }
1011
save_configuration()1012 void SpectralMeterConfigWidget::save_configuration( )
1013 {
1014 config().set_property( "SpectralMeter",
1015 "UpperFrequenty",
1016 qMax(spinBoxLowerFreq->value(), spinBoxUpperFreq->value()) );
1017 config().set_property( "SpectralMeter",
1018 "LowerFrequenty",
1019 qMin(spinBoxLowerFreq->value(), spinBoxUpperFreq->value()) );
1020 config().set_property( "SpectralMeter",
1021 "UpperdB",
1022 qMax(spinBoxUpperDb->value(), spinBoxLowerDb->value()) );
1023 config().set_property( "SpectralMeter",
1024 "LowerdB",
1025 qMin(spinBoxUpperDb->value(), spinBoxLowerDb->value()) );
1026 config().set_property("SpectralMeter", "NumberOfBands", spinBoxNumBands->value() );
1027 config().set_property("SpectralMeter", "ShowAvarage", checkBoxAverage->isChecked() );
1028
1029 config().set_property("SpectralMeter", "FFTSize", comboBoxFftSize->currentText().toInt() );
1030 config().set_property("SpectralMeter", "WindowingFunction", comboBoxWindowing->currentIndex() );
1031 }
1032
load_configuration()1033 void SpectralMeterConfigWidget::load_configuration( )
1034 {
1035 int value;
1036 value = config().get_property("SpectralMeter", "UpperFrequenty", 22050).toInt();
1037 spinBoxUpperFreq->setValue(value);
1038 value = config().get_property("SpectralMeter", "LowerFrequenty", 20).toInt();
1039 spinBoxLowerFreq->setValue(value);
1040 value = config().get_property("SpectralMeter", "UpperdB", 0).toInt();
1041 spinBoxUpperDb->setValue(value);
1042 value = config().get_property("SpectralMeter", "LowerdB", -90).toInt();
1043 spinBoxLowerDb->setValue(value);
1044 value = config().get_property("SpectralMeter", "NumberOfBands", 16).toInt();
1045 spinBoxNumBands->setValue(value);
1046 value = config().get_property("SpectralMeter", "ShowAvarage", 0).toInt();
1047 checkBoxAverage->setChecked(value);
1048 value = config().get_property("SpectralMeter", "FFTSize", 2048).toInt();
1049 QString str;
1050 str = QString("%1").arg(value);
1051 int idx = comboBoxFftSize->findText(str);
1052 idx = idx == -1 ? 3 : idx;
1053 comboBoxFftSize->setCurrentIndex(idx);
1054 value = config().get_property("SpectralMeter", "WindowingFunction", 1).toInt();
1055 comboBoxWindowing->setCurrentIndex(value);
1056 }
1057
1058 //eof
1059
1060