kwave  18.07.70
MP3Decoder.cpp
Go to the documentation of this file.
1 /*************************************************************************
2  MP3Decoder.cpp - decoder for MP3 data
3  -------------------
4  begin : Wed Aug 07 2002
5  copyright : (C) 2002 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 <math.h>
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include <id3/globals.h>
25 #include <id3/misc_support.h>
26 #include <id3/tag.h>
27 
28 #include <QDate>
29 #include <QDateTime>
30 #include <QLatin1Char>
31 #include <QTime>
32 
33 #include "libkwave/Compression.h"
34 #include "libkwave/GenreType.h"
35 #include "libkwave/MessageBox.h"
36 #include "libkwave/MultiWriter.h"
37 #include "libkwave/Sample.h"
38 #include "libkwave/SampleArray.h"
39 #include "libkwave/String.h"
40 #include "libkwave/Utils.h"
41 #include "libkwave/Writer.h"
42 
43 #include "ID3_QIODeviceReader.h"
44 #include "MP3CodecPlugin.h"
45 #include "MP3Decoder.h"
46 
47 //***************************************************************************
49  :Kwave::Decoder(),
50  m_property_map(),
51  m_source(Q_NULLPTR),
52  m_dest(Q_NULLPTR),
53  m_buffer(Q_NULLPTR),
54  m_buffer_size(0),
55  m_prepended_bytes(0),
56  m_appended_bytes(0),
57  m_failures(0),
58  m_parent_widget(Q_NULLPTR)
59 {
62 }
63 
64 //***************************************************************************
66 {
67  if (m_source) close();
68  if (m_buffer) free(m_buffer);
69 }
70 
71 //***************************************************************************
73 {
74  return new MP3Decoder();
75 }
76 
77 //***************************************************************************
78 bool Kwave::MP3Decoder::parseMp3Header(const Mp3_Headerinfo &header,
79  QWidget *widget)
80 {
81  Kwave::FileInfo info(metaData());
82 
83  /* first of all check CRC, it might be senseless if the file is broken */
84  qDebug("crc = 0x%08X", header.crc);
85  if ((header.crc == MP3CRC_MISMATCH) || (header.crc == MP3CRC_ERROR_SIZE)) {
86 
87  if (header.layer == MPEGLAYER_II) {
88  qWarning("WARNING: file is MPEG layer II, CRC calculation "
89  "in id3lib is probably wrong - CRC check skipped");
90  } else {
92  i18n("The file has an invalid checksum.\n"
93  "Do you still want to continue?"),
94  QString(), QString(), QString(),
95  _("accept_mp3_invalid_checksum"))
96  != KMessageBox::Continue) return false;
97  }
98  }
99 
100  /* MPEG layer */
101  switch (header.layer) {
102  case MPEGLAYER_I:
105  info.set(Kwave::INF_MPEG_LAYER, QVariant(1));
106  break;
107  case MPEGLAYER_II:
110  info.set(Kwave::INF_MPEG_LAYER, QVariant(2));
111  break;
112  case MPEGLAYER_III:
115  info.set(Kwave::INF_MPEG_LAYER, QVariant(3));
116  break;
117  default:
118  qWarning("unknown mpeg layer '%d'", header.layer);
119  }
120 
121  /* MPEG version */
122  switch (header.version) {
123  case MPEGVERSION_1:
124  info.set(Kwave::INF_MPEG_VERSION, QVariant(1));
125  break;
126  case MPEGVERSION_2:
127  info.set(Kwave::INF_MPEG_VERSION, QVariant(2));
128  break;
129  case MPEGVERSION_2_5:
130  info.set(Kwave::INF_MPEG_VERSION, QVariant(2.5));
131  break;
132  default:
133  qWarning("unknown mpeg version '%d'", header.version);
134  }
135 
136  /* bit rate */
137  if (header.bitrate > 0) info.set(Kwave::INF_BITRATE_NOMINAL,
138  QVariant(header.bitrate));
139  // NOTE: this is an enum value in libid3, but can also be treated
140  // as unsigned integer without problems!
141 
142  /* channel mode */
143  unsigned int tracks = 0;
144  switch (header.channelmode) {
145  case MP3CHANNELMODE_SINGLE_CHANNEL:
146  tracks = 1;
147  break;
148  case MP3CHANNELMODE_STEREO:
149  tracks = 2;
150  break;
151  case MP3CHANNELMODE_JOINT_STEREO:
152  tracks = 2;
153  break;
154  case MP3CHANNELMODE_DUAL_CHANNEL:
155  tracks = 2;
156  break;
157  default:
158  QString mode;
159  mode = mode.setNum(header.channelmode, 16);
161  i18n("The file contains an invalid channel mode 0x"
162  "%1\nAssuming Mono...", mode))
163  != KMessageBox::Continue) return false;
164  }
165  info.setTracks(tracks);
166 
167  /* MPEG Mode Extension */
168  // only in "Joint Stereo" mode, then depends on Layer
169  //
170  // Layer I+II | Layer III
171  // | Intensity stereo MS Stereo
172  //--------------------------------------------------
173  // 0 - bands 4 to 31 | off off -> 4
174  // 1 - bands 8 to 31 | on off -> 5
175  // 2 - bands 12 to 31 | off on -> 6
176  // 3 - bands 16 to 31 | on on -> 7
177  if (header.channelmode == MP3CHANNELMODE_JOINT_STEREO) {
178  int modeext = header.modeext;
179  if (header.layer >= 3) modeext += 4;
180  info.set(Kwave::INF_MPEG_MODEEXT, modeext);
181  } else {
182  int modeext = header.modeext;
183  info.set(Kwave::INF_MPEG_MODEEXT, modeext);
184  }
185 
186  /* Emphasis mode */
187  // 0 = none
188  // 1 = 50/15ms
189  // 2 = reserved
190  // 3 = CCIT J.17
191  if (header.emphasis > 0)
192  info.set(Kwave::INF_MPEG_EMPHASIS, header.emphasis);
193 
194 // qDebug("framesize=%d", header.framesize);
195 // qDebug("frames = %u", header.frames);
196 
197  if (header.privatebit) info.set(Kwave::INF_PRIVATE, header.privatebit);
198  if (header.copyrighted) info.set(Kwave::INF_COPYRIGHTED, header.copyrighted);
199  if (header.original) info.set(Kwave::INF_ORIGINAL, header.original);
200 
201  info.setRate(header.frequency); // sample rate
202  info.setBits(SAMPLE_BITS); // fake Kwave's default resolution
203  info.setLength(header.time * header.frequency);
204 
206 
207  return true;
208 }
209 
210 //***************************************************************************
212 {
213  if (tag.NumFrames() < 1) return true; // no tags, nothing to do
214 
215  QDate creation_date;
216  QTime creation_time;
217  int year = -1;
218  int month = -1;
219  int day = -1;
220 
221  ID3_Tag::Iterator *it = tag.CreateIterator();
222  ID3_Frame *frame = Q_NULLPTR;
223  Kwave::FileInfo info(metaData());
224  while (it && (frame = it->GetNext())) {
225  const ID3_FrameID id = frame->GetID();
226  const Kwave::FileProperty property = m_property_map.property(id);
228  switch (encoding) {
230  {
231  QString s = parseId3Frame2String(frame);
232  int cd = 0;
233  int cds = 0;
234  if (s.contains(QLatin1Char('/'))) {
235  int i = s.indexOf(QLatin1Char('/'));
236  cd = s.left(i).toInt();
237  cds = s.mid(i + 1).toInt();
238  } else {
239  cd = s.toInt();
240  }
241  if (cd > 0) info.set(Kwave::INF_CD , QVariant(cd));
242  if (cds > 0) info.set(Kwave::INF_CDS, QVariant(cds));
243  break;
244  }
246  {
247  QString s = parseId3Frame2String(frame);
248  int track = 0;
249  int tracks = 0;
250  if (s.contains(QLatin1Char('/'))) {
251  int i = s.indexOf(QLatin1Char('/'));
252  track = s.left(i).toInt();
253  tracks = s.mid(i + 1).toInt();
254  } else {
255  track = s.toInt();
256  }
257  if (track > 0) info.set(Kwave::INF_TRACK , QVariant(track));
258  if (tracks > 0) info.set(Kwave::INF_TRACKS, QVariant(tracks));
259  break;
260  }
262  // the same as ENC_COMMENT, but without "Description"
263  /* FALLTHROUGH */
265  {
266  QString s = parseId3Frame2String(frame);
267 
268  // optionally prepend language
269  char *lang = ID3_GetString(frame, ID3FN_LANGUAGE);
270  if (lang) {
271  s = _("[") + _(lang) + _("] ") + s;
272  ID3_FreeString(lang);
273  }
274 
275  // append to already existing tag, separated by a slash
276  if (info.contains(property))
277  s = info.get(property).toString() + _(" / ") + s;
278  info.set(property, QVariant(s));
279  break;
280  }
282  {
283  QString s = parseId3Frame2String(frame);
284  int genre = Kwave::GenreType::fromID3(s);
285  if (genre >= 0)
286  s = Kwave::GenreType::name(genre, false);
287  info.set(property, QVariant(s));
288  break;
289  }
291  {
292  // length in ms -> convert this to samples
293  QString s = parseId3Frame2String(frame);
294  const double rate = info.rate();
295  bool ok = false;
296  const double ms = s.toDouble(&ok) + 0.5;
297  if (ok && (rate > 0)) {
298  // NOTE: this overwrites the length found in the header!
299  sample_index_t length = static_cast<sample_index_t>(
300  (rate * ms) / 1000.0);
301  info.setLength(length);
302  }
303  break;
304  }
306  {
307  if (!creation_date.isValid()) {
308  QString s = parseId3Frame2String(frame);
309  switch (id)
310  {
311  case ID3FID_RECORDINGDATES:
312  // should be a ISO 8601 timestamp or similar
313  s = Kwave::string2date(s);
314  if (s.length())
315  creation_date =
316  QDate::fromString(s, Qt::ISODate);
317  break;
318  case ID3FID_DATE: {
319  // DDMM
320  unsigned int ddmm = s.toUInt();
321  day = ddmm / 100;
322  month = ddmm % 100;
323  break;
324  }
325  case ID3FID_YEAR: /* FALLTHROUGH */
326  case ID3FID_ORIGYEAR:
327  // YYYY
328  year = s.toUInt();
329  break;
330  default:
331  break;
332  }
333  }
334 
335  if (creation_time.isValid()) {
336  switch (id)
337  {
338  case ID3FID_TIME:
339  creation_time = QTime::fromString(_("hhmm"));
340  break;
341  default:
342  break;
343  }
344  }
345  break;
346  }
348  {
349  // append to already existing tag, separated by a slash
350  QString s = parseId3Frame2String(frame);
351  if (info.contains(property))
352  s = info.get(property).toString() + _(" / ") + s;
353  info.set(property, QVariant(s));
354  break;
355  }
356  case ID3_PropertyMap::ENC_TEXT_URL: /* FALLTHROUGH */
358  info.set(property, QVariant(parseId3Frame2String(frame)));
359  break;
360  case ID3_PropertyMap::ENC_NONE: /* FALLTHROUGH */
361  default:
362  {
363  QString s = parseId3Frame2String(frame);
364  qWarning("unsupported ID3 tag: %d, descr: '%s', text: '%s'",
365  id, frame->GetDescription(), DBG(s));
366  break;
367  }
368  }
369  }
370 
371  /*
372  * try to build a valid creation date/time
373  */
374  if (!creation_date.isValid()) {
375  // no complete creation date - try to reassemble from found y/m/d
376  creation_date = QDate(year, month, day);
377  }
378  if (creation_date.isValid() && creation_time.isValid()) {
379  // full date + time
380  QDateTime dt(creation_date, creation_time);
381  info.set(Kwave::INF_CREATION_DATE, dt.toString(
382  _("yyyy-MM-ddTHH:mm:ss")));
383  } else if (creation_date.isValid()) {
384  // date without time
385  info.set(Kwave::INF_CREATION_DATE, creation_date.toString(
386  _("yyyy-MM-dd")));
387  } else if (year > 0) {
388  // only year
389  creation_date = QDate(year, 1, 1);
390  info.set(Kwave::INF_CREATION_DATE, creation_date.toString(_("yyyy")));
391  }
392 
394 
395  return true;
396 }
397 
398 //***************************************************************************
399 QString Kwave::MP3Decoder::parseId3Frame2String(const ID3_Frame *frame)
400 {
401  QString s;
402  char *text = ID3_GetString(frame, ID3FN_TEXT);
403  if (text && strlen(text)) {
404  s = _(text);
405  ID3_FreeString(text);
406  }
407  return s;
408 }
409 
410 //***************************************************************************
411 bool Kwave::MP3Decoder::open(QWidget *widget, QIODevice &src)
412 {
413  qDebug("MP3Decoder::open()");
414  metaData().clear();
415  Q_ASSERT(!m_source);
416  if (m_source) qWarning("MP3Decoder::open(), already open !");
417 
418  /* open the file in readonly mode with seek enabled */
419  if (src.isSequential()) return false;
420  if (!src.open(QIODevice::ReadOnly)) {
421  qWarning("unable to open source in read-only mode!");
422  return false;
423  }
424 
425  /* read all available ID3 tags */
426  ID3_Tag tag;
427  ID3_QIODeviceReader adapter(src);
428  tag.Link(adapter, static_cast<flags_t>(ID3TT_ALL));
429 
430  qDebug("NumFrames = %u", Kwave::toUint(tag.NumFrames()));
432  if (tag.GetSpec() != ID3V2_UNKNOWN) {
433  qDebug("Size = %u", Kwave::toUint(tag.Size()));
434  }
435  qDebug("HasLyrics = %d", tag.HasLyrics());
436  qDebug("HasV1Tag = %d", tag.HasV1Tag());
437  qDebug("HasV2Tag = %d", tag.HasV2Tag());
438 
439  m_prepended_bytes = tag.GetPrependedBytes();
440  m_appended_bytes = tag.GetAppendedBytes();
441  qDebug("prepended=%lu, appended=%lu", m_prepended_bytes, m_appended_bytes);
442 
443  const Mp3_Headerinfo *mp3hdr = tag.GetMp3HeaderInfo();
444  if (!mp3hdr) {
446  i18n("The opened file is no MPEG file or it is damaged.\n"
447  "No header information has been found."));
448  return false;
449  }
450 
451  /* parse the MP3 header */
452  if (!parseMp3Header(*mp3hdr, widget)) return false;
453 
454  /* parse the ID3 tags */
455  if (!parseID3Tags(tag)) return false;
456 
457  /* accept the source */
458  m_source = &src;
459  Kwave::FileInfo info(metaData());
460  info.set(Kwave::INF_MIMETYPE, _("audio/mpeg"));
462 
463  // allocate a transfer buffer with 128 kB
464  if (m_buffer) free(m_buffer);
465  m_buffer_size = (128 << 10);
466 
467  m_buffer = static_cast<unsigned char *>(malloc(m_buffer_size));
468  if (!m_buffer) return false; // out of memory :-(
469 
470  return true;
471 }
472 
473 //***************************************************************************
474 static enum mad_flow _input_adapter(void *data, struct mad_stream *stream)
475 {
476  Kwave::MP3Decoder *decoder = reinterpret_cast<Kwave::MP3Decoder *>(data);
477  Q_ASSERT(decoder);
478  return (decoder) ? decoder->fillInput(stream) : MAD_FLOW_STOP;
479 }
480 
481 //***************************************************************************
482 static enum mad_flow _output_adapter(void *data,
483  struct mad_header const *header,
484  struct mad_pcm *pcm)
485 {
486  Kwave::MP3Decoder *decoder = reinterpret_cast<Kwave::MP3Decoder *>(data);
487  Q_ASSERT(decoder);
488  return (decoder) ?
489  decoder->processOutput(data, header, pcm) : MAD_FLOW_STOP;
490 }
491 
492 //***************************************************************************
493 static enum mad_flow _error_adapter(void *data, struct mad_stream *stream,
494  struct mad_frame *frame)
495 {
496  Kwave::MP3Decoder *decoder = reinterpret_cast<Kwave::MP3Decoder *>(data);
497  Q_ASSERT(decoder);
498  return (decoder) ?
499  decoder->handleError(data, stream, frame) : MAD_FLOW_BREAK;
500 }
501 
502 //***************************************************************************
503 enum mad_flow Kwave::MP3Decoder::handleError(void */*data*/,
504  struct mad_stream *stream, struct mad_frame */*frame*/)
505 {
506  if (m_failures >= 2) return MAD_FLOW_CONTINUE; // ignore errors
507  if (stream->error == MAD_ERROR_NONE) return MAD_FLOW_CONTINUE; // ???
508 
509  QString error;
510  switch (stream->error) {
511  case MAD_ERROR_BUFLEN:
512  case MAD_ERROR_BUFPTR:
513  case MAD_ERROR_NOMEM:
514  error = i18n("Out of memory");
515  break;
516  case MAD_ERROR_BADCRC:
517  error = i18n("Checksum error");
518  break;
519  case MAD_ERROR_LOSTSYNC:
520  error = i18n("Synchronization lost");
521  break;
522  case MAD_ERROR_BADLAYER:
523  case MAD_ERROR_BADBITRATE:
524  case MAD_ERROR_BADSAMPLERATE:
525  case MAD_ERROR_BADEMPHASIS:
526  case MAD_ERROR_BADBITALLOC:
527  case MAD_ERROR_BADSCALEFACTOR:
528  case MAD_ERROR_BADFRAMELEN:
529  case MAD_ERROR_BADBIGVALUES:
530  case MAD_ERROR_BADBLOCKTYPE:
531  case MAD_ERROR_BADSCFSI:
532  case MAD_ERROR_BADDATAPTR:
533  case MAD_ERROR_BADPART3LEN:
534  case MAD_ERROR_BADHUFFTABLE:
535  case MAD_ERROR_BADHUFFDATA:
536  case MAD_ERROR_BADSTEREO:
537  error = i18n("File contains invalid data");
538  break;
539  default:
540  QString err_hex = QString::number(
541  static_cast<int>(stream->error), 16).toUpper();
542  error = i18n("Unknown error 0x%1. Damaged file?", err_hex);
543  }
544 
545  long unsigned int pos = stream->this_frame - m_buffer;
546  int result = 0;
547  error = i18n("An error occurred while decoding the file:\n'%1',\n"
548  "at position %2.", error, pos);
549  if (!m_failures) {
550  m_failures = 1;
552  error + _("\n") + i18n("Do you still want to continue?"));
553  if (result != KMessageBox::Continue) return MAD_FLOW_BREAK;
554  } else if (m_failures == 1) {
556  error + _("\n") +
557  i18n("Do you want to continue and ignore all following errors?"));
558  m_failures++;
559  if (result != KMessageBox::Yes) return MAD_FLOW_BREAK;
560  }
561 
562  return MAD_FLOW_CONTINUE;
563 }
564 
565 //***************************************************************************
566 enum mad_flow Kwave::MP3Decoder::fillInput(struct mad_stream *stream)
567 {
568  Q_ASSERT(m_source);
569  if (!m_source) return MAD_FLOW_STOP;
570 
571  // check if the user pressed cancel
572  if (m_dest->isCanceled()) return MAD_FLOW_STOP;
573 
574  // preserve the remaining bytes from the last pass
575  size_t rest = stream->bufend - stream->next_frame;
576  if (rest) memmove(m_buffer, stream->next_frame, rest);
577 
578  // clip source at "eof-appended_bytes"
579  size_t bytes_to_read = m_buffer_size - rest;
580  if (m_source->pos() + bytes_to_read > m_source->size() - m_appended_bytes)
581  bytes_to_read = Kwave::toUint(
582  m_source->size() - m_appended_bytes - m_source->pos());
583 
584  // abort if nothing more to read, even if there are
585  // some "left-overs" from the previous pass
586  if (!bytes_to_read) return MAD_FLOW_STOP;
587 
588  // read from source to fill up the buffer
589  size_t size = rest;
590  if (bytes_to_read) size += m_source->read(
591  reinterpret_cast<char *>(m_buffer) + rest, bytes_to_read);
592  if (!size) return MAD_FLOW_STOP; // no more data
593 
594  // buffer is filled -> process it
595  mad_stream_buffer(stream, m_buffer, size);
596 
597  return MAD_FLOW_CONTINUE;
598 }
599 
604 namespace Kwave {
605  typedef struct {
606  mad_fixed_t error[3];
607  mad_fixed_t random;
608  } audio_dither;
609 }
610 
616 static inline quint32 prng(quint32 state)
617 {
618  return (state * 0x0019660dL + 0x3c6ef35fL) & 0xffffffffL;
619 }
620 
626 static inline qint32 audio_linear_dither(unsigned int bits,
627  mad_fixed_t sample, Kwave::audio_dither *dither)
628 {
629  unsigned int scalebits;
630  mad_fixed_t output, mask, random;
631 
632  enum {
633  MIN = -MAD_F_ONE,
634  MAX = MAD_F_ONE - 1
635  };
636 
637  /* noise shape */
638  sample += dither->error[0] - dither->error[1] + dither->error[2];
639 
640  dither->error[2] = dither->error[1];
641  dither->error[1] = dither->error[0] / 2;
642 
643  /* bias */
644  output = sample + mad_fixed_t(1L << (MAD_F_FRACBITS + 1 - bits - 1));
645 
646  scalebits = MAD_F_FRACBITS + 1 - bits;
647  mask = mad_fixed_t(1L << scalebits) - 1;
648 
649  /* dither */
650  random = static_cast<mad_fixed_t>(prng(dither->random));
651  output += (random & mask) - (dither->random & mask);
652 
653  dither->random = random;
654 
655  /* clip */
656  if (output > MAX) {
657  output = MAX;
658  if (sample > MAX) sample = MAX;
659  } else if (output < MIN) {
660  output = MIN;
661  if (sample < MIN) sample = MIN;
662  }
663 
664  /* quantize */
665  output &= ~mask;
666 
667  /* error feedback */
668  dither->error[0] = sample - output;
669 
670  /* scale */
671  return output >> scalebits;
672 }
673 
674 //***************************************************************************
675 enum mad_flow Kwave::MP3Decoder::processOutput(void */*data*/,
676  struct mad_header const */*header*/, struct mad_pcm *pcm)
677 {
678  static Kwave::audio_dither dither;
679  qint32 sample;
680  Kwave::SampleArray buffer(pcm->length);
681 
682  // loop over all tracks
683  const unsigned int tracks = m_dest->tracks();
684  for (unsigned int track = 0; track < tracks; ++track) {
685  unsigned int nsamples = pcm->length;
686  mad_fixed_t const *p = pcm->samples[track];
687  unsigned int ofs = 0;
688 
689  // and render samples into Kwave's internal format
690  while (nsamples--) {
691  sample = static_cast<qint32>(audio_linear_dither(SAMPLE_BITS,
692  static_cast<mad_fixed_t>(*p++), &dither));
693  buffer[ofs++] = static_cast<sample_t>(sample);
694  }
695  *(*m_dest)[track] << buffer;
696  }
697 
698  return MAD_FLOW_CONTINUE;
699 }
700 
701 //***************************************************************************
703 {
704  Q_ASSERT(m_source);
705  if (!m_source) return false;
706  m_source->seek(m_prepended_bytes); // skip id3v2 tag
707 
708  // set target of the decoding
709  m_dest = &dst;
710  m_failures = 0;
711  m_parent_widget = widget;
712 
713  // setup the decoder
714  struct mad_decoder decoder;
715  mad_decoder_init(&decoder, this,
717  Q_NULLPTR /* header */,
718  Q_NULLPTR /* filter */,
721  Q_NULLPTR /* message */);
722 
723  // decode through libmad...
724  int result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
725 
726  // release the decoder
727  mad_decoder_finish(&decoder);
728 
729  return (result == 0);
730 }
731 
732 //***************************************************************************
734 {
735  m_source = Q_NULLPTR;
736 }
737 
738 //***************************************************************************
739 //***************************************************************************
bool contains(const FileProperty property) const
Definition: FileInfo.cpp:354
ID3_PropertyMap m_property_map
Definition: MP3Decoder.h:106
virtual unsigned int tracks() const Q_DECL_OVERRIDE
QString parseId3Frame2String(const ID3_Frame *frame)
Definition: MP3Decoder.cpp:399
virtual bool open(QWidget *widget, QIODevice &source)
Definition: MP3Decoder.cpp:411
mad_fixed_t random
Definition: MP3Decoder.cpp:607
Definition: App.h:33
static QString name(int id, bool localized)
Definition: GenreType.cpp:34
static qint32 audio_linear_dither(unsigned int bits, mad_fixed_t sample, Kwave::audio_dither *dither)
Definition: MP3Decoder.cpp:626
double rate() const
Definition: FileInfo.cpp:415
static quint32 prng(quint32 state)
Definition: MP3Decoder.cpp:616
static enum mad_flow _error_adapter(void *data, struct mad_stream *stream, struct mad_frame *frame)
Definition: MP3Decoder.cpp:493
virtual void close()
Definition: MP3Decoder.cpp:733
QVariant get(FileProperty key) const
Definition: FileInfo.cpp:372
virtual ~MP3Decoder()
Definition: MP3Decoder.cpp:65
mad_fixed_t error[3]
Definition: MP3Decoder.cpp:606
size_t m_appended_bytes
Definition: MP3Decoder.h:124
static int sorry(QWidget *widget, QString message, QString caption=QString())
Definition: MessageBox.cpp:85
quint64 sample_index_t
Definition: Sample.h:28
static enum mad_flow _output_adapter(void *data, struct mad_header const *header, struct mad_pcm *pcm)
Definition: MP3Decoder.cpp:482
unsigned char * m_buffer
Definition: MP3Decoder.h:115
void set(FileProperty key, const QVariant &value)
Definition: FileInfo.cpp:363
void setRate(double rate)
Definition: FileInfo.cpp:424
QString Q_DECL_EXPORT string2date(const QString &s)
Definition: Utils.cpp:126
enum mad_flow handleError(void *data, struct mad_stream *stream, struct mad_frame *frame)
Definition: MP3Decoder.cpp:503
void setLength(sample_index_t length)
Definition: FileInfo.cpp:409
virtual bool decode(QWidget *widget, Kwave::MultiWriter &dst)
Definition: MP3Decoder.cpp:702
void setTracks(unsigned int tracks)
Definition: FileInfo.cpp:454
virtual void replace(const MetaDataList &list)
virtual Kwave::MetaDataList & metaData()
Definition: Decoder.h:78
#define REGISTER_MIME_TYPES
static int warningYesNo(QWidget *widget, QString message, QString caption=QString(), const QString buttonYes=QString(), const QString buttonNo=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:93
enum mad_flow processOutput(void *data, struct mad_header const *header, struct mad_pcm *pcm)
Definition: MP3Decoder.cpp:675
bool isCanceled() const
Definition: MultiWriter.h:64
Kwave::MultiWriter * m_dest
Definition: MP3Decoder.h:112
static int warningContinueCancel(QWidget *widget, QString message, QString caption=QString(), const QString buttonContinue=QString(), const QString buttonCancel=QString(), const QString &dontAskAgainName=QString())
Definition: MessageBox.cpp:115
unsigned int m_failures
Definition: MP3Decoder.h:127
void setBits(unsigned int bits)
Definition: FileInfo.cpp:439
QWidget * m_parent_widget
Definition: MP3Decoder.h:130
static enum mad_flow _input_adapter(void *data, struct mad_stream *stream)
Definition: MP3Decoder.cpp:474
#define REGISTER_COMPRESSION_TYPES
bool parseID3Tags(ID3_Tag &tag)
Definition: MP3Decoder.cpp:211
Encoding encoding(const ID3_FrameID id) const
#define _(m)
Definition: memcpy.c:66
QIODevice * m_source
Definition: MP3Decoder.h:109
bool parseMp3Header(const Mp3_Headerinfo &header, QWidget *widget)
Definition: MP3Decoder.cpp:78
#define DBG(qs)
Definition: String.h:55
Kwave::FileProperty property(const ID3_FrameID id) const
unsigned int toUint(T x)
Definition: Utils.h:109
static int fromID3(const QString &tag)
Definition: GenreType.cpp:45
FileProperty
Definition: FileInfo.h:45
size_t m_prepended_bytes
Definition: MP3Decoder.h:121
#define SAMPLE_BITS
Definition: Sample.h:43
enum mad_flow fillInput(struct mad_stream *stream)
Definition: MP3Decoder.cpp:566
virtual Kwave::Decoder * instance()
Definition: MP3Decoder.cpp:72
qint32 sample_t
Definition: Sample.h:37