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