1 /*************************************************************************
2        RecordDialog.cpp  -  dialog window for controlling audio recording
3                              -------------------
4     begin                : Wed Aug 20 2003
5     copyright            : (C) 2003 by Thomas Eschenbacher
6     email                : Thomas.Eschenbacher@gmx.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "config.h"
19 
20 #include <new>
21 
22 #include <QCheckBox>
23 #include <QDateTimeEdit>
24 #include <QGroupBox>
25 #include <QIcon>
26 #include <QLabel>
27 #include <QLatin1Char>
28 #include <QPixmap>
29 #include <QPointer>
30 #include <QProgressBar>
31 #include <QPushButton>
32 #include <QSlider>
33 #include <QSpinBox>
34 #include <QStatusBar>
35 #include <QTabWidget>
36 #include <QTreeView>
37 #include <QTreeWidget>
38 #include <QTreeWidgetItem>
39 #include <QVector>
40 
41 #include <KComboBox>
42 #include <KHelpClient>
43 #include <KLocalizedString>
44 #include <KIconLoader>
45 #include <KIconTheme>
46 
47 #include "libkwave/Compression.h"
48 #include "libkwave/SampleFormat.h"
49 #include "libkwave/String.h"
50 #include "libkwave/Utils.h"
51 
52 #include "libgui/FileDialog.h"
53 #include "libgui/HMSTimeWidget.h"
54 
55 #include "LevelMeter.h"
56 #include "RecordDevice.h"
57 #include "RecordDialog.h"
58 #include "RecordParams.h"
59 #include "RecordState.h"
60 
61 // status bar icons
62 #include "ledgreen.xpm"
63 #include "ledlightgreen.xpm"
64 #include "ledred.xpm"
65 #include "ledyellow.xpm"
66 #include "ok.xpm"
67 #include "stop_hand.xpm"
68 #include "walk_r1.xpm"
69 #include "walk_r2.xpm"
70 #include "walk_r3.xpm"
71 #include "walk_r4.xpm"
72 #include "walk_r5.xpm"
73 #include "walk_r6.xpm"
74 #include "walk_r7.xpm"
75 #include "walk_r8.xpm"
76 
77 /* some macros, for laziness ;-) */
78 #define SETUP(enabled,property,check,value) \
79 	check->setChecked(m_params.enabled); \
80 	value->setValue(m_params.property); \
81 
82 #define STD_SETUP(enabled,property,control) \
83 	SETUP(enabled,property,chk##control,sb##control); \
84 	sb##control->setEnabled(chk##control->isEnabled() && \
85 	                        chk##control->isChecked());
86 
87 #define STD_SETUP_SLIDER(enabled,property,control) \
88 	STD_SETUP(enabled,property,control); \
89 	sl##control->setEnabled(sb##control->isEnabled());
90 
91 //***************************************************************************
RecordDialog(QWidget * parent,QStringList & params,Kwave::RecordController * controller,Kwave::RecordDialog::Mode mode)92 Kwave::RecordDialog::RecordDialog(QWidget *parent, QStringList &params,
93                                   Kwave::RecordController *controller,
94                                   Kwave::RecordDialog::Mode mode)
95     :QDialog(parent), Ui::RecordDlg(), m_methods_map(),
96      m_file_filter(), m_devices_list_map(),
97      m_state(Kwave::REC_EMPTY), m_params(),
98      m_supported_resolutions(), m_buffer_progress_count(0),
99      m_buffer_progress_total(0), m_buffer_progress_timer(this),
100      m_record_enabled(true), m_samples_recorded(0),
101      m_enable_setDevice(true), m_state_icon_widget(Q_NULLPTR)
102 {
103     m_status_bar.m_state           = Q_NULLPTR;
104     m_status_bar.m_time            = Q_NULLPTR;
105     m_status_bar.m_sample_rate     = Q_NULLPTR;
106     m_status_bar.m_bits_per_sample = Q_NULLPTR;
107     m_status_bar.m_tracks          = Q_NULLPTR;
108 
109     setupUi(this);
110 
111     /* get initial parameters */
112     m_params.fromList(params);
113 
114     /* set the icons of the record control buttons */
115     btNew->setIcon(   QIcon::fromTheme(_("document-new")));
116     btStop->setIcon(  QIcon::fromTheme(_("kwave_player_stop")));
117     btPause->setIcon( QIcon::fromTheme(_("kwave_player_pause")));
118     btRecord->setIcon(QIcon::fromTheme(_("kwave_player_record")));
119 
120     // fill the combo box with playback methods
121     unsigned int index=0;
122     for (index = 0; index < m_methods_map.count(); ++index) {
123 	cbMethod->addItem(m_methods_map.description(index, true));
124     }
125     cbMethod->setEnabled(cbMethod->count() > 1);
126 
127     /* --- set up all controls with their default/startup values --- */
128 
129     // pre-record
130     STD_SETUP_SLIDER(pre_record_enabled, pre_record_time, RecordPre)
131     connect(chkRecordPre, SIGNAL(toggled(bool)),
132             this,         SLOT(preRecordingChecked(bool)));
133     connect(sbRecordPre,  SIGNAL(valueChanged(int)),
134             this,         SLOT(preRecordingTimeChanged(int)));
135 
136     // record time (duration)
137     STD_SETUP(record_time_limited, record_time, RecordTime)
138 
139     // start time (date & time)
140     chkRecordStartTime->setChecked(m_params.start_time_enabled);
141     startTime->setDateTime(m_params.start_time);
142 
143     // record trigger
144     STD_SETUP_SLIDER(record_trigger_enabled, record_trigger, RecordTrigger)
145 
146     // amplification
147     STD_SETUP_SLIDER(amplification_enabled, amplification, LevelAmplify)
148 
149     // AGC
150     STD_SETUP_SLIDER(agc_enabled, agc_decay, LevelAGC)
151 
152     // fade in
153     STD_SETUP(fade_in_enabled, fade_in_time, LevelFadeIn)
154 
155     // fade out
156     STD_SETUP(fade_out_enabled, fade_out_time, LevelFadeOut)
157 
158     // sample rate, bits per sample, track
159     // -> will be initialized later, by the plugin
160 
161     // number of buffers
162     slSourceBufferCount->setValue(m_params.buffer_count);
163 
164     // power of buffer size
165     slSourceBufferSize->setValue(m_params.buffer_size);
166     sourceBufferSizeChanged(m_params.buffer_size);
167 
168     // after this point all controls have their initial values
169 
170     /* --- connect some missing low level GUI functionality --- */
171 
172     connect(cbMethod, SIGNAL(activated(int)),
173             this, SLOT(methodSelected(int)));
174 
175     // record buffer size and count
176     slSourceBufferCount->setValue(m_params.buffer_count);
177     slSourceBufferSize->setValue(m_params.buffer_size);
178     connect(slSourceBufferSize, SIGNAL(valueChanged(int)),
179             this, SLOT(sourceBufferSizeChanged(int)));
180     connect(slSourceBufferCount, SIGNAL(valueChanged(int)),
181             this, SLOT(sourceBufferCountChanged(int)));
182 
183     // device treeview
184     connect(listDevices,
185             SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)),
186             SLOT(listEntrySelected(QTreeWidgetItem*,QTreeWidgetItem*)));
187     connect(listDevices, SIGNAL(itemExpanded(QTreeWidgetItem*)),
188             SLOT(listItemExpanded(QTreeWidgetItem*)));
189     connect(listDevices, SIGNAL(focusLost()),
190             SLOT(updateListSelection()));
191 
192     // "select device..." button
193     connect(btSourceSelect, SIGNAL(clicked()),
194             this, SLOT(selectRecordDevice()));
195     connect(cbDevice, SIGNAL(activated(QString)),
196             this, SLOT(setDevice(QString)));
197 
198     // setup controls
199     connect(chkRecordTime, SIGNAL(toggled(bool)),
200             this, SLOT(recordTimeChecked(bool)));
201     connect(sbRecordTime, SIGNAL(valueChanged(int)),
202             this, SLOT(recordTimeChanged(int)));
203 
204     connect(chkRecordStartTime, SIGNAL(toggled(bool)),
205             this, SLOT(startTimeChecked(bool)));
206     connect(startTime, SIGNAL(dateTimeChanged(QDateTime)),
207             this, SLOT(startTimeChanged(QDateTime)));
208 
209     connect(chkRecordTrigger, SIGNAL(toggled(bool)),
210             this, SLOT(triggerChecked(bool)));
211     connect(sbRecordTrigger, SIGNAL(valueChanged(int)),
212             this, SLOT(triggerChanged(int)));
213 
214     connect(cbFormatSampleRate, SIGNAL(editTextChanged(QString)),
215             this, SLOT(sampleRateChanged(QString)));
216     connect(cbFormatSampleRate, SIGNAL(activated(QString)),
217             this, SLOT(sampleRateChanged(QString)));
218 
219     connect(sbFormatTracks, SIGNAL(valueChanged(int)),
220             this, SLOT(tracksChanged(int)));
221 
222     connect(cbFormatCompression, SIGNAL(activated(int)),
223             this, SLOT(compressionChanged(int)));
224 
225     connect(sbFormatResolution, SIGNAL(valueChanged(int)),
226             this, SLOT(bitsPerSampleChanged(int)));
227 
228     connect(cbFormatSampleFormat, SIGNAL(activated(int)),
229             this, SLOT(sampleFormatChanged(int)));
230 
231     // connect the buttons to the record controller
232     connect(btNew, SIGNAL(clicked()),
233             controller, SLOT(actionReset()));
234     connect(btStop, SIGNAL(clicked()),
235             controller, SLOT(actionStop()));
236     connect(btPause, SIGNAL(clicked()),
237             controller, SLOT(actionPause()));
238     connect(btRecord, SIGNAL(clicked()),
239             controller, SLOT(actionStart()));
240 
241     // stop recording when the window gets closed
242     connect(this, SIGNAL(rejected()), controller, SLOT(actionStop()));
243     connect(this, SIGNAL(accepted()), controller, SLOT(actionStop()));
244 
245     // connect the notifications/commands of the record controller
246     connect(controller, SIGNAL(stateChanged(Kwave::RecordState)),
247             this, SLOT(setState(Kwave::RecordState)));
248 
249     // timer for updating the buffer progress bar
250     connect(&m_buffer_progress_timer, SIGNAL(timeout()),
251             this, SLOT(updateBufferProgressBar()));
252 
253     // help button
254     connect(buttonBox->button(QDialogButtonBox::Help), SIGNAL(clicked()),
255             this,   SLOT(invokeHelp()));
256 
257     // status bar
258     m_state_icon_widget = new(std::nothrow) Kwave::StatusWidget(this);
259     Q_ASSERT(m_state_icon_widget);
260     if (!m_state_icon_widget) return;
261 
262     m_state_icon_widget->setFixedSize(16, 16);
263     lbl_state->addWidget(m_state_icon_widget);
264 
265     m_status_bar.m_state = new(std::nothrow) QLabel(_(" "));
266     Q_ASSERT(m_status_bar.m_state);
267     if (!m_status_bar.m_state) return;
268     m_status_bar.m_state->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
269     lbl_state->addWidget(m_status_bar.m_state);
270 
271     m_status_bar.m_time = new(std::nothrow) QLabel(_(" "));
272     Q_ASSERT(m_status_bar.m_time);
273     if (!m_status_bar.m_time) return;
274     m_status_bar.m_time->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
275     lbl_state->addWidget(m_status_bar.m_time);
276 
277     m_status_bar.m_sample_rate = new(std::nothrow) QLabel(_(" "));
278     Q_ASSERT(m_status_bar.m_sample_rate);
279     if (!m_status_bar.m_sample_rate) return;
280     m_status_bar.m_sample_rate->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
281     lbl_state->addWidget(m_status_bar.m_sample_rate);
282 
283     m_status_bar.m_bits_per_sample = new(std::nothrow) QLabel(_(" "));
284     Q_ASSERT(m_status_bar.m_bits_per_sample);
285     if (!m_status_bar.m_bits_per_sample) return;
286     m_status_bar.m_bits_per_sample->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
287     lbl_state->addWidget(m_status_bar.m_bits_per_sample);
288 
289     m_status_bar.m_tracks = new(std::nothrow) QLabel(_(" "));
290     Q_ASSERT(m_status_bar.m_tracks);
291     if (!m_status_bar.m_tracks) return;
292     m_status_bar.m_tracks->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
293     lbl_state->addWidget(m_status_bar.m_tracks);
294 
295     m_state_icon_widget->setFixedSize(16, lbl_state->childrenRect().height());
296 
297     // set the initial state of the dialog to "Reset/Empty"
298     setState(Kwave::REC_EMPTY);
299 
300     // disable the "level" tab, it is not implemented yet
301     tabRecord->setCurrentIndex(1);
302     QWidget *page = tabRecord->currentWidget();
303     tabRecord->setCurrentIndex(0);
304     if (page) delete page;
305 
306     // add the "Done" button manually, otherwise it would have "Cancel" semantic
307     QPushButton *bt_done =
308 	buttonBox->addButton(i18n("&Done"), QDialogButtonBox::AcceptRole);
309     Q_ASSERT(bt_done);
310     if (!bt_done) return;
311     connect(bt_done, SIGNAL(clicked(bool)), this, SLOT(accept()));
312 
313     switch (mode)
314     {
315 	case Kwave::RecordDialog::SETTINGS_FORMAT:
316 	    tabRecord->setCurrentIndex(1);
317 	    break;
318 	case Kwave::RecordDialog::SETTINGS_SOURCE:
319 	    tabRecord->setCurrentIndex(2);
320 	    break;
321 	case Kwave::RecordDialog::START_RECORDING:  /* FALLTHROUGH */
322 	case Kwave::RecordDialog::SETTINGS_DEFAULT: /* FALLTHROUGH */
323 	default:
324 	    tabRecord->setCurrentIndex(0);
325 	    // set the focus onto the "Record" button
326 	    btRecord->setFocus();
327 	    break;
328     }
329 }
330 
331 //***************************************************************************
~RecordDialog()332 Kwave::RecordDialog::~RecordDialog()
333 {
334     updateBufferState(0,0);
335 }
336 
337 //***************************************************************************
params()338 Kwave::RecordParams &Kwave::RecordDialog::params()
339 {
340     return m_params;
341 }
342 
343 //***************************************************************************
setMethod(Kwave::record_method_t method)344 void Kwave::RecordDialog::setMethod(Kwave::record_method_t method)
345 {
346     m_params.method = method;
347     cbMethod->setCurrentIndex(m_methods_map.findFromData(
348         m_params.method));
349 }
350 
351 //***************************************************************************
methodSelected(int index)352 void Kwave::RecordDialog::methodSelected(int index)
353 {
354     Kwave::record_method_t method = m_methods_map.data(index);
355 //     qDebug("RecordDialog::methodSelected(%d) - %d", index, (int)method);
356 
357     Q_ASSERT(method > Kwave::RECORD_NONE);
358     Q_ASSERT(method < Kwave::RECORD_INVALID);
359     if (method <= Kwave::RECORD_NONE) return;
360     if (method >= Kwave::RECORD_INVALID) return;
361 
362     if (method != m_params.method) {
363 	setMethod(method);
364 	emit sigMethodChanged(method);
365     }
366 }
367 
368 //***************************************************************************
setSupportedDevices(QStringList devices)369 void Kwave::RecordDialog::setSupportedDevices(QStringList devices)
370 {
371 //     qDebug("RecordDialog::setSupportedDevices(QStringList devices)");
372     Q_ASSERT(cbDevice);
373     Q_ASSERT(listDevices);
374     if (!cbDevice || !listDevices) return;
375     QString current_device = m_params.device_name;
376 
377     // disable all that noisy stuff that comes from modifying the
378     // device controls...
379     m_enable_setDevice = false;
380 
381     KIconLoader *icon_loader = KIconLoader::global();
382 
383     cbDevice->clearEditText();
384     cbDevice->clear();
385     listDevices->clear();
386 
387     if (devices.contains(_("#EDIT#"))) {
388 	devices.removeAll(_("#EDIT#"));
389 	cbDevice->setEditable(true);
390     } else {
391 	cbDevice->setEditable(false);
392     }
393 
394     if (devices.contains(_("#SELECT#"))) {
395 	devices.removeAll(_("#SELECT#"));
396 	btSourceSelect->setEnabled(true);
397 	btSourceSelect->show();
398     } else {
399 	btSourceSelect->setEnabled(false);
400 	btSourceSelect->hide();
401     }
402 
403     if (devices.contains(_("#TREE#"))) {
404 	// treeview mode
405 	devices.removeAll(_("#TREE#"));
406 	listDevices->setEnabled(true);
407 	cbDevice->setEnabled(false);
408 	cbDevice->hide();
409 	m_devices_list_map.clear();
410 
411 	// build a tree with all nodes in the list
412 	foreach (QString dev_id, devices) {
413             QTreeWidgetItem *parent = Q_NULLPTR;
414 
415 	    QStringList list = dev_id.split(_("||"), Qt::KeepEmptyParts);
416 	    foreach (QString token, list) {
417                 QTreeWidgetItem *item = Q_NULLPTR;
418 
419 		// split the icon name from the token
420 		QString icon_name;
421 		int pos = token.indexOf(QLatin1Char('|'));
422 		if (pos > 0) {
423 		    icon_name = token.mid(pos+1);
424 		    token     = token.left(pos);
425 		}
426 
427 		// find the first item with the same text
428 		// and the same root
429 		if (parent) {
430 		    for (int i = 0; i < parent->childCount(); i++) {
431 			QTreeWidgetItem *node = parent->child(i);
432 			if (node && node->text(0) == token) {
433 			    item = node;
434 			    break;
435 			}
436 		    }
437 		} else {
438 		    QList<QTreeWidgetItem *> matches =
439 			listDevices->findItems(token, Qt::MatchExactly);
440 		    if (matches.count())
441 			item = matches.takeFirst();
442 		}
443 
444 		if (item) {
445 		    // already in the list
446 		    parent = item;
447 		} else if (parent) {
448 		    // new leaf, add to the parent
449 		    item = new(std::nothrow) QTreeWidgetItem(parent);
450 		    Q_ASSERT(item);
451 		    if (item) {
452 			item->setText(0, token);
453 			m_devices_list_map.insert(item, dev_id);
454 		    }
455 
456 		    parent->setExpanded(true);
457 		    parent->setFlags(parent->flags() &
458 			~(Qt::ItemIsUserCheckable | Qt::ItemIsSelectable));
459 		    if (m_devices_list_map.contains(parent)) {
460 			// make the parent not selectable
461 			m_devices_list_map.remove(parent);
462 		    }
463 		} else {
464 		    // new root node
465 		    item = new(std::nothrow) QTreeWidgetItem(listDevices);
466 		    Q_ASSERT(item);
467 		    if (item) {
468 			item->setText(0, token);
469 			m_devices_list_map.insert(item, dev_id);
470 		    }
471 		}
472 
473 		if (item && icon_name.length() && icon_loader) {
474 		    QIcon icon = icon_loader->loadIcon(
475 			icon_name, KIconLoader::User);
476 		    item->setIcon(0, icon);
477 		}
478 
479 		// use the current item as parent for the next pass
480 		parent = item;
481 	    }
482 	}
483     } else {
484 	// combo box mode
485 	cbDevice->addItems(devices);
486 	cbDevice->show();
487 	listDevices->setEnabled(false);
488 
489 	if (devices.contains(current_device)) {
490 	    // current device is in the list
491 	    cbDevice->setCurrentIndex(cbDevice->findText(current_device));
492 	} else {
493 	    if (cbDevice->isEditable() && current_device.length()) {
494 		// user defined device name
495 		cbDevice->setEditText(current_device);
496 	    } else if (devices.count()) {
497 		// one or more other possibilities -> take the first one
498 		cbDevice->setCurrentIndex(0);
499 	    } else {
500 		// empty list of possibilities
501 		cbDevice->clearEditText();
502 		cbDevice->clear();
503 	    }
504 	}
505 	cbDevice->setEnabled(devices.count() > 1);
506     }
507 
508     // enable changes in the device controls again
509     m_enable_setDevice = true;
510 }
511 
512 //***************************************************************************
listEntrySelected(QTreeWidgetItem * current,QTreeWidgetItem * previous)513 void Kwave::RecordDialog::listEntrySelected(QTreeWidgetItem *current,
514                                             QTreeWidgetItem *previous)
515 {
516     Q_ASSERT(listDevices);
517     Q_UNUSED(previous)
518     if (!current || !listDevices) return;
519 
520     if (m_devices_list_map.contains(current))
521 	setDevice(m_devices_list_map[current]);
522 }
523 
524 //***************************************************************************
listItemExpanded(QTreeWidgetItem * item)525 void Kwave::RecordDialog::listItemExpanded(QTreeWidgetItem *item)
526 {
527     Q_UNUSED(item)
528     updateListSelection();
529 }
530 
531 //***************************************************************************
updateListSelection()532 void Kwave::RecordDialog::updateListSelection()
533 {
534     // set the current device again, otherwise nothing will be selected
535     setDevice(m_params.device_name);
536 }
537 
538 //***************************************************************************
setDevice(const QString & device)539 void Kwave::RecordDialog::setDevice(const QString &device)
540 {
541     Q_ASSERT(cbDevice);
542     Q_ASSERT(listDevices);
543     if (!cbDevice || !listDevices) return;
544 
545     bool device_changed = (device != m_params.device_name);
546     m_params.device_name = device;
547 //     qDebug("RecordDialog::setDevice(%s)", device.local8Bit().data());
548 
549     if (listDevices->isEnabled()) {
550 	// treeview mode
551         QTreeWidgetItem *node = m_devices_list_map.key(device, Q_NULLPTR);
552 	if (node) {
553 	    node->setSelected(true);
554 	    listDevices->scrollToItem(node);
555 	    listDevices->setCurrentItem(node);
556 	}
557     } else if (cbDevice->isEditable() && device.length()) {
558 	// user defined device name
559 	if (!device.isEmpty() && (cbDevice->currentText() != device)) {
560 	    cbDevice->setCurrentIndex(cbDevice->findText(device));
561 	    cbDevice->setEditText(device);
562 	}
563     } else {
564 	// just take one from the list
565 	if (cbDevice->findText(device) >= 0) {
566 	    cbDevice->setCurrentIndex(cbDevice->findText(device));
567 	} else if (cbDevice->count()) {
568 	    cbDevice->setCurrentIndex(0);
569 	}
570     }
571 
572     if (device_changed) emit sigDeviceChanged(device);
573 }
574 
575 //***************************************************************************
sourceBufferCountChanged(int value)576 void Kwave::RecordDialog::sourceBufferCountChanged(int value)
577 {
578     Q_ASSERT(value >=  4);
579     Q_ASSERT(value <= 64);
580     if (value < 4)  value = 4;
581     if (value > 64) value = 64;
582 
583     // take the value into our struct
584     m_params.buffer_count = value;
585     emit sigBuffersChanged();
586 }
587 
588 //***************************************************************************
sourceBufferSizeChanged(int value)589 void Kwave::RecordDialog::sourceBufferSizeChanged(int value)
590 {
591     Q_ASSERT(value >= 10);
592     Q_ASSERT(value <= 18);
593     if (value < 10) value = 10;
594     if (value > 18) value = 18;
595 
596     // take the value into our struct
597     m_params.buffer_size = value;
598 
599     // update the text
600     unsigned int buffer_size = (1 << value);
601     txtSourceBuffer->setText(i18n("%1 samples", buffer_size));
602 
603     emit sigBuffersChanged();
604 }
605 
606 //***************************************************************************
setFileFilter(const QString & filter)607 void Kwave::RecordDialog::setFileFilter(const QString &filter)
608 {
609     m_file_filter = filter;
610     if (btSourceSelect) btSourceSelect->setEnabled(m_file_filter.length());
611 }
612 
613 //***************************************************************************
selectRecordDevice()614 void Kwave::RecordDialog::selectRecordDevice()
615 {
616     if (!m_enable_setDevice) return;
617 
618     QString filter;
619     filter += _("dsp*|")    + i18n("OSS record device (dsp*)");
620     filter += _("\nadsp*|") + i18n("ALSA record device (adsp*)");
621     filter += _("\n*|")     + i18n("Any device (*)");
622 
623     QPointer<Kwave::FileDialog> dlg = new(std::nothrow) Kwave::FileDialog(
624 	_("kfiledialog:///kwave_record_device"),
625 	Kwave::FileDialog::OpenFile, filter, this,
626 	QUrl(_("file:/dev"))
627     );
628     if (!dlg) return;
629     dlg->setWindowTitle(i18n("Select Record Device"));
630     if (!m_params.device_name.startsWith(_("#")))
631         dlg->selectUrl(QUrl(_("file:") + m_params.device_name));
632     else
633         dlg->selectUrl(QUrl(_("file:/dev/*")));
634     if ((dlg->exec() == QDialog::Accepted) && dlg) {
635 	// selected new device
636 	QString new_device = dlg->selectedUrl().path();
637 	if (new_device != m_params.device_name)
638 	    emit sigDeviceChanged(new_device);
639     }
640     delete dlg;
641 }
642 
643 //***************************************************************************
rate2string(double rate) const644 QString Kwave::RecordDialog::rate2string(double rate) const
645 {
646     QLocale locale;
647     const QString dot  = locale.decimalPoint();
648     const QString tsep = locale.groupSeparator();
649 
650     // format number with 3 digits
651     QString s = locale.toString(rate, 'f', 3);
652 
653     // remove thousands separator (looks ugly)
654     s.remove(tsep);
655 
656     // remove trailing zeroes
657     while (s.endsWith(_("0"))) s.remove(s.length()-1, 1);
658 
659     // remove decimal point if necessary
660     if (s.endsWith(dot)) s.remove(s.length()-1, 1);
661 
662     return s;
663 }
664 
665 //***************************************************************************
string2rate(const QString & rate) const666 double Kwave::RecordDialog::string2rate(const QString &rate) const
667 {
668     QLocale locale;
669     const QString s = rate;
670     double r;
671     bool ok;
672     r = locale.toDouble(rate, &ok);
673     Q_ASSERT(ok);
674     if (!ok) return s.toDouble();
675 
676     return r;
677 }
678 
679 //***************************************************************************
setSupportedTracks(unsigned int min,unsigned int max)680 void Kwave::RecordDialog::setSupportedTracks(unsigned int min,
681                                              unsigned int max)
682 {
683     Q_ASSERT(sbFormatTracks);
684     if (!sbFormatTracks) return;
685 
686     if ((min == max) || (!max)) {
687 	sbFormatTracks->setEnabled(false);
688 	return;
689     } else
690 	sbFormatTracks->setEnabled(true);
691 
692     if (sbFormatTracks->value() < sbFormatTracks->minimum()) {
693 	sbFormatTracks->setMaximum(max);
694 	sbFormatTracks->setMinimum(min);
695     } else {
696 	sbFormatTracks->setMinimum(min);
697 	sbFormatTracks->setMaximum(max);
698     }
699 
700 }
701 
702 //***************************************************************************
setTracks(unsigned int tracks)703 void Kwave::RecordDialog::setTracks(unsigned int tracks)
704 {
705 //     qDebug("+++ RecordDialog::setTracks(%u)", tracks);
706     Q_ASSERT(sbFormatTracks);
707     Q_ASSERT(m_status_bar.m_tracks);
708     if (!sbFormatTracks || !m_status_bar.m_tracks) return;
709     if (!tracks) return;
710 
711     m_params.tracks = tracks;
712     QString tracks_str;
713 
714     switch (tracks) {
715 	case 1:
716 	    tracks_str = i18n("Mono");
717 	    break;
718 	case 2:
719 	    tracks_str = i18n("Stereo");
720 	    break;
721 	case 4:
722 	    tracks_str = i18n("Quadro");
723 	    break;
724 	default:
725 	    tracks_str = _("");
726     }
727 
728     if (tracks_str.length()) {
729 	lblTracksVerbose->setText(_("(") + tracks_str + _(")"));
730 	m_status_bar.m_tracks->setText(tracks_str);
731     } else {
732 	lblTracksVerbose->setText(_(""));
733 	m_status_bar.m_tracks->setText(i18n("%1 tracks", tracks));
734     }
735 
736     sbFormatTracks->setValue(tracks);
737 }
738 
739 //***************************************************************************
tracksChanged(int tracks)740 void Kwave::RecordDialog::tracksChanged(int tracks)
741 {
742     if (tracks < 1) return; // no device
743     if (tracks == Kwave::toInt(m_params.tracks)) return;
744 
745     m_params.tracks = tracks;
746     emit sigTracksChanged(tracks);
747 }
748 
749 //***************************************************************************
setSupportedSampleRates(const QList<double> & rates)750 void Kwave::RecordDialog::setSupportedSampleRates(const QList<double> &rates)
751 {
752     Q_ASSERT(cbFormatSampleRate);
753     if (!cbFormatSampleRate) return;
754 
755     cbFormatSampleRate->clearEditText();
756     cbFormatSampleRate->setEditable(false);
757     cbFormatSampleRate->clear();
758 
759     foreach (double r, rates) {
760 	QString rate = rate2string(r);
761 	Q_ASSERT(rate.length());
762 	if (!rate.length()) continue; // string was zero?
763 	cbFormatSampleRate->addItem(rate);
764     }
765 
766     bool have_choice = (cbFormatSampleRate->count() > 1);
767     cbFormatSampleRate->setEnabled(have_choice);
768 }
769 
770 //***************************************************************************
setSampleRate(double new_rate)771 void Kwave::RecordDialog::setSampleRate(double new_rate)
772 {
773     Q_ASSERT(cbFormatSampleRate);
774     Q_ASSERT(m_status_bar.m_sample_rate);
775     if (!cbFormatSampleRate || !m_status_bar.m_sample_rate) return;
776 
777     if (new_rate <= 0) {
778 	cbFormatSampleRate->setEnabled(false);
779 	return;
780     } else {
781 	bool have_choice = (cbFormatSampleRate->count() > 1);
782 	cbFormatSampleRate->setEnabled(have_choice);
783 	m_params.sample_rate = new_rate;
784     }
785 
786     QString rate;
787     rate = rate2string(new_rate);
788     cbFormatSampleRate->setCurrentItem(rate, true);
789     m_status_bar.m_sample_rate->setText(i18n("%1 Hz", rate));
790 }
791 
792 //***************************************************************************
sampleRateChanged(const QString & rate)793 void Kwave::RecordDialog::sampleRateChanged(const QString &rate)
794 {
795     if (!rate.length()) return; // no rate selected, combo box clear
796     double sample_rate = string2rate(rate);
797     if (qFuzzyCompare(sample_rate, m_params.sample_rate)) return;
798 
799     m_params.sample_rate = sample_rate;
800     emit sampleRateChanged(sample_rate);
801 }
802 
803 //***************************************************************************
setSupportedCompressions(const QList<Kwave::Compression::Type> & comps)804 void Kwave::RecordDialog::setSupportedCompressions(
805     const QList<Kwave::Compression::Type> &comps
806 )
807 {
808     Q_ASSERT(cbFormatCompression);
809     if (!cbFormatCompression) return;
810 
811     cbFormatCompression->clear();
812 
813     if (comps.isEmpty()) {
814 	// no compressions -> add "none" manually
815 	const Kwave::Compression comp(Kwave::Compression::NONE);
816 	cbFormatCompression->addItem(comp.name());
817     } else {
818 	foreach (Kwave::Compression::Type c, comps) {
819 	    const Kwave::Compression comp(c);
820 	    cbFormatCompression->addItem(comp.name(), comp.toInt());
821 	}
822     }
823 
824     bool have_choice = (cbFormatCompression->count() > 1);
825     cbFormatCompression->setEnabled(have_choice);
826 }
827 
828 //***************************************************************************
setCompression(int compression)829 void Kwave::RecordDialog::setCompression(int compression)
830 {
831     Q_ASSERT(cbFormatCompression);
832     if (!cbFormatCompression) return;
833 
834     if (compression < 0) {
835 	cbFormatCompression->setEnabled(false);
836 	return;
837     } else {
838 	bool have_choice = (cbFormatCompression->count() > 1);
839 	cbFormatCompression->setEnabled(have_choice);
840 	m_params.compression = Kwave::Compression::fromInt(compression);
841     }
842 
843     const Kwave::Compression comp(Kwave::Compression::fromInt(compression));
844     cbFormatCompression->setCurrentItem(comp.name(), true);
845 }
846 
847 //***************************************************************************
compressionChanged(int index)848 void Kwave::RecordDialog::compressionChanged(int index)
849 {
850     Kwave::Compression::Type compression = Kwave::Compression::fromInt(
851 	cbFormatCompression->itemData(index).toInt());
852     if (compression != m_params.compression)
853 	emit sigCompressionChanged(compression);
854 }
855 
856 //***************************************************************************
setSupportedBits(const QList<unsigned int> & bits)857 void Kwave::RecordDialog::setSupportedBits(const QList<unsigned int> &bits)
858 {
859     Q_ASSERT(sbFormatResolution);
860     if (!sbFormatResolution) return;
861 
862     m_supported_resolutions = bits;
863     if (bits.count()) {
864 	sbFormatResolution->setMinimum(bits.first());
865 	sbFormatResolution->setMaximum(bits.last());
866     }
867 
868     // enable only if there is a choice
869     sbFormatResolution->setEnabled(bits.count() > 1);
870 }
871 
872 //***************************************************************************
setBitsPerSample(unsigned int bits)873 void Kwave::RecordDialog::setBitsPerSample(unsigned int bits)
874 {
875     Q_ASSERT(sbFormatResolution);
876     Q_ASSERT(m_status_bar.m_bits_per_sample);
877     if (!sbFormatResolution || !m_status_bar.m_bits_per_sample) return;
878 
879     if (!bits ) {
880 	sbFormatResolution->setEnabled(false);
881 	return;
882     } else {
883 	sbFormatResolution->setEnabled(m_supported_resolutions.count() > 1);
884 	m_params.bits_per_sample = bits;
885     }
886 
887     m_status_bar.m_bits_per_sample->setText(i18n("%1 bit", bits));
888     sbFormatResolution->setValue(bits);
889 }
890 
891 //***************************************************************************
bitsPerSampleChanged(int bits)892 void Kwave::RecordDialog::bitsPerSampleChanged(int bits)
893 {
894     if (bits < 1) return; // no device
895     int last = m_params.bits_per_sample;
896     if (bits == last) return;
897 
898     // round up or down to the next supported resolution in bits per sample
899     if (!m_supported_resolutions.isEmpty()) {
900 	if (bits > last) {
901 	    // step up to the next supported value
902 	    QListIterator<unsigned int> it(m_supported_resolutions);
903 	    while (it.hasNext()) {
904 		bits = it.next();
905 		if (bits > last) break;
906 	    }
907 	    if (bits < last) bits = m_supported_resolutions.last();
908 	} else {
909 	    // step down to the next supported value
910 	    QListIterator<unsigned int> it(m_supported_resolutions);
911 	    it.toBack();
912 	    while (it.hasPrevious()) {
913 		bits = it.previous();
914 		if (bits < last) break;
915 	    }
916 	    if (bits > last) bits = m_supported_resolutions.first();
917 	}
918     }
919 
920     m_params.bits_per_sample = bits;
921 
922     if (sbFormatResolution && (bits != sbFormatResolution->value()))
923         sbFormatResolution->setValue(bits);
924 
925     emit sigBitsPerSampleChanged(bits);
926 }
927 
928 //***************************************************************************
setSupportedSampleFormats(const QList<Kwave::SampleFormat::Format> & formats)929 void Kwave::RecordDialog::setSupportedSampleFormats(
930     const QList<Kwave::SampleFormat::Format> &formats)
931 {
932     Q_ASSERT(cbFormatSampleFormat);
933     if (!cbFormatSampleFormat) return;
934 
935     cbFormatSampleFormat->clear();
936     Kwave::SampleFormat::Map types;
937     foreach (Kwave::SampleFormat::Format format, formats) {
938 	int index = types.findFromData(format);
939 	cbFormatSampleFormat->addItem(
940 	    types.description(index, true),
941 	    Kwave::SampleFormat(format).toInt()
942 	);
943     }
944 
945     bool have_choice = (cbFormatSampleFormat->count() > 1);
946     cbFormatSampleFormat->setEnabled(have_choice);
947 }
948 
949 //***************************************************************************
setSampleFormat(Kwave::SampleFormat::Format sample_format)950 void Kwave::RecordDialog::setSampleFormat(
951     Kwave::SampleFormat::Format sample_format)
952 {
953     Q_ASSERT(cbFormatSampleFormat);
954     if (!cbFormatSampleFormat) return;
955 
956     if (sample_format == Kwave::SampleFormat::Unknown) {
957 	cbFormatSampleFormat->setEnabled(false);
958 	return;
959     } else {
960 	bool have_choice = (cbFormatSampleFormat->count() > 1);
961 	cbFormatSampleFormat->setEnabled(have_choice);
962 	m_params.sample_format = sample_format;
963     }
964 
965     int cb_index = cbFormatSampleFormat->findData(
966 	Kwave::SampleFormat(sample_format).toInt());
967     cbFormatSampleFormat->setCurrentIndex(cb_index);
968 }
969 
970 //***************************************************************************
sampleFormatChanged(int index)971 void Kwave::RecordDialog::sampleFormatChanged(int index)
972 {
973     Q_ASSERT(cbFormatSampleFormat);
974     if (!cbFormatSampleFormat) return;
975 
976     Kwave::SampleFormat format;
977     format.fromInt(cbFormatSampleFormat->itemData(index).toInt());
978 
979     if (format == m_params.sample_format) return;
980 
981     emit sigSampleFormatChanged(format);
982 }
983 
984 //***************************************************************************
setState(Kwave::RecordState state)985 void Kwave::RecordDialog::setState(Kwave::RecordState state)
986 {
987     Q_ASSERT(m_status_bar.m_state);
988     if (!m_status_bar.m_state) return;
989 
990     bool enable_new = false;
991     bool enable_pause = false;
992     bool enable_stop = false;
993     bool enable_record = false;
994     bool enable_settings = false;
995     bool enable_trigger = false;
996     QString state_text = _("");
997     QVector<QPixmap> pixmaps;
998     unsigned int animation_time = 500;
999 
1000     m_state = state;
1001     switch (state) {
1002 	case Kwave::REC_UNINITIALIZED:
1003 	    state_text = i18n("Please check the source device settings...");
1004 	    enable_new      = true;
1005 	    enable_pause    = false;
1006 	    enable_stop     = false;
1007 	    enable_record   = false;
1008 	    enable_settings = true;
1009 	    enable_trigger  = true;
1010 	    pixmaps.push_back(QPixmap(stop_hand_xpm));
1011 	    pixmaps.push_back(QPixmap(ledred_xpm));
1012 	    m_status_bar.m_time->setText(_(""));
1013 	    break;
1014 	case Kwave::REC_EMPTY:
1015 	    state_text = i18n("(empty)");
1016 	    enable_new      = true;
1017 	    enable_pause    = false;
1018 	    enable_stop     = false;
1019 	    enable_record   = m_params.device_name.length();
1020 	    enable_settings = true;
1021 	    enable_trigger  = true;
1022 	    pixmaps.push_back(QPixmap(ledgreen_xpm));
1023 	    m_status_bar.m_time->setText(_(""));
1024 	    break;
1025 	case Kwave::REC_BUFFERING:
1026 	    state_text = i18n("Buffering...");
1027 	    enable_new      = true; /* throw away current FIFO content */
1028 	    enable_pause    = false;
1029 	    enable_stop     = true;
1030 	    enable_record   = true; /* acts as "trigger now" */
1031 	    enable_settings = false;
1032 	    enable_trigger  = true;
1033 	    pixmaps.push_back(QPixmap(ledgreen_xpm));
1034 	    pixmaps.push_back(QPixmap(ledlightgreen_xpm));
1035 	    break;
1036 	case Kwave::REC_PRERECORDING:
1037 	    state_text = i18n("Prerecording...");
1038 	    enable_new      = false;
1039 	    enable_pause    = false;
1040 	    enable_stop     = true;
1041 	    enable_record   = true;
1042 	    enable_settings = false;
1043 	    enable_trigger  = true;
1044 	    pixmaps.push_back(QPixmap(ledgreen_xpm));
1045 	    pixmaps.push_back(QPixmap(ledlightgreen_xpm));
1046 	    break;
1047 	case Kwave::REC_WAITING_FOR_TRIGGER:
1048 	    state_text = i18n("Waiting for trigger...");
1049 	    enable_new      = false;
1050 	    enable_pause    = false;
1051 	    enable_stop     = true;
1052 	    enable_record   = true; /* acts as "trigger now" */
1053 	    enable_settings = false;
1054 	    enable_trigger  = true;
1055 	    pixmaps.push_back(QPixmap(ledgreen_xpm));
1056 	    pixmaps.push_back(QPixmap(ledlightgreen_xpm));
1057 	    break;
1058 	case Kwave::REC_RECORDING:
1059 	    state_text = i18n("Recording...");
1060 	    enable_new      = false;
1061 	    enable_pause    = true;
1062 	    enable_stop     = true;
1063 	    enable_record   = false;
1064 	    enable_settings = false;
1065 	    enable_trigger  = false;
1066 	    pixmaps.push_back(QPixmap(walk_r1_xpm));
1067 	    pixmaps.push_back(QPixmap(walk_r2_xpm));
1068 	    pixmaps.push_back(QPixmap(walk_r3_xpm));
1069 	    pixmaps.push_back(QPixmap(walk_r4_xpm));
1070 	    pixmaps.push_back(QPixmap(walk_r5_xpm));
1071 	    pixmaps.push_back(QPixmap(walk_r6_xpm));
1072 	    pixmaps.push_back(QPixmap(walk_r7_xpm));
1073 	    pixmaps.push_back(QPixmap(walk_r8_xpm));
1074 	    animation_time = 100;
1075 	    break;
1076 	case Kwave::REC_PAUSED:
1077 	    state_text = i18n("Paused");
1078 	    enable_new      = true; /* start again */
1079 	    enable_pause    = true; /* used for "continue" */
1080 	    enable_stop     = true;
1081 	    enable_record   = true; /* used for "continue" */
1082 	    enable_settings = false;
1083 	    enable_trigger  = false;
1084 	    pixmaps.push_back(QPixmap(ledgreen_xpm));
1085 	    pixmaps.push_back(QPixmap(ledyellow_xpm));
1086 	    break;
1087 	case Kwave::REC_DONE:
1088 	    state_text = i18n("Done");
1089 	    enable_new      = true;
1090 	    enable_pause    = false;
1091 	    enable_stop     = false;
1092 	    enable_record   = true;
1093 	    enable_settings = true;
1094 	    enable_trigger  = true;
1095 	    pixmaps.push_back(QPixmap(ok_xpm));
1096 	    break;
1097     }
1098     m_status_bar.m_state->setText(state_text);
1099     m_state_icon_widget->setPixmaps(pixmaps, animation_time);
1100 
1101     // enable/disable the record control buttons
1102     btNew->setEnabled(enable_new);
1103     btPause->setEnabled(enable_pause);
1104     btStop->setEnabled(enable_stop);
1105     m_record_enabled = enable_record;
1106     updateRecordButton();
1107 
1108     // enable disable all controls (groups) for setup
1109     chkRecordPre->setEnabled(enable_settings);
1110     sbRecordPre->setEnabled(enable_settings &&
1111                             chkRecordPre->isChecked());
1112     slRecordPre->setEnabled(enable_settings &&
1113                             chkRecordPre->isChecked());
1114 
1115     chkRecordStartTime->setEnabled(enable_settings);
1116     chkRecordTime->setEnabled(enable_settings);
1117     sbRecordTime->setEnabled(enable_settings &&
1118                              chkRecordTime->isChecked());
1119     chkRecordTrigger->setEnabled(enable_settings);
1120 
1121     // it is not really necessary to disable these ;-)
1122     sbRecordTrigger->setEnabled(enable_trigger &&
1123                                 chkRecordTrigger->isChecked());
1124     slRecordTrigger->setEnabled(enable_trigger &&
1125                                 chkRecordTrigger->isChecked());
1126     startTime->setEnabled(enable_settings &&
1127                           chkRecordStartTime->isChecked());
1128 
1129     grpFormat->setEnabled(enable_settings);
1130     grpSource->setEnabled(enable_settings);
1131 
1132 }
1133 
1134 //***************************************************************************
updateBufferState(unsigned int count,unsigned int total)1135 void Kwave::RecordDialog::updateBufferState(unsigned int count,
1136                                             unsigned int total)
1137 {
1138     Q_ASSERT(progress_bar);
1139     Q_ASSERT(m_status_bar.m_state);
1140     if (!progress_bar || !m_status_bar.m_state) return;
1141 
1142     if (total == 0) {
1143 	// we are done: stop update timer and reset buffer percentage
1144 	m_buffer_progress_timer.stop();
1145 	m_buffer_progress_count = 0;
1146 	m_buffer_progress_total = 0;
1147 	progress_bar->setTextVisible(false);
1148 	progress_bar->setMinimum(0);
1149 	progress_bar->setMaximum(100);
1150 	progress_bar->setValue(0);
1151 	progress_bar->reset();
1152     } else {
1153 	m_buffer_progress_count = count;
1154 	m_buffer_progress_total = total;
1155 
1156 	if (!m_buffer_progress_timer.isActive())
1157 	    updateBufferProgressBar();
1158     }
1159 
1160     // update recording time
1161     QString txt;
1162     switch (m_state) {
1163 	case Kwave::REC_UNINITIALIZED:
1164 	case Kwave::REC_EMPTY:
1165 	case Kwave::REC_BUFFERING:
1166 	case Kwave::REC_PRERECORDING:
1167 	    txt = _("");
1168 	    break;
1169 	case Kwave::REC_WAITING_FOR_TRIGGER: {
1170 	    txt = _("");
1171 	    QString state_text;
1172 	    QDateTime now     = QDateTime::currentDateTime();
1173 	    QDateTime t_start = m_params.start_time;
1174 
1175 	    if (m_params.start_time_enabled && (now < t_start)) {
1176 		// waiting for start time to come...
1177 
1178 		int s = Kwave::toInt(now.secsTo(t_start));
1179 		int m = s / 60;
1180 		s %= 60;
1181 		int h = m / 60;
1182 		m %= 60;
1183 		int d = h / 24;
1184 		h %= 24;
1185 
1186 		QString days    = (d) ?
1187 		    i18np("one day ",    "%1 days ",    d) : _("");
1188 		QString hours   = (h) ?
1189 		    i18np("one hour ",   "%1 hours ",   h) : _("");
1190 		QString minutes = (m) ?
1191 		    i18np("one minute ", "%1 minutes ", m) : _("");
1192 		QString seconds =
1193 		    (d | h | m) ?
1194 		    i18np("and %1 second", "and %1 seconds", s) :
1195 		    i18np("%1 second", "%1 seconds", s);
1196 
1197 		state_text = i18nc(
1198 		    "%1=days; %2=hours; %3=minutes; %4=seconds",
1199 		    "Waiting for start in %1%2%3%4...",
1200 		    days, hours, minutes, seconds);
1201 	    } else {
1202 		// waiting for trigger...
1203 		state_text = i18n("Waiting for trigger...");
1204 	    }
1205 	    m_status_bar.m_state->setText(state_text);
1206 
1207 	    break;
1208 	}
1209 	case Kwave::REC_RECORDING:
1210 	case Kwave::REC_PAUSED:
1211 	case Kwave::REC_DONE: {
1212 	    if (m_samples_recorded > 1) {
1213 		double rate = m_params.sample_rate;
1214 		double ms = (rate > 0) ?
1215 		    ((static_cast<double>(m_samples_recorded) / rate) * 1E3)
1216 		    : 0;
1217 		txt = _(" ") +
1218 		    i18n("Length: %1", Kwave::ms2string(ms)) +
1219 		    _(" ") + i18n("(%1 samples)",
1220 		    Kwave::samples2string(m_samples_recorded));
1221 	    } else txt = _("");
1222 	    break;
1223 	}
1224     }
1225     m_status_bar.m_time->setText(txt);
1226 }
1227 
1228 //***************************************************************************
preRecordingChecked(bool enabled)1229 void Kwave::RecordDialog::preRecordingChecked(bool enabled)
1230 {
1231     m_params.pre_record_enabled = enabled;
1232     emit sigPreRecordingChanged(enabled);
1233 }
1234 
1235 //***************************************************************************
preRecordingTimeChanged(int time)1236 void Kwave::RecordDialog::preRecordingTimeChanged(int time)
1237 {
1238     m_params.pre_record_time = time;
1239 }
1240 
1241 //***************************************************************************
recordTimeChecked(bool limited)1242 void Kwave::RecordDialog::recordTimeChecked(bool limited)
1243 {
1244     m_params.record_time_limited = limited;
1245     emit sigRecordTimeChanged(limited ? sbRecordTime->value() : -1);
1246 }
1247 
1248 //***************************************************************************
recordTimeChanged(int limit)1249 void Kwave::RecordDialog::recordTimeChanged(int limit)
1250 {
1251     m_params.record_time = limit;
1252     emit sigRecordTimeChanged(chkRecordTime->isChecked() ?
1253                               limit : -1);
1254     updateRecordButton();
1255 }
1256 
1257 //***************************************************************************
startTimeChecked(bool enabled)1258 void Kwave::RecordDialog::startTimeChecked(bool enabled)
1259 {
1260     m_params.start_time_enabled = enabled;
1261     emit sigTriggerChanged(enabled || m_params.record_trigger_enabled);
1262 }
1263 
1264 //***************************************************************************
startTimeChanged(const QDateTime & datetime)1265 void Kwave::RecordDialog::startTimeChanged(const QDateTime &datetime)
1266 {
1267     m_params.start_time = datetime;
1268 
1269     // force seconds to zero
1270     QTime t = m_params.start_time.time();
1271     t.setHMS(t.hour(), t.minute(), 0, 0);
1272     m_params.start_time.setTime(t);
1273 }
1274 
1275 //***************************************************************************
triggerChecked(bool enabled)1276 void Kwave::RecordDialog::triggerChecked(bool enabled)
1277 {
1278     m_params.record_trigger_enabled = enabled;
1279     emit sigTriggerChanged(enabled || m_params.start_time_enabled);
1280 }
1281 
1282 //***************************************************************************
triggerChanged(int trigger)1283 void Kwave::RecordDialog::triggerChanged(int trigger)
1284 {
1285     m_params.record_trigger = trigger;
1286 }
1287 
1288 //***************************************************************************
updateBufferProgressBar()1289 void Kwave::RecordDialog::updateBufferProgressBar()
1290 {
1291     unsigned int count = m_buffer_progress_count;
1292     unsigned int total = m_buffer_progress_total;
1293 //     qDebug("RecordDialog::updateBufferProgressBar(): %u/%u",
1294 //            count, total);
1295 
1296     /*
1297      * @note: QProgressBar has a bug when handling small numbers,
1298      *        therefore we multiply everything by 100
1299      */
1300     progress_bar->setTextVisible(true);
1301     progress_bar->setMinimum(0);
1302     progress_bar->setMaximum(100 * total);
1303     progress_bar->setValue(100 * count);
1304 
1305     m_buffer_progress_timer.setSingleShot(true);
1306     m_buffer_progress_timer.setInterval(100);
1307     m_buffer_progress_timer.start();
1308 }
1309 
1310 //***************************************************************************
updateEffects(unsigned int track,Kwave::SampleArray & buffer)1311 void Kwave::RecordDialog::updateEffects(unsigned int track,
1312                                         Kwave::SampleArray &buffer)
1313 {
1314     if (!buffer.size()) return;
1315 
1316     if (level_meter) {
1317 	level_meter->setTracks(m_params.tracks);
1318 	level_meter->setSampleRate(m_params.sample_rate);
1319 	level_meter->updateTrack(track, buffer);
1320     }
1321 
1322 }
1323 
1324 //***************************************************************************
setRecordedSamples(sample_index_t samples_recorded)1325 void Kwave::RecordDialog::setRecordedSamples(sample_index_t samples_recorded)
1326 {
1327     // if (!m_params.record_time_limited) return; // not of interest
1328     m_samples_recorded = samples_recorded;
1329     updateRecordButton();
1330 }
1331 
1332 //***************************************************************************
updateRecordButton()1333 void Kwave::RecordDialog::updateRecordButton()
1334 {
1335     bool old_enable = btRecord->isEnabled();
1336     bool new_enable;
1337 
1338     // enabled if not disabled by status and also not limited or
1339     // less than the limit has been recorded
1340     new_enable = m_record_enabled && (!m_params.record_time_limited ||
1341 	(static_cast<double>(m_samples_recorded) <
1342          m_params.record_time * m_params.sample_rate));
1343 
1344     if (new_enable != old_enable) btRecord->setEnabled(new_enable);
1345 }
1346 
1347 //***************************************************************************
invokeHelp()1348 void Kwave::RecordDialog::invokeHelp()
1349 {
1350     KHelpClient::invokeHelp(_("recording"));
1351 }
1352 
1353 //***************************************************************************
message(const QString & message)1354 void Kwave::RecordDialog::message(const QString &message)
1355 {
1356     if (lbl_state) lbl_state->showMessage(message, 3000);
1357 }
1358 
1359 //***************************************************************************
showDevicePage()1360 void Kwave::RecordDialog::showDevicePage()
1361 {
1362     if (tabRecord) tabRecord->setCurrentIndex(2);
1363 }
1364 
1365 //***************************************************************************
1366 //***************************************************************************
1367