kwave  18.07.70
NoiseDialog.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  NoiseDialog.cpp - dialog for the "noise" plugin
3  -------------------
4  begin : Sat Sep 28 2013
5  copyright : (C) 2013 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 #include "math.h"
20 
21 #include <QColor>
22 #include <QPainter>
23 #include <QPushButton>
24 #include <QRadioButton>
25 #include <QSlider>
26 #include <QSpinBox>
27 
28 #include <KHelpClient>
29 #include <KLocalizedString>
30 
31 #include "libkwave/String.h"
32 #include "libkwave/Utils.h"
33 
34 #include "libgui/Colors.h"
35 #include "libgui/CurveWidget.h"
36 #include "libgui/ImageView.h"
38 #include "libgui/OverViewCache.h"
39 #include "libgui/ScaleWidget.h"
40 
41 #include "NoiseDialog.h"
42 
43 //***************************************************************************
45  Kwave::OverViewCache *overview_cache)
46  :QDialog(parent), Kwave::PluginSetupDialog(), Ui::NoiseDlg(),
47  m_noise(0.1), m_mode(MODE_DECIBEL),
48  m_enable_updates(true), m_overview_cache(overview_cache)
49 {
50  setupUi(this);
51  setModal(true);
52 
53  // process changed in mode selection
54  connect(rbPercentage, SIGNAL(toggled(bool)),
55  this, SLOT(modeChanged(bool)));
56  connect(rbLogarithmic, SIGNAL(toggled(bool)),
57  this, SLOT(modeChanged(bool)));
58 
59  // changes in the slider or spinbox
60  connect(slider, SIGNAL(valueChanged(int)),
61  this, SLOT(sliderChanged(int)));
62  connect(spinbox, SIGNAL(valueChanged(int)),
63  this, SLOT(spinboxChanged(int)));
64  // click to the "Listen" button
65  connect(btListen, SIGNAL(toggled(bool)),
66  this, SLOT(listenToggled(bool)));
67 
68  // force activation of the layout
69  layout()->activate();
70 
71  // give the preview image a odd height, for better symmetry
72  int h = preview->height();
73  if (~h & 1) h++;
74  preview->setFixedHeight(h);
75 
76  // expand the "Listen" button to it's maximum width
77  listenToggled(true);
78  if (btListen->width() > btListen->minimumWidth())
79  btListen->setMinimumWidth(btListen->width());
80  listenToggled(false);
81  if (btListen->width() > btListen->minimumWidth())
82  btListen->setMinimumWidth(btListen->width());
83 
84  // set the initial size of the dialog
85  h = (sizeHint().height() * 12) / 10;
86  int w = (3 * h) / 4;
87  if (sizeHint().width() > w) w = sizeHint().width();
88  setFixedSize(w, h);
89 
90  // set default: 10%
91  setMode(m_mode);
92  updateDisplay(+0.1);
93 
94  connect(buttonBox_Help->button(QDialogButtonBox::Help), SIGNAL(clicked()),
95  this, SLOT(invokeHelp()));
96 
97  // set the focus onto the "OK" button
98  buttonBox->button(QDialogButtonBox::Ok)->setFocus();
99 }
100 
101 //***************************************************************************
103 {
104  // better stop pre-listen now
105  listenToggled(false);
106 
107  delete m_overview_cache;
108  m_overview_cache = Q_NULLPTR;
109 }
110 
111 //***************************************************************************
113 {
114  double value = m_noise;
115  m_mode = mode;
116  bool old_enable_updates = m_enable_updates;
117  m_enable_updates = false;
118 
119  switch (m_mode) {
120  case MODE_PERCENT: {
121  rbPercentage->setChecked(true);
122 
123  slider->setMinimum(1);
124  slider->setMaximum(100);
125  slider->setPageStep(100);
126  slider->setTickInterval(10);
127  spinbox->setMinimum(1);
128  spinbox->setMaximum(100);
129  break;
130  }
131  case MODE_DECIBEL: {
132  rbLogarithmic->setChecked(true);
133 
134  slider->setMinimum(-21);
135  slider->setMaximum(0);
136  slider->setPageStep(6);
137  slider->setTickInterval(3);
138  spinbox->setMinimum(-21);
139  spinbox->setMaximum(0);
140  break;
141  }
142  }
143 
144  // update the value in the display
145  updateDisplay(value);
146  m_enable_updates = old_enable_updates;
147 }
148 
149 //***************************************************************************
151 {
152  bool old_enable_updates = m_enable_updates;
153  m_enable_updates = false;
154 
155  if (rbPercentage->isChecked()) setMode(MODE_PERCENT);
156  if (rbLogarithmic->isChecked()) setMode(MODE_DECIBEL);
157 
158  m_enable_updates = old_enable_updates;
159 }
160 
161 //***************************************************************************
163 {
164  int new_spinbox_value = 0;
165  int new_slider_value = 0;
166  bool old_enable_updates = m_enable_updates;
167  m_enable_updates = false;
168 
170 
171  if (!qFuzzyCompare(m_noise, value)) {
172 
173  // take over the new factor
174  m_noise = value;
175 
176  // update the preview widget
177  if (m_overview_cache && preview) {
178  int width = preview->width();
179  int height = preview->height();
180  QColor color_bg = Kwave::Colors::Normal.background;
181  QColor color_sig = Kwave::Colors::Normal.interpolated;
182  QColor color_noise = Kwave::Colors::Normal.sample;
183 
184  // get the min/max information
185  int count = m_overview_cache->getMinMax(width, m_minmax);
186 
187  QImage image(width, height, QImage::Format_ARGB32_Premultiplied);
188  QPainter p;
189  p.begin(&image);
190  p.fillRect(image.rect(), color_bg);
191 
192  // calculate scaling factor and (noise level / 2) in pixel
193  const int middle = height >> 1;
194  const int noise_2 = Kwave::toInt(middle * m_noise);
195 
196  /*
197  * mixing of noise goes like this:
198  *
199  * y[t] = x[t] * (1 - n) + noise(t) * n;
200  *
201  * and has this effect on min/max:
202  *
203  * [---noise---] [---noise---]
204  * [min -------------------max]
205  * ^ ^ ^ ^ ^ ^
206  * | | | | | |
207  * y1 y2 y3 y4 y5 y6
208  */
209 
210  for (int x = 0; x < count; ++x) {
211  int y2 = Kwave::toInt((sample2double(m_minmax[x].min) *
212  (1.0 - m_noise)) * middle);
213  int y5 = Kwave::toInt((sample2double(m_minmax[x].max) *
214  (1.0 - m_noise)) * middle);
215  int y1 = y2 - noise_2;
216  int y3 = y2 + noise_2;
217  int y4 = y5 - noise_2;
218  int y6 = y5 + noise_2;
219 
220  if (y4 > y3) {
221  // noise around "min" [y1 ... y3]
222  p.setPen(color_noise);
223  p.drawLine(x, middle - y3, x, middle - y1);
224 
225  // noise around "max" [y4 ... y6]
226  p.drawLine(x, middle - y6, x, middle - y4);
227 
228  // original signal [y3 ... y4 ]
229  p.setPen(color_sig);
230  p.drawLine(x, middle - y4, x, middle - y3);
231  } else {
232  // only noise [y1 ... y6]
233  p.setPen(color_noise);
234  p.drawLine(x, middle - y6, x, middle - y1);
235  }
236  }
237 
238  // zero line
239  p.setCompositionMode(QPainter::CompositionMode_SourceOver);
240  p.setPen(Kwave::Colors::Normal.zero);
241  p.drawLine(0, middle, width - 1, middle);
242 
243  p.end();
244 
245  // update the image view
246  preview->setImage(image);
247  }
248 
249  // emit the noise level change to the plugin
250  emit levelChanged(m_noise);
251  }
252 
253  switch (m_mode) {
254  case MODE_PERCENT: {
255  // factor 1.0 means 100%
256  new_spinbox_value = Kwave::toInt(rint(value * 100.0));
257  new_slider_value = new_spinbox_value;
258  spinbox->setPrefix(_(""));
259  spinbox->setSuffix(_("%"));
260  spinbox->setInverse(false);
261  break;
262  }
263  case MODE_DECIBEL: {
264  // factor 1.0 means 0dB
265  if (!qFuzzyIsNull(value))
266  new_slider_value = Kwave::toInt(rint(20.0 * log10(value)));
267  else
268  new_slider_value = 0;
269  new_spinbox_value = new_slider_value;
270  if (new_spinbox_value >= 0) {
271  spinbox->setPrefix(new_spinbox_value ? _("+") : _("+/- "));
272  } else {
273  // negative value
274  spinbox->setPrefix(_(""));
275  }
276  spinbox->setSuffix(_(" ") + i18n("dB"));
277  spinbox->setInverse(false);
278  break;
279  }
280  }
281 
282  // update the spinbox
283  if (spinbox->value() != new_spinbox_value) spinbox->setValue(new_spinbox_value);
284 
285  // update the slider, it's inverse => top=maximum, bottom=minimum !
286  int sv = slider->maximum() + slider->minimum() - new_slider_value;
287  if (slider->value() != sv) slider->setValue(sv);
288 
289  m_enable_updates = old_enable_updates;
290 }
291 
292 //***************************************************************************
294 {
295  if (!m_enable_updates) return;
296 
297  int sv = slider->maximum() + slider->minimum() - pos;
298  spinboxChanged(sv);
299 }
300 
301 //***************************************************************************
303 {
304  if (!m_enable_updates) return;
305 
306  double factor = m_noise;
307 
308  switch (m_mode) {
309  case MODE_PERCENT:
310  // percentage
311  factor = static_cast<double>(pos) / 100.0;
312  break;
313  case MODE_DECIBEL:
314  // decibel
315  factor = pow(10.0, pos / 20.0);
316  break;
317  }
318 
319  updateDisplay(factor);
320 }
321 
322 //***************************************************************************
324 {
325  QStringList list;
326  list << QString::number(m_noise);
327  list << QString::number(static_cast<int>(m_mode));
328  return list;
329 }
330 
331 //***************************************************************************
333 {
334  // evaluate the parameter list
335  double factor = params[0].toDouble();
336  factor = qBound<double>(0.0, factor, 1.0);
337 
338  switch (params[1].toUInt()) {
339  case 0: m_mode = MODE_PERCENT; break;
340  case 1: m_mode = MODE_DECIBEL; break;
341  default: m_mode = MODE_DECIBEL;
342  }
343 
344  // update mode, using default factor 1.0
345  m_noise = 1.0; // works with every mode
346  setMode(m_mode);
347 
348  // update factor
349  updateDisplay(factor);
350 }
351 
352 //***************************************************************************
354 {
355  Q_ASSERT(btListen);
356  if (!btListen) return;
357 
358  if (listen) {
359  // start pre-listen mode
360  emit startPreListen();
361  btListen->setText(i18n("&Stop"));
362  } else {
363  // stop pre-listen mode
364  emit stopPreListen();
365  btListen->setText(i18n("&Listen"));
366  }
367 }
368 
369 //***************************************************************************
371 {
372  if (btListen) btListen->setChecked(false);
373 }
374 
375 //***************************************************************************
377 {
378  KHelpClient::invokeHelp(_("plugin_sect_noise"));
379 }
380 
381 //***************************************************************************
382 //***************************************************************************
void updateDisplay(double value)
void modeChanged(bool)
Definition: App.h:33
void setMode(Mode mode)
void listenToggled(bool listen)
int getMinMax(int width, MinMaxArray &minmax)
virtual QStringList params() Q_DECL_OVERRIDE
bool connect(Kwave::StreamObject &source, const char *output, Kwave::StreamObject &sink, const char *input)
Definition: Connect.cpp:48
Kwave::OverViewCache * m_overview_cache
Definition: NoiseDialog.h:131
QVector< MinMax > MinMaxArray
Definition: OverViewCache.h:60
NoiseDialog(QWidget *parent, Kwave::OverViewCache *overview_cache)
Definition: NoiseDialog.cpp:44
int toInt(T x)
Definition: Utils.h:127
void spinboxChanged(int pos)
static double sample2double(const sample_t s)
Definition: Sample.h:73
void sliderChanged(int pos)
#define _(m)
Definition: memcpy.c:66
virtual void setParams(QStringList &params) Q_DECL_OVERRIDE
virtual ~NoiseDialog() Q_DECL_OVERRIDE
static double zero(double)
Definition: Functions.cpp:83
static Q_DECL_EXPORT ColorSet Normal
Definition: Colors.h:49
void levelChanged(double level)