1 /*
2 Copyright (C) 2005-2008 Remon Sijrier
3
4 This file is part of Traverso
5
6 Traverso is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
20 */
21
22 #include "InfoWidgets.h"
23
24 #include "AudioDevice.h"
25 #include "Config.h"
26 #include "DiskIO.h"
27 #include "Interface.h"
28 #include "MessageWidget.h"
29 #include "Project.h"
30 #include "ProjectManager.h"
31 #include "Sheet.h"
32 #include "Themer.h"
33 #include "Track.h"
34 #include "Utils.h"
35
36 #include <QPainter>
37 #include <QByteArray>
38 #include <QPalette>
39 #include <QPushButton>
40 #include <QHBoxLayout>
41 #include <QAction>
42
43
44 #if defined (Q_WS_WIN)
45 #include <windows.h>
46 #elif defined (Q_WS_MAC)
47 #include <sys/param.h>
48 #include <sys/mount.h>
49 #else
50 #if defined(HAVE_SYS_VFS_H)
51 #include <sys/vfs.h>
52 #endif
53 #endif
54
55
56 // Always put me below _all_ includes, this is needed
57 // in case we run with memory leak detection enabled!
58 #include "Debugger.h"
59
60 #if defined (Q_WS_MAC)
61 static const int SONG_TOOLBAR_HEIGHT = 27;
62 #else
63 static const int SONG_TOOLBAR_HEIGHT = 24;
64 #endif
65
66
SystemResources(QWidget * parent)67 SystemResources::SystemResources(QWidget * parent)
68 : InfoWidget(parent)
69 {
70
71 m_writeBufferStatus = new SystemValueBar(this);
72 m_readBufferStatus = new SystemValueBar(this);
73 m_readBufferStatus->setToolTip(tr("Read Buffer Status"));
74 m_writeBufferStatus->setToolTip(tr("Write Buffer Status"));
75 m_cpuUsage = new SystemValueBar(this);
76 m_icon = new QPushButton();
77 m_icon->setIcon(find_pixmap(":/memorysmall"));
78 m_icon->setFlat(true);
79 m_icon->setMaximumWidth(20);
80 m_icon->setFocusPolicy(Qt::NoFocus);
81
82 m_writeBufferStatus->set_range(0, 100);
83 m_writeBufferStatus->add_range_color(0, 40, QColor(255, 0, 0));
84 m_writeBufferStatus->add_range_color(40, 60, QColor(255, 255, 0));
85 m_writeBufferStatus->add_range_color(60, 100, QColor(227, 254, 227));
86 m_writeBufferStatus->setMinimumWidth(60);
87
88 m_readBufferStatus->set_range(0, 100);
89 m_readBufferStatus->add_range_color(0, 40, QColor(255, 0, 0));
90 m_readBufferStatus->add_range_color(40, 60, QColor(255, 255, 0));
91 m_readBufferStatus->add_range_color(60, 100, QColor(227, 254, 227));
92 m_readBufferStatus->setMinimumWidth(60);
93
94 m_cpuUsage->set_range(0, 100);
95 m_cpuUsage->set_int_rounding(false);
96 m_cpuUsage->setMinimumWidth(90);
97 m_cpuUsage->add_range_color(0, 60, QColor(227, 254, 227));
98 m_cpuUsage->add_range_color(60, 75, QColor(255, 255, 0));
99 m_cpuUsage->add_range_color(75, 100, QColor(255, 0, 0));
100
101 m_readBufferStatus->set_text("R");
102 m_writeBufferStatus->set_text("W");
103 m_cpuUsage->set_text("CPU");
104
105 QHBoxLayout* lay = new QHBoxLayout(this);
106 lay->addSpacing(6);
107 lay->addWidget(m_readBufferStatus);
108 lay->addWidget(m_icon);
109 lay->addWidget(m_writeBufferStatus);
110 lay->addWidget(m_cpuUsage);
111 lay->setMargin(0);
112 lay->addSpacing(6);
113 setLayout(lay);
114 setFrameStyle(QFrame::NoFrame);
115
116 connect(&m_updateTimer, SIGNAL(timeout()), this, SLOT(update_status()));
117
118 update_status();
119
120 m_updateTimer.start(1200);
121 }
122
update_status()123 void SystemResources::update_status( )
124 {
125 float time = audiodevice().get_cpu_time();
126 int bufReadStatus = 100;
127 int bufWriteStatus = 100;
128
129 if (m_project) {
130 foreach(Sheet* sheet, m_project->get_sheets() ) {
131 bufReadStatus = std::min(sheet->get_diskio()->get_read_buffers_fill_status(), bufReadStatus);
132 bufWriteStatus = std::min(sheet->get_diskio()->get_write_buffers_fill_status(), bufWriteStatus);
133 time += sheet->get_diskio()->get_cpu_time();
134 }
135 }
136
137
138 m_readBufferStatus->set_value(bufReadStatus);
139 m_writeBufferStatus->set_value(bufWriteStatus);
140 m_cpuUsage->set_value(time);
141 }
142
143
sizeHint() const144 QSize SystemResources::sizeHint() const
145 {
146 return QSize(250, SONG_TOOLBAR_HEIGHT);
147 }
148
149
150
DriverInfo(QWidget * parent)151 DriverInfo::DriverInfo( QWidget * parent )
152 : InfoWidget(parent)
153 {
154 m_driver = new QPushButton();
155 m_driver->setIcon(find_pixmap(":/driver"));
156 m_driver->setToolTip(tr("Change Audio Device settings"));
157 m_driver->setFlat(true);
158 m_driver->setFocusPolicy(Qt::NoFocus);
159
160 QHBoxLayout* lay = new QHBoxLayout(this);
161 lay->addWidget(m_driver);
162 lay->setMargin(0);
163 setLayout(lay);
164
165 setFrameStyle(QFrame::NoFrame);
166
167 connect(&audiodevice(), SIGNAL(driverParamsChanged()), this, SLOT(update_driver_info()));
168 connect(&audiodevice(), SIGNAL(bufferUnderRun()), this, SLOT(update_xrun_info()));
169 connect(m_driver, SIGNAL(clicked( bool )), this, SLOT(show_driver_config_dialog()));
170
171 update_driver_info();
172 }
173
update_driver_info()174 void DriverInfo::update_driver_info( )
175 {
176 xrunCount = 0;
177 draw_information();
178 }
179
draw_information()180 void DriverInfo::draw_information( )
181 {
182 QString text;
183 QString latency = QString::number( ( (float) (audiodevice().get_buffer_size() * 2) / audiodevice().get_sample_rate() ) * 1000, 'f', 2 ).append(" ms ");
184
185 QByteArray xruns;
186 if (xrunCount) {
187 xruns = QByteArray::number(xrunCount).prepend(" xruns ");
188 }
189
190 text = audiodevice().get_driver_type() + " " +
191 QString::number(audiodevice().get_sample_rate()) +
192 "/" +
193 QString::number(audiodevice().get_bit_depth()) +
194 " @ " + latency +
195 xruns;
196
197 m_driver->setText(text);
198 updateGeometry();
199 }
200
update_xrun_info()201 void DriverInfo::update_xrun_info( )
202 {
203 xrunCount++;
204 draw_information();
205 }
206
sizeHint() const207 QSize DriverInfo::sizeHint() const
208 {
209 return QSize(m_driver->width(), SONG_TOOLBAR_HEIGHT);
210 }
211
enterEvent(QEvent * event)212 void DriverInfo::enterEvent(QEvent * event)
213 {
214 m_driver->setFlat(false);
215 }
216
leaveEvent(QEvent * event)217 void DriverInfo::leaveEvent(QEvent * event)
218 {
219 m_driver->setFlat(true);
220 }
221
222
show_driver_config_dialog()223 void DriverInfo::show_driver_config_dialog( )
224 {
225 Interface::instance()->show_settings_dialog_sound_system_page();
226 }
227
228
229
HDDSpaceInfo(QWidget * parent)230 HDDSpaceInfo::HDDSpaceInfo(QWidget* parent )
231 : InfoWidget(parent)
232 {
233 m_button = new QPushButton;
234 m_button->setIcon(find_pixmap(":/harddrivesmall"));
235 m_button->setFlat(true);
236 m_button->setFocusPolicy(Qt::NoFocus);
237 m_button->setEnabled(false);
238
239 QHBoxLayout* lay = new QHBoxLayout;
240 lay->setMargin(0);
241 lay->addWidget(m_button);
242 setLayout(lay);
243
244 setFrameStyle(QFrame::NoFrame);
245
246 connect(&updateTimer, SIGNAL(timeout()), this, SLOT(update_status()));
247
248 update_status();
249 updateTimer.start(20000);
250 }
251
252
set_sheet(Sheet * sheet)253 void HDDSpaceInfo::set_sheet(Sheet* sheet)
254 {
255 m_sheet = sheet;
256
257 if (! m_sheet) {
258 updateTimer.start(20000);
259 return;
260 }
261
262 update_status();
263
264 connect(m_sheet, SIGNAL(transportStopped()), this, SLOT(sheet_stopped()));
265 connect(m_sheet, SIGNAL(transportStarted()), this, SLOT(sheet_started()));
266 }
267
sheet_started()268 void HDDSpaceInfo::sheet_started()
269 {
270 updateTimer.start(5000);
271 m_button->setEnabled(true);
272 update_status();
273 }
274
sheet_stopped()275 void HDDSpaceInfo::sheet_stopped()
276 {
277 updateTimer.start(60000);
278 m_button->setEnabled(false);
279 update_status();
280 }
281
282
283
update_status()284 void HDDSpaceInfo::update_status( )
285 {
286 if (!m_project) {
287 m_button->setText("No Info");
288 return;
289 }
290
291 double space = 0.0;
292
293 #if defined (Q_WS_WIN)
294 __int64 freebytestocaller, totalbytes, freebytes;
295 if (! GetDiskFreeSpaceEx ((const CHAR*)(QS_C(m_project->get_root_dir())),
296 (PULARGE_INTEGER)&freebytestocaller,
297 (PULARGE_INTEGER)&totalbytes,
298 (PULARGE_INTEGER)&freebytes))
299 {
300 // info().warning("HHDSpaceInfo: " + QString().sprintf("error: %lu", GetLastError()));
301 m_button->setText("No Info");
302 return;
303 }
304
305 space = double(freebytestocaller / (1 << 20));
306 #else
307
308 #if !defined(HAVE_SYS_VFS_H)
309 m_button->setText("No Info");
310 return;
311 #else
312
313 struct statfs fs;
314 statfs(QS_C(m_project->get_root_dir()), &fs);
315 space = floor (fs.f_bavail * (fs.f_bsize / 1048576.0));
316 #endif
317 #endif
318
319 QList<Sheet*> recordingSheets;
320 foreach(Sheet* sheet, m_project->get_sheets()) {
321 if (sheet->is_recording() && sheet->any_track_armed()) {
322 recordingSheets.append(sheet);
323 }
324 }
325
326 QString text;
327
328 if (recordingSheets.size()) {
329 int recChannelCount = 0;
330 foreach(Sheet* sheet, recordingSheets) {
331 foreach(Track* track, sheet->get_tracks()) {
332 if (track->armed()) {
333 recChannelCount += track->capture_left_channel() ? 1 : 0;
334 recChannelCount += track->capture_right_channel() ? 1 : 0;
335 }
336 }
337 }
338
339 uint rate = audiodevice().get_sample_rate();
340 double availabletime = (double(UNIVERSAL_SAMPLE_RATE) / rate) * space * 1048576.0;
341 availabletime /= double(sizeof(float) * recChannelCount);
342
343 QString recordFormat = config().get_property("Recording", "FileFormat", "wav").toString();
344 // I think a compression ratio of 40 % with wavpack is a safe estimation
345 // and 50% with skipwvx...
346 if (recordFormat == "wavpack") {
347 QString skipwvx = config().get_property("Recording", "WavpackSkipWVX", "false").toString();
348 if (skipwvx == "true") {
349 availabletime = qint64(availabletime / 0.5);
350 } else {
351 availabletime = qint64(availabletime / 0.6);
352 }
353 }
354
355 TimeRef time(availabletime);
356 text = timeref_to_hms(time);
357 if (text < "00:30:00") {
358 QPalette pal;
359 pal.setColor(QPalette::ButtonText, QColor(Qt::red));
360 m_button->setPalette(pal);
361 }
362 } else {
363 if (space > 9216) {
364 text.setNum((space/1024), 'f', 2);
365 text.append(" GB");
366 } else {
367 text.setNum(space, 'f', 0);
368 text.append(" MB");
369 }
370 }
371
372 m_button->setText(text);
373 }
374
sizeHint() const375 QSize HDDSpaceInfo::sizeHint() const
376 {
377 return QSize(90, SONG_TOOLBAR_HEIGHT);
378 }
379
380
381
382
383
384
InfoWidget(QWidget * parent)385 InfoWidget::InfoWidget(QWidget* parent)
386 : QFrame(parent)
387 , m_sheet(0)
388 , m_project(0)
389 {
390 setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
391 connect(&pm(), SIGNAL(projectLoaded(Project*)), this, SLOT(set_project(Project*)));
392
393 setFocusPolicy(Qt::NoFocus);
394 }
395
396
set_project(Project * project)397 void InfoWidget::set_project(Project* project )
398 {
399 m_project = project;
400 if (m_project) {
401 connect(m_project, SIGNAL(currentSheetChanged(Sheet*)), this, SLOT(set_sheet(Sheet*)));
402 } else {
403 set_sheet(0);
404 }
405 }
406
set_sheet(Sheet * sheet)407 void InfoWidget::set_sheet(Sheet* sheet)
408 {
409 m_sheet = sheet;
410 }
411
412
SysInfoToolBar(QWidget * parent)413 SysInfoToolBar::SysInfoToolBar(QWidget * parent)
414 : QToolBar(parent)
415 {
416 setObjectName(tr("System Information"));
417 message = new MessageWidget(this);
418 resourcesInfo = new SystemResources(this);
419 hddInfo = new HDDSpaceInfo(this);
420 driverInfo = new DriverInfo(this);
421
422 setMovable(false);
423
424 QAction* action;
425
426 action = addWidget(driverInfo);
427 action->setVisible(true);
428 addSeparator();
429 action = addWidget(resourcesInfo);
430 action->setVisible(true);
431 addSeparator();
432 action = addWidget(hddInfo);
433 action->setVisible(true);
434 addSeparator();
435 action = addWidget(message);
436 action->setVisible(true);
437 }
438
SystemValueBar(QWidget * parent)439 SystemValueBar::SystemValueBar(QWidget * parent)
440 : QWidget(parent)
441 {
442 m_current = m_min = m_max = 0;
443 m_text = "";
444 m_introunding = true;
445 }
446
set_value(float value)447 void SystemValueBar::set_value(float value)
448 {
449 if (m_current == value) {
450 return;
451 }
452
453 m_current = value;
454
455 if (m_current > m_max) {
456 m_current = m_max;
457 }
458
459 if (m_current < m_min) {
460 m_current = m_min;
461 }
462
463 update();
464 }
465
set_range(float min,float max)466 void SystemValueBar::set_range(float min, float max)
467 {
468 m_min = min;
469 m_max = max;
470 update();
471 }
472
set_text(const QString & text)473 void SystemValueBar::set_text(const QString & text)
474 {
475 m_text = text;
476 }
477
paintEvent(QPaintEvent *)478 void SystemValueBar::paintEvent(QPaintEvent* )
479 {
480 QPainter painter(this);
481 painter.setRenderHints(QPainter::Antialiasing);
482
483 QColor color = QColor(227, 254, 227);
484
485 for (int i=0; i<m_rangecolors.size(); ++i) {
486 RangeColor range = m_rangecolors.at(i);
487 if (m_current <= range.x1 && m_current >= range.x0) {
488 color = range.color;
489 break;
490 }
491 }
492
493 QRect rect = QRect(0, (height() - 15) / 2, width(), 15);
494 painter.drawRect(rect);
495
496 painter.setBrush(color);
497 painter.setPen(Qt::NoPen);
498 float scalefactor = width() / m_max;
499 rect = QRect(1, (height() - 15) / 2 + 1, width() - 2 - (int)(scalefactor* (m_max - m_current)), 13);
500 painter.drawRect(rect);
501
502 painter.setPen(Qt::black);
503 painter.setFont(themer()->get_font("InfoWidget:fontscale:values"));
504
505 if (m_introunding) {
506 painter.drawText(0, 0, width(), height(), Qt::AlignCenter,
507 m_text + " " + QString::number((int)m_current).append("%"));
508 } else {
509 painter.drawText(0, 0, width(), height(), Qt::AlignCenter,
510 m_text + " " + QString::number(m_current, 'f', 2).append("%"));
511 }
512 }
513
sizeHint() const514 QSize SystemValueBar::sizeHint() const
515 {
516 return QSize(60, 25);
517 }
518
set_int_rounding(bool rounding)519 void SystemValueBar::set_int_rounding(bool rounding)
520 {
521 m_introunding = rounding;
522 }
523
add_range_color(float x0,float x1,QColor color)524 void SystemValueBar::add_range_color(float x0, float x1, QColor color)
525 {
526 RangeColor range;
527 range.x0 = x0;
528 range.x1 = x1;
529 range.color = color;
530 m_rangecolors.append(range);
531 }
532
ProgressToolBar(QWidget * parent)533 ProgressToolBar::ProgressToolBar(QWidget* parent)
534 : QToolBar(tr("Progress Toolbar"), parent)
535 {
536 m_progressBar = new QProgressBar(this);
537 m_progressBar->setMinimumWidth(800);
538 addWidget(m_progressBar);
539 m_progressBar->setEnabled(false);
540 filecount = 1;
541 filenum = 1;
542
543 QString style = "QProgressBar {border: 2px solid grey;border-radius: 5px; height: 10px; width 300px; text-align: center;}"
544 "QProgressBar::chunk {background-color: qlineargradient(x1: 0, y1: 0, x2: 1.0, y2: 1.0,stop: 0 white, stop: 1 navy);}";
545
546 m_progressBar->setStyleSheet(style);
547 }
548
~ProgressToolBar()549 ProgressToolBar::~ProgressToolBar()
550 {
551 }
552
set_progress(int i)553 void ProgressToolBar::set_progress(int i)
554 {
555 if (i == m_progressBar->maximum()) {
556 if (filenum == filecount) {
557 hide();
558 m_progressBar->reset();
559 m_progressBar->setEnabled(false);
560 return;
561 } else {
562 ++filenum;
563 }
564 }
565
566 if (!m_progressBar->isEnabled()) {
567 m_progressBar->setEnabled(true);
568 show();
569 }
570
571 m_progressBar->setValue(i);
572 }
573
set_label(QString s)574 void ProgressToolBar::set_label(QString s)
575 {
576 Q_UNUSED(s);
577 m_progressBar->setFormat(tr("Importing file %1 of %2: %p%").arg(filenum).arg(filecount));
578 }
579
set_num_files(int i)580 void ProgressToolBar::set_num_files(int i)
581 {
582 filecount = i;
583 filenum = 1;
584 }
585
586 //eof
587