kwave  18.07.70
PlayBackPlugin.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  PlayBackPlugin.cpp - plugin for playback and playback configuration
3  -------------------
4  begin : Sun May 13 2001
5  copyright : (C) 2001 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 <errno.h>
21 #include <limits.h>
22 #include <math.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <unistd.h>
26 
27 #include <QApplication>
28 #include <QCursor>
29 #include <QFile>
30 #include <QLatin1Char>
31 #include <QMutex>
32 #include <QMutexLocker>
33 #include <QProgressDialog>
34 #include <QString>
35 #include <QTimer>
36 
37 #include <KConfig>
38 
39 #include "libkwave/Connect.h"
40 #include "libkwave/Curve.h"
41 #include "libkwave/MessageBox.h"
47 #include "libkwave/Plugin.h"
48 #include "libkwave/PluginManager.h"
49 #include "libkwave/Sample.h"
50 #include "libkwave/SampleReader.h"
51 #include "libkwave/SignalManager.h"
52 #include "libkwave/String.h"
53 #include "libkwave/Utils.h"
54 
56 #include "libkwave/modules/Delay.h"
57 #include "libkwave/modules/Mul.h"
58 #include "libkwave/modules/Osc.h"
59 
60 #include "PlayBack-ALSA.h"
61 #include "PlayBack-OSS.h"
62 #include "PlayBack-PulseAudio.h"
63 #include "PlayBack-Qt.h"
64 
65 #include "PlayBackDialog.h"
66 #include "PlayBackPlugin.h"
67 
68 KWAVE_PLUGIN(playback, PlayBackPlugin)
69 
70 
71 #define PLAYBACK_TEST_FREQUENCY 440.0
72 
73 //***************************************************************************
75  const QVariantList &args)
76  :Kwave::Plugin(parent, args),
77  m_dialog(Q_NULLPTR),
78  m_playback_controller(manager().playbackController()),
79  m_playback_sink(Q_NULLPTR)
80 {
81 }
82 
83 //***************************************************************************
85 {
86  // make sure the dialog is gone
87  if (m_dialog) delete m_dialog;
88  m_dialog = Q_NULLPTR;
89 
90  Q_ASSERT(!m_playback_sink);
91 }
92 
93 //***************************************************************************
95  QStringList &params)
96 {
97  Kwave::PlayBackParam playback_params;
98  Kwave::PlayBackParam default_params;
99  bool ok;
100  QString param;
101 
102  // evaluate the parameter list
103  if (params.count() != 5) return default_params;
104 
105  // parameter #0: playback method
106  param = params[0];
107  unsigned int method = param.toUInt(&ok);
108  Q_ASSERT(ok);
109  if (!ok) return default_params;
110  if (method >= Kwave::PLAYBACK_INVALID) method = Kwave::PLAYBACK_NONE;
111  playback_params.method = static_cast<Kwave::playback_method_t>(method);
112 
113  // parameter #1: playback device [/dev/dsp , ... ]
114  param = params[1];
115  playback_params.device = param;
116 
117  // parameter #2: number of channels [1 | 2]
118  param = params[2];
119  playback_params.channels = param.toUInt(&ok);
120  Q_ASSERT(ok);
121  if (!ok) return default_params;
122 
123  // parameter #3: bits per sample [8 | 16 ]
124  param = params[3];
125  playback_params.bits_per_sample = param.toUInt(&ok);
126  Q_ASSERT(ok);
127  if (!ok) return default_params;
128 
129  // parameter #4: base of buffer size [4...16]
130  param = params[4];
131  playback_params.bufbase = param.toUInt(&ok);
132  Q_ASSERT(ok);
133  if (!ok) return default_params;
134 
135  return playback_params;
136 }
137 
138 //***************************************************************************
139 void Kwave::PlayBackPlugin::load(QStringList &params)
140 {
141  use(); // stay loaded
142 
143  // register as a factory for playback devices
146 }
147 
148 /***************************************************************************/
150 {
151  // unregister from the list playback factories
153  release();
154 }
155 
156 //***************************************************************************
157 QStringList *Kwave::PlayBackPlugin::setup(QStringList &previous_params)
158 {
159  QStringList *result = Q_NULLPTR;
160 
161  // try to interpret the list of previous parameters, ignore errors
162  Kwave::PlayBackParam playback_params =
163  interpreteParameters(previous_params);
164 
165  Q_ASSERT(!m_dialog);
166  if (m_dialog) delete m_dialog;
167 
169  *this,
170  manager().playbackController(),
171  playback_params
172  );
173  Q_ASSERT(m_dialog);
174  if (!m_dialog) return Q_NULLPTR;
175 
176  connect(m_dialog, SIGNAL(sigTestPlayback()),
177  this, SLOT(testPlayBack()));
178 
179  // activate the playback method
180  m_dialog->setMethod(playback_params.method);
181 
182  if (m_dialog->exec() == QDialog::Accepted) {
183  // get the new parameters and let them take effect
184  result = new QStringList();
185  Q_ASSERT(result);
186  if (result) {
187  QString param;
188 
189  playback_params = m_dialog->params();
190 
191  // parameter #0: playback method
192  param = param.setNum(
193  static_cast<unsigned int>(playback_params.method));
194  result->append(param);
195 
196  // parameter #1: playback device [/dev/dsp , ... ]
197  param = playback_params.device;
198  result->append(param);
199 
200  // parameter #2: number of channels [1, 2, ... n]
201  param = param.setNum(playback_params.channels);
202  result->append(param);
203 
204  // parameter #3: bits per sample [8, 16, 24, ...]
205  param = param.setNum(playback_params.bits_per_sample);
206  result->append(param);
207 
208  // parameter #4: base of buffer size [8 ... 16]
209  param = param.setNum(playback_params.bufbase);
210  result->append(param);
211 
212  qDebug("new playback params: '%s",
213  DBG(result->join(_("','")) + _("'")));
214 
215  // take over the new playback parameters
217  playback_params
218  );
219  }
220  }
221 
222  delete m_dialog;
223  m_dialog = Q_NULLPTR;
224 
225  return result;
226 }
227 
228 //***************************************************************************
229 QList<Kwave::playback_method_t> Kwave::PlayBackPlugin::supportedMethods()
230 {
231  QList<Kwave::playback_method_t> methods;
232 
233 #ifdef HAVE_QT_AUDIO_SUPPORT
234  methods.append(Kwave::PLAYBACK_QT_AUDIO);
235 #endif /* HAVE_QT_AUDIO_SUPPORT */
236 
237 #ifdef HAVE_PULSEAUDIO_SUPPORT
238  methods.append(Kwave::PLAYBACK_PULSEAUDIO);
239 #endif /* HAVE_PULSEAUDIO_SUPPORT */
240 
241 #ifdef HAVE_ALSA_SUPPORT
242  methods.append(Kwave::PLAYBACK_ALSA);
243 #endif /* HAVE_ALSA_SUPPORT */
244 
245 #ifdef HAVE_OSS_SUPPORT
246  methods.append(Kwave::PLAYBACK_OSS);
247 #endif /* HAVE_OSS_SUPPORT */
248 
249  return methods;
250 }
251 
252 //***************************************************************************
255 {
256  Kwave::PlayBackTypesMap methods;
257  qDebug("PlayBackPlugin::createDevice('%s' [%d])",
258  DBG(methods.name(methods.findFromData(method))),
259  static_cast<int>(method) );
260 
261  switch (method) {
262 #ifdef HAVE_QT_AUDIO_SUPPORT
264  return new Kwave::PlayBackQt();
265 #endif /* HAVE_QT_AUDIO_SUPPORT */
266 
267 #ifdef HAVE_PULSEAUDIO_SUPPORT
269  return new Kwave::PlayBackPulseAudio(
270  Kwave::FileInfo(signalManager().metaData()));
271 #endif /* HAVE_PULSEAUDIO_SUPPORT */
272 
273 #ifdef HAVE_ALSA_SUPPORT
275  return new Kwave::PlayBackALSA();
276 #endif /* HAVE_ALSA_SUPPORT */
277 
278 #ifdef HAVE_OSS_SUPPORT
279  case Kwave::PLAYBACK_OSS:
280  return new Kwave::PlayBackOSS();
281 #endif /* HAVE_OSS_SUPPORT */
282 
283  default:
284  break;
285  }
286 
287  return Q_NULLPTR; // nothing found :-(
288 }
289 
290 //***************************************************************************
291 void Kwave::PlayBackPlugin::run(QStringList params)
292 {
293  const double t_sweep = 1.0; /* seconds per speaker */
294  const unsigned int periods = 3; /* number of periods to play */
295 
296  qDebug("PlayBackPlugin::run()");
297 
298  Q_UNUSED(params);
299 
300  Q_ASSERT(m_dialog);
301  Q_ASSERT(m_playback_sink);
302  if (!m_dialog || !m_playback_sink) return;
303  Kwave::PlayBackParam playback_params = m_dialog->params();
304 
305  unsigned int channels = playback_params.channels;
306  double rate = playback_params.rate;
307  Q_ASSERT(channels);
308  Q_ASSERT(rate > 1.0);
309  if (!channels || (rate <= 1.0)) return;
310 
311  // settings are valid -> take them
312 
313  double t_period = t_sweep * channels;
314  unsigned int curve_length = Kwave::toUint(t_period * rate);
315 
316  // create all objects
317  Kwave::Curve curve;
318  curve.insert(0.0, 0.0);
319  if (channels < 2) {
320  // mono
321  curve.insert(0.5, 1.0);
322  } else {
323  // all above
324  curve.insert(0.5 / static_cast<double>(channels), 1.0);
325  curve.insert(1.0 / static_cast<double>(channels), 0.0);
326  }
327  curve.insert(1.0, 0.0);
328 
329  Kwave::CurveStreamAdapter curve_adapter(curve, curve_length);
330 
332  for (unsigned int i = 0; i < channels; i++) {
333  Q_ASSERT(delay[i]);
334  if (!delay[i]) break;
335  delay[i]->setAttribute(SLOT(setDelay(QVariant)),
336  QVariant(i * t_sweep * rate));
337  }
338 
339  Kwave::Osc osc;
340  osc.setAttribute(SLOT(setFrequency(QVariant)),
341  QVariant(rate / PLAYBACK_TEST_FREQUENCY));
342 
344 
345  // connect everything together...
346  //
347  // curve -> delay --.
348  // |
349  // v
350  // mul -> sink
351  // ^
352  // |
353  // osc --'
354 
356  curve_adapter, SIGNAL(output(Kwave::SampleArray)),
357  delay, SLOT(input(Kwave::SampleArray)));
359  delay, SIGNAL(output(Kwave::SampleArray)),
360  mul, SLOT(input_a(Kwave::SampleArray)));
362  osc, SIGNAL(output(Kwave::SampleArray)),
363  mul, SLOT(input_b(Kwave::SampleArray)));
365  mul, SIGNAL(output(Kwave::SampleArray)),
366  *m_playback_sink, SLOT(input(Kwave::SampleArray)));
367 
368  // show a progress dialog
369 
370  // transport the samples
371  sample_index_t samples_max = static_cast<sample_index_t>(
372  periods * t_period * rate);
373  sample_index_t samples_written = 0;
374  while (!shouldStop() && (samples_written <= samples_max)) {
375  osc.goOn();
376  curve_adapter.goOn();
377  delay.goOn();
378  mul.goOn();
379 
380  samples_written += osc.blockSize();
381 
382  double percent = (static_cast<double>(samples_written) * 100.0) /
383  static_cast<double>(samples_max);
384  emit sigTestProgress(Kwave::toInt(percent));
385  }
386 }
387 
388 //***************************************************************************
390 {
391  qDebug("PlayBackPlugin::testPlayBack()");
392 
393  Q_ASSERT(m_dialog);
394  if (!m_dialog) return;
395  Kwave::PlayBackParam playback_params = m_dialog->params();
396 
397  // check if we really have selected a playback device
398  if (!playback_params.device.length()) {
400  "Please select a playback device first"));
401  return;
402  }
403 
404  unsigned int channels = playback_params.channels;
405  double rate = playback_params.rate;
406  Q_ASSERT(channels);
407  Q_ASSERT(rate > 1.0);
408  if (!channels || (rate <= 1.0)) return;
409 
410  // settings are valid -> take them
411 
412  // create the multi track playback sink
413  // NOTE: this must be done in main thread context!
414  Q_ASSERT(!m_playback_sink);
415  if (m_playback_sink) return;
417  channels,
418  &playback_params
419  );
420  if (!m_playback_sink) return;
422 
423  // show a progress dialog
424  QProgressDialog *progress = Q_NULLPTR;
425  progress = new QProgressDialog(m_dialog);
426  Q_ASSERT(progress);
427  if (progress) {
428  progress->setWindowTitle(i18n("Playback Test"));
429  progress->setModal(true);
430  progress->setMinimumDuration(0);
431  progress->setMinimum(0);
432  progress->setMaximum(100);
433  progress->setAutoClose(false);
434  progress->setValue(0);
435  progress->setLabelText(
436  _("<html><p><br>") +
437  i18n("You should now hear a %1 Hz test tone.<br/><br/>"
438  "(If you hear clicks or dropouts, please increase<br/>"
439  "the buffer size and try again)",
441  _("</p></html>")
442  );
443  connect(progress, SIGNAL(canceled()), this, SLOT(cancel()),
444  Qt::QueuedConnection);
445  connect(this, SIGNAL(sigDone(Kwave::Plugin*)), progress, SLOT(close()),
446  Qt::QueuedConnection);
447  connect(this, SIGNAL(sigTestProgress(int)), progress, SLOT(setValue(int)),
448  Qt::QueuedConnection);
449 
450  QStringList params;
451  execute(params);
452  progress->exec();
453  cancel();
454  }
455 
456  // set hourglass cursor, waiting for shutdown could take some time...
457  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
458 
459  // wait through manual polling here, no timeout
460  qDebug("waiting...");
461  while (isRunning()) {
462  cancel();
463  sleep(1);
464  qDebug(".");
465  }
466  qDebug("done.");
467 
468  // close the playback sink again (here in main thread context)
470  delete m_playback_sink;
471  m_playback_sink = Q_NULLPTR;
472 
473  // free the progress dialog
474  delete progress;
475 
476  // stop the worker thread through the Runnable API
477  stop();
478 
479  // remove hourglass
480  QApplication::restoreOverrideCursor();
481 }
482 
483 //***************************************************************************
484 #include "PlayBackPlugin.moc"
485 //***************************************************************************
486 //***************************************************************************
virtual void goOn() Q_DECL_OVERRIDE
Definition: Osc.cpp:37
void unregisterPlaybackDeviceFactory(Kwave::PlaybackDeviceFactory *factory)
void setDefaultParams(const Kwave::PlayBackParam &params)
void setMethod(Kwave::playback_method_t method)
Definition: App.h:33
#define PLAYBACK_TEST_FREQUENCY
PlayBackPlugin(QObject *parent, const QVariantList &args)
unsigned int channels
Definition: PlayBackParam.h:66
playback_method_t
Definition: PlayBackParam.h:31
Kwave::SampleSink * openMultiTrackPlayback(unsigned int tracks, const Kwave::PlayBackParam *playback_params=Q_NULLPTR)
Kwave::SignalManager & signalManager()
Definition: Plugin.cpp:444
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
unsigned int bits_per_sample
Definition: PlayBackParam.h:69
void insert(double x, double y)
Definition: Curve.cpp:147
virtual void close()
Definition: Plugin.cpp:394
void release()
Definition: Plugin.cpp:420
virtual void unload() Q_DECL_OVERRIDE
static void setInteractive(bool interactive)
quint64 sample_index_t
Definition: Sample.h:28
Kwave::PlaybackController & playbackController()
Kwave::PlayBackDialog * m_dialog
unsigned int bufbase
Definition: PlayBackParam.h:75
Kwave::PluginManager & manager() const
Definition: Plugin.cpp:437
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
virtual void goOn() Q_DECL_OVERRIDE
virtual int stop()
Definition: Plugin.cpp:214
Kwave::PlayBackParam interpreteParameters(QStringList &params)
virtual void run(QStringList params) Q_DECL_OVERRIDE
void sigDone(Kwave::Plugin *plugin)
virtual void goOn() Q_DECL_OVERRIDE
virtual ~PlayBackPlugin() Q_DECL_OVERRIDE
void registerPlaybackDeviceFactory(Kwave::PlaybackDeviceFactory *factory)
int toInt(T x)
Definition: Utils.h:127
virtual void load(QStringList &params) Q_DECL_OVERRIDE
void sigTestProgress(int percent)
virtual void cancel()
Definition: Plugin.cpp:325
virtual QStringList * setup(QStringList &previous_params) Q_DECL_OVERRIDE
virtual unsigned int blockSize() const
Kwave::SampleSink * m_playback_sink
int execute(QStringList &params)
Definition: Plugin.cpp:331
#define KWAVE_PLUGIN(name, class)
Definition: Plugin.h:54
#define _(m)
Definition: memcpy.c:66
QString name(IDX type) const
Definition: TypesMap.h:117
Kwave::playback_method_t method
Definition: PlayBackParam.h:78
#define DBG(qs)
Definition: String.h:55
unsigned int toUint(T x)
Definition: Utils.h:109
virtual Kwave::PlayBackDevice * createDevice(Kwave::playback_method_t method) Q_DECL_OVERRIDE
void use()
Definition: Plugin.cpp:412
bool isRunning() const
Definition: Plugin.cpp:357
Kwave::PlaybackController & m_playback_controller
IDX findFromData(const DATA &data) const
Definition: TypesMap.h:89
virtual QList< Kwave::playback_method_t > supportedMethods() Q_DECL_OVERRIDE
bool shouldStop() const
Definition: Plugin.h:120
void setAttribute(const char *attribute, const QVariant &value)
const Kwave::PlayBackParam & params()
Definition: Osc.h:32