kwave  18.07.70
SampleRatePlugin.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  SampleRatePlugin.cpp - sample rate conversion
3  -------------------
4  begin : Tue Jul 07 2009
5  copyright : (C) 2009 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 <errno.h>
20 
21 #include <KLocalizedString> // for the i18n macro
22 
23 #include <QList>
24 #include <QListIterator>
25 #include <QStringList>
26 
27 #include "libkwave/Connect.h"
28 #include "libkwave/FileInfo.h"
29 #include "libkwave/MetaDataList.h"
32 #include "libkwave/PluginManager.h"
33 #include "libkwave/SignalManager.h"
34 #include "libkwave/Utils.h"
35 #include "libkwave/Writer.h"
38 
39 #include "SampleRatePlugin.h"
40 
41 KWAVE_PLUGIN(samplerate, SampleRatePlugin)
42 
43 //***************************************************************************
45  const QVariantList &args)
46  :Kwave::Plugin(parent, args), m_params(), m_new_rate(0.0),
47  m_whole_signal(false)
48 {
49 }
50 
51 //***************************************************************************
53 {
54 }
55 
56 //***************************************************************************
58 {
59  bool ok = false;
60  QString param;
61 
62  // set defaults
63  m_new_rate = 44100.0;
64  m_whole_signal = false;
65 
66  // evaluate the parameter list
67  if (params.count() < 1) return -EINVAL;
68 
69  param = params[0];
70  m_new_rate = param.toDouble(&ok);
71  Q_ASSERT(ok);
72  if (!ok) return -EINVAL;
73 
74  // check whether we should change the whole signal (optional)
75  if (params.count() == 2) {
76  if (params[1] != _("all"))
77  return -EINVAL;
78  m_whole_signal = true;
79  }
80 
81  // all parameters accepted
82  m_params = params;
83 
84  return 0;
85 }
86 
87 //***************************************************************************
88 void Kwave::SampleRatePlugin::run(QStringList params)
89 {
91 
92  // parse parameters
93  if (interpreteParameters(params) < 0)
94  return;
95 
96  double old_rate = Kwave::FileInfo(signalManager().metaData()).rate();
97  if ((old_rate <= 0) || qFuzzyCompare(old_rate, m_new_rate)) return;
98 
99  Kwave::UndoTransactionGuard undo_guard(*this, i18n("Change sample rate"));
100 
101  // get the current selection and the list of affected tracks
102  sample_index_t first = 0;
103  sample_index_t last = 0;
104  sample_index_t length;
105  QList<unsigned int> tracks;
106  if (m_whole_signal) {
107  length = signalLength();
108  last = (length) ? (length - 1) : 0;
109  tracks = mgr.allTracks();
110  } else {
111  length = selection(&tracks, &first, &last, true);
112  if ((length == signalLength()) &&
113  (tracks.count() == Kwave::toInt(mgr.tracks())))
114  {
115  // manually selected the whole signal
116  m_whole_signal = true;
117  }
118  }
119  qDebug("SampleRatePlugin: from %9lu - %9lu (%9lu)",
120  static_cast<unsigned long int>(first),
121  static_cast<unsigned long int>(last),
122  static_cast<unsigned long int>(length));
123  if (!length || tracks.isEmpty()) return;
124 
125  // calculate the new length
126  double ratio = m_new_rate / old_rate;
127  sample_index_t new_length = static_cast<sample_index_t>(length * ratio);
128  if ((new_length == length) || !new_length) return;
129 
130  // if the new length is bigger than the current length,
131  // insert some space at the end
132  if (new_length > length) {
133  qDebug("SampleRatePlugin: inserting %lu at %lu",
134  static_cast<unsigned long int>(new_length - length + 1),
135  static_cast<unsigned long int>(last + 1));
136  mgr.insertSpace(last + 1, new_length - length + 1, tracks);
137  }
138 
140  mgr, tracks, first, last);
141 
142  // connect the progress dialog
143  connect(&source, SIGNAL(progress(qreal)),
144  this, SLOT(updateProgress(qreal)),
145  Qt::BlockingQueuedConnection);
146  emit setProgressText(
147  i18n("Changing sample rate from %1 kHz to %2 kHz...",
148  (old_rate / 1E3), (m_new_rate / 1E3))
149  );
150 
151  // create the converter
153  tracks.count(), this);
154  converter.setAttribute(SLOT(setRatio(QVariant)), QVariant(ratio));
155 
156  // create the writer with the appropriate length
157  Kwave::MultiTrackWriter sink(mgr, tracks, Kwave::Overwrite,
158  first, first + new_length - 1);
159 
160  // connect the objects
161  bool ok = true;
162  if (ok) ok = Kwave::connect(
163  source, SIGNAL(output(Kwave::SampleArray)),
164  converter, SLOT(input(Kwave::SampleArray)));
165  if (ok) ok = Kwave::connect(
166  converter, SIGNAL(output(Kwave::SampleArray)),
167  sink, SLOT(input(Kwave::SampleArray)));
168  if (!ok) {
169  return;
170  }
171 
172  while (!shouldStop() && !source.eof()) {
173  source.goOn();
174  converter.goOn();
175  }
176 
177  sink.flush();
178 
179  // find out how many samples have been written and delete the leftovers
180  sample_index_t written = sink[0]->position() - first;
181 // qDebug("SampleRatePlugin: old=%u, expexted=%u, written=%u",
182 // length, new_length, written);
183  if (written < length) {
184  sample_index_t to_delete = length - written;
185  mgr.deleteRange(written, to_delete, tracks);
186  }
187 
188  // adjust meta data locations
189  Kwave::MetaDataList meta = mgr.metaData().copy(first, last, tracks);
190  if (!meta.isEmpty()) {
191  // adjust all positions in the originally selected range
192  // NOTE: if the ratio is > 1, work backwards, otherwise forward
193 
195  (ratio > 1) ? it.toBack() : it.toFront();
196  while ((ratio > 1) ? it.hasPrevious() : it.hasNext()) {
197  Kwave::MetaData &m = (ratio > 1) ?
198  it.previous().value() : it.next().value();
199 
200  QStringList properties =
202  foreach (const QString &property, properties) {
203  if (!m.hasProperty(property))
204  continue;
205 
206  sample_index_t pos = static_cast<sample_index_t>(
207  m[property].toULongLong());
208  if (pos < first) continue;
209  if (pos > last) continue;
210 
211  // is in our range -> calculate new position
212  pos -= first;
213  pos *= ratio;
214  pos += first;
215 
216  m[property] = pos;
217  }
218  }
219 
220  mgr.metaData().deleteRange(first, last, tracks);
221  mgr.metaData().merge(meta);
222  }
223 
224  // update the selection if it was not empty
225  length = selection(Q_NULLPTR, &first, &last, false);
226  if (length) {
227  if (m_whole_signal) {
228  // if whole signal selected -> adjust start and end
229  first *= ratio;
230  last *= ratio;
231  length = last - first + 1;
232  } else {
233  // only a portion selected -> adjust only length
234  length *= ratio;
235  }
236 
237  mgr.selectRange(first, length);
238  }
239 
240  // set the sample rate if we modified the whole signal
241  if (m_whole_signal) {
242  Kwave::FileInfo info(signalManager().metaData());
243  info.setRate(m_new_rate);
244  mgr.setFileInfo(info, false);
245  }
246 
247 }
248 
249 //***************************************************************************
250 #include "SampleRatePlugin.moc"
251 //***************************************************************************
252 //***************************************************************************
virtual MetaDataList copy(sample_index_t offset, sample_index_t length, const QList< unsigned int > &tracks) const
static QStringList positionBoundPropertyNames()
Definition: MetaData.cpp:155
bool hasProperty(const QString &p) const
Definition: MetaData.cpp:104
void selectRange(sample_index_t offset, sample_index_t length)
Definition: App.h:33
double rate() const
Definition: FileInfo.cpp:415
bool insertSpace(sample_index_t offset, sample_index_t length, const QList< unsigned int > &track_list)
Kwave::MetaDataList & metaData()
virtual void run(QStringList params) Q_DECL_OVERRIDE
Kwave::SignalManager & signalManager()
Definition: Plugin.cpp:444
unsigned int tracks()
quint64 sample_index_t
Definition: Sample.h:28
bool deleteRange(sample_index_t offset, sample_index_t length, const QList< unsigned int > &track_list)
void merge(const MetaDataList &meta_data)
int interpreteParameters(QStringList &params)
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 bool eof() const
void setRate(double rate)
Definition: FileInfo.cpp:424
void setFileInfo(const Kwave::FileInfo &new_info, bool with_undo)
virtual void flush()
int toInt(T x)
Definition: Utils.h:127
QMutableMapIterator< QString, MetaData > MutableIterator
Definition: MetaDataList.h:44
virtual sample_index_t signalLength()
Definition: Plugin.cpp:462
virtual ~SampleRatePlugin() Q_DECL_OVERRIDE
const QList< unsigned int > allTracks()
virtual void deleteRange(sample_index_t offset, sample_index_t length, const QList< unsigned int > &tracks)
#define KWAVE_PLUGIN(name, class)
Definition: Plugin.h:54
#define _(m)
Definition: memcpy.c:66
virtual void updateProgress(qreal progress)
Definition: Plugin.cpp:260
void setProgressText(const QString &text)
bool shouldStop() const
Definition: Plugin.h:120
void setAttribute(const char *attribute, const QVariant &value)
virtual sample_index_t selection(QList< unsigned int > *tracks=Q_NULLPTR, sample_index_t *left=Q_NULLPTR, sample_index_t *right=Q_NULLPTR, bool expand_if_empty=false)
Definition: Plugin.cpp:480