Audacity  3.0.3
Public Member Functions | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
MP3ImportFileHandle Class Referencefinal

An ImportFileHandle for MP3 data. More...

Inheritance diagram for MP3ImportFileHandle:
[legend]
Collaboration diagram for MP3ImportFileHandle:
[legend]

Public Member Functions

 MP3ImportFileHandle (const FilePath &filename)
 
 ~MP3ImportFileHandle ()
 
TranslatableString GetFileDescription () override
 
ByteCount GetFileUncompressedBytes () override
 
ProgressResult Import (WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override
 
wxInt32 GetStreamCount () override
 
const TranslatableStringsGetStreamInfo () override
 
void SetStreamUsage (wxInt32 StreamID, bool Use) override
 
- Public Member Functions inherited from ImportFileHandle
 ImportFileHandle (const FilePath &filename)
 
virtual ~ImportFileHandle ()
 
void CreateProgress ()
 

Private Member Functions

bool Open ()
 
void CheckTags ()
 
void CheckAPETags (bool atEnd)
 
void CheckID3V1Tags ()
 
void CheckID3V2Tags (bool atEnd)
 
void CheckLyrics ()
 
bool CheckMP3 ()
 
bool FillBuffer ()
 
void LoadID3 (Tags *tags)
 
mad_flow InputCB (struct mad_stream *stream)
 
mad_flow FilterCB (struct mad_stream const *stream, struct mad_frame *frame)
 
mad_flow OutputCB (struct mad_header const *header, struct mad_pcm *pcm)
 
mad_flow ErrorCB (struct mad_stream *stream, struct mad_frame *frame)
 

Static Private Member Functions

static mad_flow input_cb (void *that, struct mad_stream *stream)
 
static mad_flow filter_cb (void *that, struct mad_stream const *stream, struct mad_frame *frame)
 
static mad_flow output_cb (void *that, struct mad_header const *header, struct mad_pcm *pcm)
 
static mad_flow error_cb (void *that, struct mad_stream *stream, struct mad_frame *frame)
 

Private Attributes

mad_decoder mDecoder
 
wxFile mFile
 
wxFileOffset mFilePos
 
wxFileOffset mFileLen
 
unsigned char mInputBuffer [INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD]
 
int mInputBufferLen
 
WaveTrackFactorymTrackFactory
 
NewChannelGroup mChannels
 
unsigned mNumChannels
 
ProgressResult mUpdateResult
 
int mDelay
 
int mPadding
 
bool mHaveID3
 
friend MP3ImportPlugin
 

Additional Inherited Members

- Public Types inherited from ImportFileHandle
using ProgressResult = BasicUI::ProgressResult
 
using ByteCount = unsigned long long
 
- Static Public Member Functions inherited from ImportFileHandle
static sampleFormat ChooseFormat (sampleFormat effectiveFormat)
 Choose appropriate format, which will not be narrower than the specified one. More...
 
- Protected Member Functions inherited from ImportFileHandle
std::shared_ptr< WaveTrackNewWaveTrack (WaveTrackFactory &trackFactory, sampleFormat effectiveFormat, double rate)
 Build a wave track with appropriate format, which will not be narrower than the specified one. More...
 
- Protected Attributes inherited from ImportFileHandle
FilePath mFilename
 
std::unique_ptr< ProgressDialogmProgress
 

Detailed Description

An ImportFileHandle for MP3 data.

Audacity has finally moved to using a single mp3 library on all platforms! It is the high performance, beautifully written libmad (mpeg audio decoder). Finally there is harmony in the mp3 universe.

Much of this source code is based on 'minimad.c' as distributed with libmad.

Definition at line 105 of file ImportMP3.cpp.

Constructor & Destructor Documentation

◆ MP3ImportFileHandle()

MP3ImportFileHandle::MP3ImportFileHandle ( const FilePath filename)

Definition at line 220 of file ImportMP3.cpp.

221 : ImportFileHandle(filename)
222 {
223 }

◆ ~MP3ImportFileHandle()

MP3ImportFileHandle::~MP3ImportFileHandle ( )

Definition at line 225 of file ImportMP3.cpp.

226 {
227 }

Member Function Documentation

◆ CheckAPETags()

void MP3ImportFileHandle::CheckAPETags ( bool  atEnd)
private

Definition at line 385 of file ImportMP3.cpp.

386 {
387  int offset = atEnd ? mFileLen - 32 : mFilePos;
388 
389  // Ensure file is positioned to start of (possible) tags
390  if (mFile.Seek(offset, wxFromStart) == wxInvalidOffset || mFile.Error())
391  {
392  return;
393  }
394 
395  // An APE tag header is 32 bytes
396  if (mFile.Read(mInputBuffer, 32) != 32 || mFile.Error())
397  {
398  return;
399  }
400 
401  // Do we have an APE preamble?
402  if (memcmp(mInputBuffer, "APETAGEX", 8) != 0)
403  {
404  return;
405  }
406 
407  // Get the (little endian) length
408  wxFileOffset len = (mInputBuffer[12] & 0xff) |
409  ((mInputBuffer[13] & 0xff) << 8) |
410  ((mInputBuffer[14] & 0xff) << 16) |
411  ((mInputBuffer[15] & 0xff) << 24);
412 
413  // Get needed flags
414  bool hasHeader = mInputBuffer[23] & 0x80;
415 
416  // Skip the tags
417  if (!atEnd)
418  {
419  mFilePos += (32 + len);
420  }
421  else
422  {
423  mFileLen -= ((hasHeader ? 32 : 0) + len);
424  }
425 }

References mFile, mFileLen, mFilePos, and mInputBuffer.

Referenced by CheckTags().

Here is the caller graph for this function:

◆ CheckID3V1Tags()

void MP3ImportFileHandle::CheckID3V1Tags ( )
private

Definition at line 427 of file ImportMP3.cpp.

428 {
429  // Ensure file is positioned to start of (possible) tags
430  if (mFile.Seek(mFileLen - 128, wxFromStart) == wxInvalidOffset || mFile.Error())
431  {
432  return;
433  }
434 
435  // An ID3v1 tag header is 3 bytes
436  if (mFile.Read(mInputBuffer, 3) != 3 || mFile.Error())
437  {
438  return;
439  }
440 
441  // Do we have ID3v1 tags?
442  if (memcmp(mInputBuffer, "TAG", 3) != 0)
443  {
444  return;
445  }
446 
447  // Adjust file length
448  mFileLen -= 128;
449 
450  // Remember that we have tags
451  mHaveID3 = true;
452 }

References mFile, mFileLen, mHaveID3, and mInputBuffer.

Referenced by CheckTags().

Here is the caller graph for this function:

◆ CheckID3V2Tags()

void MP3ImportFileHandle::CheckID3V2Tags ( bool  atEnd)
private

Definition at line 520 of file ImportMP3.cpp.

521 {
522  int offset = atEnd ? mFileLen - 10 : mFilePos;
523 
524  // Ensure file is positioned to start of (possible) tags
525  if (mFile.Seek(offset, wxFromStart) == wxInvalidOffset || mFile.Error())
526  {
527  return;
528  }
529 
530  // An ID3v2 tag header is 10 bytes
531  if (mFile.Read(mInputBuffer, 10) != 10 || mFile.Error())
532  {
533  return;
534  }
535 
536  // Do we have an ID3v2 header or footer?
537  if (memcmp(mInputBuffer, atEnd ? "3DI" : "ID3", 3) != 0)
538  {
539  return;
540  }
541 
542  // Get and decode the length
543  wxFileOffset len = (mInputBuffer[6] & 0x7f);
544  len = (len << 7) | (mInputBuffer[7] & 0x7f);
545  len = (len << 7) | (mInputBuffer[8] & 0x7f);
546  len = (len << 7) | (mInputBuffer[9] & 0x7f);
547 
548  // Skip the tags
549  if (!atEnd)
550  {
551  mFilePos += (10 + len);
552  }
553  else
554  {
555  mFileLen -= (10 + len + 10);
556  }
557 
558  // Remember that we have tags
559  mHaveID3 = true;
560 }

References mFile, mFileLen, mFilePos, mHaveID3, and mInputBuffer.

Referenced by CheckTags().

Here is the caller graph for this function:

◆ CheckLyrics()

void MP3ImportFileHandle::CheckLyrics ( )
private

Definition at line 454 of file ImportMP3.cpp.

455 {
456  int offset = mFileLen - 9;
457 
458  // Ensure file is positioned to start of (possible) lyrics
459  if (mFile.Seek(offset, wxFromStart) == wxInvalidOffset || mFile.Error())
460  {
461  return;
462  }
463 
464  // An Lyrics3 footeris 9 bytes
465  if (mFile.Read(mInputBuffer, 9) != 9 || mFile.Error())
466  {
467  return;
468  }
469 
470  // Found a v1 Lyrics footer?
471  if (memcmp(mInputBuffer, "LYRICSEND", 9) == 0)
472  {
473  wxFileOffset pos = wxMax(offset - 5100, 0);
474  size_t len = offset - pos;
475 
476  // Ensure file is positioned to start of (possible) lyrics
477  if (mFile.Seek(pos, wxFromStart) == wxInvalidOffset || mFile.Error())
478  {
479  return;
480  }
481 
482  // Read the lyrics
483  if (mFile.Read(mInputBuffer, len) != len || mFile.Error())
484  {
485  return;
486  }
487 
488  // Search forward to find the beginning of the lyrics
489  for (size_t i = 0; i < len; ++i)
490  {
491  if (memcmp(&mInputBuffer[i], "LYRICSBEGIN", 11) == 0)
492  {
493  // Adjust the file length to exclude the lyrics
494  mFileLen = pos + i;
495  break;
496  }
497  }
498  }
499  // Found a v2 Lyrics footer?
500  else if (memcmp(mInputBuffer, "LYRICS200", 9) == 0)
501  {
502  // Ensure file is positioned to start of (possible) lyrics
503  if (mFile.Seek(-15, wxFromCurrent) == wxInvalidOffset || mFile.Error())
504  {
505  return;
506  }
507 
508  // An Lyrics3v2 length is 6 bytes
509  if (mFile.Read(mInputBuffer, 6) != 6 || mFile.Error())
510  {
511  return;
512  }
513 
514  // Adjust the file length to exclude the lyrics
515  mInputBuffer[6] = 0;
516  mFileLen -= (wxAtoi((char *) mInputBuffer) + 15);
517  }
518 }

References mFile, mFileLen, and mInputBuffer.

Referenced by CheckTags().

Here is the caller graph for this function:

◆ CheckMP3()

bool MP3ImportFileHandle::CheckMP3 ( )
private

Definition at line 562 of file ImportMP3.cpp.

563 {
564  wxFileOffset savedPos = mFilePos;
565 
566  // Ensure file is positioned to start of 1st mp3 frame
567  if (mFile.Seek(mFilePos, wxFromStart) == wxInvalidOffset || mFile.Error())
568  {
569  return false;
570  }
571 
572  // Load as much as will fit into the buffer
573  if (!FillBuffer())
574  {
575  return false;
576  }
577 
578  // Initialize mad stream
579  mad_stream stream;
580  mad_stream_init(&stream);
581  mad_stream_buffer(&stream, mInputBuffer, mInputBufferLen);
582 
583  // And header
584  mad_header header;
585  mad_header_init(&header);
586 
587  // Scan the input buffer for 2 consecutive MP3 frames. When the header
588  // decoder finds a frame, it decodes it and ensures it is followed by
589  // another frame or EOF...thus 2 (or 1) consecutive frame(s) are detected.
590  int consecutive = 1;
591  while (consecutive > 0)
592  {
593  // Decode the header at the current stream position.
594  if (mad_header_decode(&header, &stream))
595  {
596  // End of buffer.
597  if (stream.error != MAD_ERROR_NONE)
598  {
599  break;
600  }
601  }
602 
603  consecutive -= 1;
604  }
605 
606  // Remember how many bytes were processed
607  int used = stream.this_frame - stream.buffer;
608 
609  // Cleanup
610  mad_header_finish(&header);
611  mad_stream_finish(&stream);
612 
613  // Did we find all that we wanted?
614  if (consecutive)
615  {
616  return false;
617  }
618 
619  // Reset file controls
620  mInputBufferLen = 0;
621 
622  // Reposition file to start of mp3 frames to prepare for the Import.
623  mFilePos = savedPos + used;
624  if (mFile.Seek(mFilePos, wxFromStart) == wxInvalidOffset || mFile.Error())
625  {
626  return false;
627  }
628 
629  // Looks like an MP3...
630  return true;
631 }

References FillBuffer(), mFile, mFilePos, mInputBuffer, and mInputBufferLen.

Referenced by Open().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ CheckTags()

void MP3ImportFileHandle::CheckTags ( )
private

Definition at line 363 of file ImportMP3.cpp.

364 {
365  // We do this twice to allow them to be in any order
366  for (int i = 0; i < 2; ++i)
367  {
368  CheckAPETags(false);
369  CheckID3V2Tags(false);
370  }
371 
372  // We do this twice to allow them to be in any order. Even though ID3v1 is
373  // supposed to at the end, some apps put the v2 tags after the v1 tags.
374  for (int i = 0; i < 2; ++i)
375  {
376  CheckAPETags(true);
377  CheckID3V1Tags();
378  CheckLyrics();
379  CheckID3V2Tags(true);
380  }
381 
382  return;
383 }

References CheckAPETags(), CheckID3V1Tags(), CheckID3V2Tags(), and CheckLyrics().

Referenced by Open().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ error_cb()

mad_flow MP3ImportFileHandle::error_cb ( void *  that,
struct mad_stream stream,
struct mad_frame frame 
)
staticprivate

Definition at line 1072 of file ImportMP3.cpp.

1075 {
1076  auto cb = [&]()
1077  {
1078  return ((MP3ImportFileHandle *) that)->ErrorCB(stream, frame);
1079  };
1080 
1081  return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
1082 }

Referenced by Import().

Here is the caller graph for this function:

◆ ErrorCB()

enum mad_flow MP3ImportFileHandle::ErrorCB ( struct mad_stream stream,
struct mad_frame frame 
)
private

Definition at line 1072 of file ImportMP3.cpp.

1086 {
1087  // You always get a LOSTSYNC error at EOF, so just ignore it
1088  if (stream->error == MAD_ERROR_LOSTSYNC && mFilePos == mFileLen)
1089  {
1090  return MAD_FLOW_CONTINUE;
1091  }
1092 
1093  // This can happen when parsing the first frame. We can use the number of channels
1094  // to test for this since it hasn't been determined yet.
1095  if (stream->error == MAD_ERROR_BADDATAPTR && mNumChannels == 0)
1096  {
1097  return MAD_FLOW_CONTINUE;
1098  }
1099 
1100  // Let the user know about the error
1101  using namespace BasicUI;
1102  ShowErrorDialog( {},
1103  DefaultCaption(),
1104  XO("Import failed\n\nThis is likely caused by a malformed MP3.\n\n"),
1105  "Opening_malformed_MP3_files");
1106  return MAD_FLOW_BREAK;
1107 }

References MakeSimpleGuard().

Here is the call graph for this function:

◆ FillBuffer()

bool MP3ImportFileHandle::FillBuffer ( )
private

Definition at line 633 of file ImportMP3.cpp.

634 {
635  // We either want enough to fill the input buffer or what's left in the file
636  auto want = wxMin(INPUT_BUFFER_SIZE - mInputBufferLen, mFileLen - mFilePos);
637  if (want > 0)
638  {
639  // We should always get what we ask for
640  auto got = mFile.Read(&mInputBuffer[mInputBufferLen], want);
641  if (got != want || mFile.Error())
642  {
643  return false;
644  }
645 
646  // Adjust input control
647  mInputBufferLen += got;
648  mFilePos += got;
649  }
650 
651  // MAD requires that we add MAD_BUFFER_GUARD extra bytes when we've processed
652  // all of the MP3 frames. Otherwise, we will drop the last frame.
653  if (mFilePos == mFileLen)
654  {
655  memset(&mInputBuffer[mInputBufferLen], 0, MAD_BUFFER_GUARD);
656  mInputBufferLen += MAD_BUFFER_GUARD;
657  }
658 
659  return true;
660 }

References INPUT_BUFFER_SIZE, mFile, mFileLen, mFilePos, mInputBuffer, and mInputBufferLen.

Referenced by CheckMP3(), and InputCB().

Here is the caller graph for this function:

◆ filter_cb()

mad_flow MP3ImportFileHandle::filter_cb ( void *  that,
struct mad_stream const *  stream,
struct mad_frame frame 
)
staticprivate

Definition at line 905 of file ImportMP3.cpp.

908 {
909  auto cb = [&]()
910  {
911  return ((MP3ImportFileHandle *) that)->FilterCB(stream, frame);
912  };
913 
914  return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
915 }

References FilterCB(), and MakeSimpleGuard().

Referenced by Import().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ FilterCB()

mad_flow MP3ImportFileHandle::FilterCB ( struct mad_stream const *  stream,
struct mad_frame frame 
)
private

Definition at line 917 of file ImportMP3.cpp.

919 {
920  // We only want to jinspect the first frame, so disable future calls
921  mDecoder.filter_func = nullptr;
922 
923  // Is it a VBRI info frame?
924  if (memcmp(&stream->this_frame[4 + 32], "VBRI", 4) == 0)
925  {
926  mDelay = (stream->this_frame[4 + 32 + 6] & 0xff) << 8 |
927  (stream->this_frame[4 + 32 + 7] & 0xff);
928 
929  return MAD_FLOW_CONTINUE;
930  }
931 
932  // Look for Xing/Info information
933 
934  // Get the ancillary data ptr and length. If the frame has CRC protection, we make
935  // a small adjustment to get around an apparent bug in libmad.
936  auto ptr = stream->anc_ptr.byte - (frame->header.flags & MAD_FLAG_PROTECTION ? 2 : 0);
937  int len = stream->anc_bitlen / 8;
938 
939  // Ensure it's something we can understand
940  if (len < 4 || (memcmp(ptr, "Xing", 4) != 0 && memcmp(ptr, "Info", 4) != 0))
941  {
942  return MAD_FLOW_CONTINUE;
943  }
944 
945  // Skip the tag
946  ptr += 4;
947  len -= 4;
948 
949  enum flagBits
950  {
951  hasFrames = 0x0001,
952  hasBytes = 0x0002,
953  hasToc = 0x0004,
954  hasScale = 0x0008
955  };
956 
957  // Extract the flags
958  unsigned int flags = (((((ptr[0] << 8) + ptr[1]) << 8) + ptr[2]) << 8) + ptr[3];
959  ptr += 4;
960  len -= 4;
961 
962  // Skip the number of frames
963  if (len >= 4 && flags & hasFrames)
964  {
965  ptr += 4;
966  len -= 4;
967  }
968 
969  // Skip the number of bytes
970  if (len >= 4 && flags & hasBytes)
971  {
972  ptr += 4;
973  len -= 4;
974  }
975 
976  // Skip the TOC
977  if (len >= 100 && flags & hasToc)
978  {
979  ptr += 100;
980  len -= 100;
981  }
982 
983  // Skip the VBR Scale
984  if (len >= 4 && flags & hasScale)
985  {
986  ptr += 4;
987  len -= 4;
988  }
989 
990  // Bail if LAME wasn't the encoder or we don't have enough ancillary data left
991  if (len < 24 || memcmp(ptr, "LAME", 4) != 0)
992  {
993  return MAD_FLOW_IGNORE;
994  }
995 
996  // Skip down to the delay and padding
997  ptr += 21;
998  len -= 21;
999 
1000  // Extract the delay and padding and adjust for decoder delay
1001  mDelay = (ptr[0] << 4) + (ptr[1] >> 4) + MAD_DELAY;
1002  mPadding = ((ptr[1] & 0x0f) << 8) + ptr[2] - MAD_DELAY;
1003  if (mPadding < 0)
1004  {
1005  mPadding = 0;
1006  }
1007 
1008  return MAD_FLOW_IGNORE;
1009 }

References MAD_DELAY, mDecoder, mDelay, and mPadding.

Referenced by filter_cb().

Here is the caller graph for this function:

◆ GetFileDescription()

TranslatableString MP3ImportFileHandle::GetFileDescription ( )
overridevirtual

Implements ImportFileHandle.

Definition at line 229 of file ImportMP3.cpp.

230 {
231  return DESC;
232 }

References DESC.

◆ GetFileUncompressedBytes()

auto MP3ImportFileHandle::GetFileUncompressedBytes ( )
overridevirtual

Implements ImportFileHandle.

Definition at line 234 of file ImportMP3.cpp.

235 {
236  // TODO
237  return 0;
238 }

◆ GetStreamCount()

wxInt32 MP3ImportFileHandle::GetStreamCount ( )
overridevirtual

Implements ImportFileHandle.

Definition at line 240 of file ImportMP3.cpp.

241 {
242  return 1;
243 }

◆ GetStreamInfo()

const TranslatableStrings & MP3ImportFileHandle::GetStreamInfo ( )
overridevirtual

Implements ImportFileHandle.

Definition at line 245 of file ImportMP3.cpp.

246 {
247  static TranslatableStrings empty;
248  return empty;
249 }

◆ Import()

ProgressResult MP3ImportFileHandle::Import ( WaveTrackFactory trackFactory,
TrackHolders outTracks,
Tags tags 
)
overridevirtual

Implements ImportFileHandle.

Definition at line 255 of file ImportMP3.cpp.

258 {
259  outTracks.clear();
260 
261  CreateProgress();
262 
263  mTrackFactory = trackFactory;
265  mNumChannels = 0;
266 
267  // Set delay and padding to best possible in case the LAME tag is not present
268  mDelay = MAD_DELAY;
269  mPadding = 0;
270 
271  // Initialize decoder
272  mad_decoder_init(&mDecoder, this, input_cb, 0, filter_cb, output_cb, error_cb, 0);
273 
274  // Send the decoder on its way!
275  auto res = mad_decoder_run(&mDecoder, MAD_DECODER_MODE_SYNC);
276 
277  // Terminate decoder
278  mad_decoder_finish(&mDecoder);
279 
280  // Decoding failed, so pass it on
281  if (res != 0)
282  {
283  return ProgressResult::Failed;
284  }
285 
286  // The user canceled the decoding, so bail without saving tracks or tags
288  {
289  return mUpdateResult;
290  }
291 
292  // Flush and trim the channels
293  for (const auto &channel : mChannels)
294  {
295  channel->Flush();
296 
297  // Trim any padding
298  if (mPadding)
299  {
300  double et = channel->GetEndTime();
301  double t1 = et - channel->LongSamplesToTime(mPadding);
302  channel->Clear(t1, et);
303  }
304 
305  // And delay
306  if (mDelay)
307  {
308  double st = channel->GetStartTime();
309  double t0 = st + channel->LongSamplesToTime(mDelay);
310  channel->Clear(st, t0);
311  }
312  }
313 
314  // Copy the WaveTrack pointers into the Track pointer list that
315  // we are expected to fill
316  outTracks.push_back(std::move(mChannels));
317 
318  // Load ID3 tags from the file
319  LoadID3(tags);
320 
321  return mUpdateResult;
322 }

References RefreshCode::Cancelled, ImportFileHandle::CreateProgress(), error_cb(), filter_cb(), input_cb(), LoadID3(), MAD_DELAY, mChannels, mDecoder, mDelay, mNumChannels, mPadding, mTrackFactory, mUpdateResult, output_cb(), and BasicUI::Success.

Here is the call graph for this function:

◆ input_cb()

mad_flow MP3ImportFileHandle::input_cb ( void *  that,
struct mad_stream stream 
)
staticprivate

Definition at line 852 of file ImportMP3.cpp.

854 {
855  auto cb = [&]()
856  {
857  return ((MP3ImportFileHandle *) that)->InputCB(stream);
858  };
859 
860  return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
861 }

References InputCB(), and MakeSimpleGuard().

Referenced by Import().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ InputCB()

mad_flow MP3ImportFileHandle::InputCB ( struct mad_stream stream)
private

Definition at line 863 of file ImportMP3.cpp.

864 {
865  // Update the progress
866  mUpdateResult = mProgress->Update((wxLongLong_t) mFilePos, (wxLongLong_t) mFileLen);
868  {
869  return MAD_FLOW_STOP;
870  }
871 
872  // Stop if we've consumed all of the MP3 data
873  if (mFilePos == mFileLen)
874  {
875  return MAD_FLOW_STOP;
876  }
877 
878  // "Each time you refill your buffer, you need to preserve the data in
879  // your existing buffer from stream.next_frame to the end.
880  //
881  // This usually amounts to calling memmove() on this unconsumed portion
882  // of the buffer and appending NEW data after it, before calling
883  // mad_stream_buffer()
884  // -- Rob Leslie, on the mad-dev mailing list
885  if (stream->next_frame)
886  {
887  mInputBufferLen -= (stream->next_frame - mInputBuffer);
888  memmove(mInputBuffer, stream->next_frame, mInputBufferLen);
889  }
890 
891  // Refill the buffer
892  if (!FillBuffer())
893  {
894  return MAD_FLOW_BREAK;
895  }
896 
897  // And give it back to MAD
898  mad_stream_buffer(stream, mInputBuffer, mInputBufferLen);
899 
900  return MAD_FLOW_CONTINUE;
901 }

References FillBuffer(), mFileLen, mFilePos, mInputBuffer, mInputBufferLen, ImportFileHandle::mProgress, mUpdateResult, and BasicUI::Success.

Referenced by input_cb().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ LoadID3()

void MP3ImportFileHandle::LoadID3 ( Tags tags)
private

Definition at line 662 of file ImportMP3.cpp.

663 {
664 #ifdef USE_LIBID3TAG
665  struct id3_file *id3file = NULL;
666  auto cleanup = finally([&]
667  {
668  if (id3file)
669  {
670  id3_file_close(id3file);
671  }
672  });
673 
674  // Use id3_file_fdopen() instead of id3_file_open since wxWidgets can open a
675  // file with a Unicode name and id3_file_open() can't (under Windows).
676  id3file = id3_file_fdopen(mFile.fd(), ID3_FILE_MODE_READONLY);
677  if (!id3file)
678  {
679  return;
680  }
681 
682  // The file descriptor is now owned by "id3file", so we must tell "mFile" to forget
683  // about it.
684  mFile.Detach();
685 
686  // Load the tags
687  struct id3_tag *id3tags = id3_file_tag(id3file);
688  if (!id3tags || id3tags->nframes == 0)
689  {
690  return;
691  }
692 
693  // Convert from libid3tag's ucs4 type to wxString.
694  //
695  // The ucs4 type is unsigned long which can be 8 bytes instead
696  // of the expected 4 bytes for a UTF-32 character, so we have
697  // to convert to unsigned int and then to wxString.
698  wxMBConvUTF32 converter;
699  auto toString = [=](const id3_ucs4_t *in)
700  {
701  // Count the number of characters
702  size_t len = 0;
703  for (const id3_ucs4_t *p = in; *p; p++)
704  {
705  len++;
706  }
707 
708  // Would like to use std::dynarray or runtime-sized array,
709  // but VS doesn't support either.
710  wxUint32 *buf = (wxUint32 *) alloca((len + 1) * sizeof(wxUint32));
711 
712  // Copy and convert to unsigned int
713  wxUint32 *out;
714  for (out = buf; *in; in++, out++)
715  {
716  *out = (wxUint32) (*in);
717  }
718  *out = 0;
719 
720  // Finally convert to and return wxString
721  return wxString((char *) buf, converter);
722  };
723 
724  tags->Clear();
725 
726  // Extract tags from ID3 frames and add to our tags
727  bool have_year = false;
728  for (unsigned int i = 0; i < id3tags->nframes; ++i)
729  {
730  struct id3_frame *frame = id3tags->frames[i];
731 
732 #if 0
733  wxLogDebug("ID: %08x '%4s'", (int) *(int *)frame->id, frame->id);
734  wxLogDebug("Desc: %s", frame->description);
735  wxLogDebug("Num fields: %d", frame->nfields);
736 
737  for (unsigned int j = 0; j < frame->nfields; ++j)
738  {
739  wxLogDebug("field %d type %d", j, frame->fields[j].type);
740  if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST)
741  {
742  wxLogDebug("num strings %d", frame->fields[j].stringlist.nstrings);
743  }
744  }
745 #endif
746 
747  wxString n;
748  wxString v;
749 
750  // Determine the tag name
751  if (strcmp(frame->id, ID3_FRAME_TITLE) == 0)
752  {
753  n = TAG_TITLE;
754  }
755  else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0)
756  {
757  n = TAG_ARTIST;
758  }
759  else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0)
760  {
761  n = TAG_ALBUM;
762  }
763  else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0)
764  {
765  n = TAG_TRACK;
766  }
767  else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0)
768  {
769  // LLL: When libid3tag encounters the "TYER" tag, it converts it to a
770  // "ZOBS" (obsolete) tag and adds a "TDRC" tag at the end of the
771  // list of tags using the first 4 characters of the "TYER" tag.
772  // Since we write both the "TDRC" and "TYER" tags, the "TDRC" tag
773  // will always be encountered first in the list. We want to use
774  // it since the converted "TYER" tag may have been truncated.
775  if (have_year)
776  {
777  continue;
778  }
779  n = TAG_YEAR;
780  have_year = true;
781  }
782  else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0)
783  {
784  n = TAG_COMMENTS;
785  }
786  else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0)
787  {
788  n = TAG_GENRE;
789  }
790  else
791  {
792  // Use frame description as default tag name. The descriptions
793  // may include several "meanings" separated by "/" characters, so
794  // we just use the first meaning
795  n = UTF8CTOWX(frame->description).BeforeFirst(wxT('/'));
796  }
797 
798  // Now get the tag value
799  const id3_ucs4_t *ustr = NULL;
800 
801  if (n == TAG_COMMENTS)
802  {
803  ustr = id3_field_getfullstring(&frame->fields[3]);
804  }
805  else if (frame->nfields == 3)
806  {
807  ustr = id3_field_getstring(&frame->fields[1]);
808  if (ustr)
809  {
810  n = toString(ustr);
811  }
812 
813  ustr = id3_field_getstring(&frame->fields[2]);
814  }
815  else if (frame->nfields >= 2)
816  {
817  ustr = id3_field_getstrings(&frame->fields[1], 0);
818  }
819 
820  // Convert the value
821  if (ustr)
822  {
823  v = toString(ustr);
824  }
825 
826  // And add it to the list of tags
827  if (!n.empty() && !v.empty())
828  {
829  tags->SetTag(n, v);
830  }
831  }
832 
833  // Convert v1 genre to name
834  if (tags->HasTag(TAG_GENRE))
835  {
836  long g = -1;
837  if (tags->GetTag(TAG_GENRE).ToLong(&g))
838  {
839  tags->SetTag(TAG_GENRE, tags->GetGenre(g));
840  }
841  }
842 #else
843  (void) tags;
844 #endif
845 }

References Tags::Clear(), Tags::GetGenre(), Tags::GetTag(), Tags::HasTag(), mFile, Tags::SetTag(), TAG_ALBUM, TAG_ARTIST, TAG_COMMENTS, TAG_GENRE, TAG_TITLE, TAG_TRACK, TAG_YEAR, and UTF8CTOWX.

Referenced by Import().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ Open()

bool MP3ImportFileHandle::Open ( )
private

Definition at line 324 of file ImportMP3.cpp.

325 {
326  mInputBufferLen = 0;
327  mFilePos = 0;
328  mHaveID3 = false;
329 
330  // Open the file
331  if (!mFile.Open(mFilename))
332  {
333  return false;
334  }
335 
336  // Get the length of the file
337  mFileLen = mFile.Seek(0, wxFromEnd);
338  if (mFileLen == wxInvalidOffset || mFile.Error())
339  {
340  mFile.Close();
341  return false;
342  }
343 
344  if (mFile.Seek(0, wxFromStart) == wxInvalidOffset || mFile.Error())
345  {
346  mFile.Close();
347  return false;
348  }
349 
350  // Check for ID3 tags
351  CheckTags();
352 
353  // Scan for the first MP3 frame
354  if (!CheckMP3())
355  {
356  mFile.Close();
357  return false;
358  }
359 
360  return true;
361 }

References CheckMP3(), CheckTags(), mFile, mFileLen, ImportFileHandle::mFilename, mFilePos, mHaveID3, and mInputBufferLen.

Here is the call graph for this function:

◆ output_cb()

mad_flow MP3ImportFileHandle::output_cb ( void *  that,
struct mad_header const *  header,
struct mad_pcm pcm 
)
staticprivate

Definition at line 1013 of file ImportMP3.cpp.

1016 {
1017  auto cb = [&]()
1018  {
1019  return ((MP3ImportFileHandle *) that)->OutputCB(header, pcm);
1020  };
1021 
1022  return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
1023 }

Referenced by Import().

Here is the caller graph for this function:

◆ OutputCB()

enum mad_flow MP3ImportFileHandle::OutputCB ( struct mad_header const *  header,
struct mad_pcm pcm 
)
private

Definition at line 1013 of file ImportMP3.cpp.

1027 {
1028  // If this is the first run, we need to create the WaveTracks that
1029  // will hold the data. We do this now because now is the first
1030  // moment when we know how many channels there are.
1031  if (mChannels.empty())
1032  {
1033  mNumChannels = pcm->channels;
1034 
1035  mChannels.resize(mNumChannels);
1036 
1037  for (auto &channel: mChannels)
1038  {
1039  // Mad library header explains the 32 bit fixed point format with
1040  // 28 fractional bits. Effective sample format must therefore be
1041  // more than 24, and this is our only choice now.
1042  channel = NewWaveTrack(*mTrackFactory, floatSample, pcm->samplerate);
1043  }
1044  }
1045 
1046  // Get the number of samples in each channel
1047  auto samples = pcm->length;
1048 
1049  // Convert libmad samples to float and append to WaveTracks
1050  for (int chn = 0; chn < mNumChannels; ++chn)
1051  {
1052  // Number of samples will never be more than 1152
1053  float sampleBuf[1152];
1054  wxASSERT(samples <= 1152);
1055 
1056  // Copy over the samples
1057  for (int sample = 0; sample < samples; ++sample)
1058  {
1059  // Convert libmad's fixed point representation to float
1060  sampleBuf[sample] = ((float) pcm->samples[chn][sample] / (1L << MAD_F_FRACBITS));
1061  }
1062 
1063  // And append to the channel
1064  mChannels[chn]->Append((samplePtr) sampleBuf, floatSample, samples);
1065  }
1066 
1067  return MAD_FLOW_CONTINUE;
1068 }

References MakeSimpleGuard().

Here is the call graph for this function:

◆ SetStreamUsage()

void MP3ImportFileHandle::SetStreamUsage ( wxInt32  StreamID,
bool  Use 
)
overridevirtual

Implements ImportFileHandle.

Definition at line 251 of file ImportMP3.cpp.

252 {
253 }

Member Data Documentation

◆ mChannels

NewChannelGroup MP3ImportFileHandle::mChannels
private

Definition at line 161 of file ImportMP3.cpp.

Referenced by Import().

◆ mDecoder

mad_decoder MP3ImportFileHandle::mDecoder
private

Definition at line 151 of file ImportMP3.cpp.

Referenced by FilterCB(), and Import().

◆ mDelay

int MP3ImportFileHandle::mDelay
private

Definition at line 166 of file ImportMP3.cpp.

Referenced by FilterCB(), and Import().

◆ mFile

wxFile MP3ImportFileHandle::mFile
private

◆ mFileLen

wxFileOffset MP3ImportFileHandle::mFileLen
private

◆ mFilePos

wxFileOffset MP3ImportFileHandle::mFilePos
private

Definition at line 154 of file ImportMP3.cpp.

Referenced by CheckAPETags(), CheckID3V2Tags(), CheckMP3(), FillBuffer(), InputCB(), and Open().

◆ mHaveID3

bool MP3ImportFileHandle::mHaveID3
private

Definition at line 169 of file ImportMP3.cpp.

Referenced by CheckID3V1Tags(), CheckID3V2Tags(), and Open().

◆ mInputBuffer

unsigned char MP3ImportFileHandle::mInputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD]
private

◆ mInputBufferLen

int MP3ImportFileHandle::mInputBufferLen
private

Definition at line 158 of file ImportMP3.cpp.

Referenced by CheckMP3(), FillBuffer(), InputCB(), and Open().

◆ mNumChannels

unsigned MP3ImportFileHandle::mNumChannels
private

Definition at line 162 of file ImportMP3.cpp.

Referenced by Import().

◆ MP3ImportPlugin

friend MP3ImportFileHandle::MP3ImportPlugin
private

Definition at line 171 of file ImportMP3.cpp.

◆ mPadding

int MP3ImportFileHandle::mPadding
private

Definition at line 167 of file ImportMP3.cpp.

Referenced by FilterCB(), and Import().

◆ mTrackFactory

WaveTrackFactory* MP3ImportFileHandle::mTrackFactory
private

Definition at line 160 of file ImportMP3.cpp.

Referenced by Import().

◆ mUpdateResult

ProgressResult MP3ImportFileHandle::mUpdateResult
private

Definition at line 164 of file ImportMP3.cpp.

Referenced by Import(), and InputCB().


The documentation for this class was generated from the following file:
BasicUI::ProgressResult::Success
@ Success
MP3ImportFileHandle::mTrackFactory
WaveTrackFactory * mTrackFactory
Definition: ImportMP3.cpp:160
MP3ImportFileHandle::mDelay
int mDelay
Definition: ImportMP3.cpp:166
MP3ImportFileHandle
An ImportFileHandle for MP3 data.
Definition: ImportMP3.cpp:106
MP3ImportFileHandle::mInputBuffer
unsigned char mInputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD]
Definition: ImportMP3.cpp:157
TranslatableStrings
std::vector< TranslatableString > TranslatableStrings
Definition: TranslatableString.h:295
BasicUI::ShowErrorDialog
void ShowErrorDialog(const WindowPlacement &placement, const TranslatableString &dlogTitle, const TranslatableString &message, const ManualPageID &helpPage, const ErrorDialogOptions &options={})
Show an error dialog with a link to the manual for further help.
Definition: BasicUI.h:233
MP3ImportFileHandle::mChannels
NewChannelGroup mChannels
Definition: ImportMP3.cpp:161
Tags::HasTag
bool HasTag(const wxString &name) const
Definition: Tags.cpp:452
TAG_TRACK
#define TAG_TRACK
Definition: Tags.h:63
MakeSimpleGuard
SimpleGuard< R > MakeSimpleGuard(R value)
Convert a value to a handler function returning that value, suitable for GuardedCall<R>
Definition: AudacityException.h:167
INPUT_BUFFER_SIZE
#define INPUT_BUFFER_SIZE
Definition: ImportMP3.cpp:86
MP3ImportFileHandle::CheckMP3
bool CheckMP3()
Definition: ImportMP3.cpp:562
RefreshCode::Cancelled
@ Cancelled
Definition: RefreshCode.h:23
XO
#define XO(s)
Definition: Internat.h:31
mad_stream
struct in the MPEG library, used for MP3 compression by MP3Exporter
MP3ImportFileHandle::CheckTags
void CheckTags()
Definition: ImportMP3.cpp:363
MP3ImportFileHandle::CheckLyrics
void CheckLyrics()
Definition: ImportMP3.cpp:454
MP3ImportFileHandle::mHaveID3
bool mHaveID3
Definition: ImportMP3.cpp:169
MP3ImportFileHandle::FillBuffer
bool FillBuffer()
Definition: ImportMP3.cpp:633
Tags::GetTag
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:461
ImportFileHandle::mProgress
std::unique_ptr< ProgressDialog > mProgress
Definition: ImportPlugin.h:159
MP3ImportFileHandle::mFilePos
wxFileOffset mFilePos
Definition: ImportMP3.cpp:154
floatSample
@ floatSample
Definition: SampleFormat.h:34
ImportFileHandle::ImportFileHandle
ImportFileHandle(const FilePath &filename)
Definition: ImportPlugin.cpp:36
Tags::GetGenre
wxString GetGenre(int value)
Definition: Tags.cpp:428
ImportFileHandle::CreateProgress
void CreateProgress()
Definition: ImportPlugin.cpp:45
ImportFileHandle::NewWaveTrack
std::shared_ptr< WaveTrack > NewWaveTrack(WaveTrackFactory &trackFactory, sampleFormat effectiveFormat, double rate)
Build a wave track with appropriate format, which will not be narrower than the specified one.
Definition: ImportPlugin.cpp:69
Tags::SetTag
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:486
MP3ImportFileHandle::filter_cb
static mad_flow filter_cb(void *that, struct mad_stream const *stream, struct mad_frame *frame)
Definition: ImportMP3.cpp:905
MP3ImportFileHandle::CheckID3V1Tags
void CheckID3V1Tags()
Definition: ImportMP3.cpp:427
MP3ImportFileHandle::mInputBufferLen
int mInputBufferLen
Definition: ImportMP3.cpp:158
mad_header
struct in the MPEG library, used for MP3 compression by MP3Exporter
MP3ImportFileHandle::ErrorCB
mad_flow ErrorCB(struct mad_stream *stream, struct mad_frame *frame)
Definition: ImportMP3.cpp:1084
MP3ImportFileHandle::CheckAPETags
void CheckAPETags(bool atEnd)
Definition: ImportMP3.cpp:385
UTF8CTOWX
#define UTF8CTOWX(X)
Definition: Internat.h:159
Tags::Clear
void Clear()
Definition: Tags.cpp:337
TAG_GENRE
#define TAG_GENRE
Definition: Tags.h:65
ImportFileHandle::mFilename
FilePath mFilename
Definition: ImportPlugin.h:158
TAG_YEAR
#define TAG_YEAR
Definition: Tags.h:64
MP3ImportFileHandle::output_cb
static mad_flow output_cb(void *that, struct mad_header const *header, struct mad_pcm *pcm)
Definition: ImportMP3.cpp:1013
MP3ImportFileHandle::mFileLen
wxFileOffset mFileLen
Definition: ImportMP3.cpp:155
MP3ImportFileHandle::LoadID3
void LoadID3(Tags *tags)
Definition: ImportMP3.cpp:662
MP3ImportFileHandle::InputCB
mad_flow InputCB(struct mad_stream *stream)
Definition: ImportMP3.cpp:863
MP3ImportFileHandle::mPadding
int mPadding
Definition: ImportMP3.cpp:167
MP3ImportFileHandle::CheckID3V2Tags
void CheckID3V2Tags(bool atEnd)
Definition: ImportMP3.cpp:520
DESC
#define DESC
Definition: ImportMP3.cpp:38
samplePtr
char * samplePtr
Definition: SampleFormat.h:49
MP3ImportFileHandle::input_cb
static mad_flow input_cb(void *that, struct mad_stream *stream)
Definition: ImportMP3.cpp:852
MP3ImportFileHandle::mFile
wxFile mFile
Definition: ImportMP3.cpp:153
BasicUI
Definition: Export.h:39
MP3ImportFileHandle::mDecoder
mad_decoder mDecoder
Definition: ImportMP3.cpp:151
MP3ImportFileHandle::OutputCB
mad_flow OutputCB(struct mad_header const *header, struct mad_pcm *pcm)
Definition: ImportMP3.cpp:1025
TAG_COMMENTS
#define TAG_COMMENTS
Definition: Tags.h:66
TAG_ARTIST
#define TAG_ARTIST
Definition: Tags.h:61
BasicUI::DefaultCaption
TranslatableString DefaultCaption()
"Message", suitably translated
Definition: BasicUI.cpp:70
MP3ImportFileHandle::mUpdateResult
ProgressResult mUpdateResult
Definition: ImportMP3.cpp:164
MP3ImportFileHandle::FilterCB
mad_flow FilterCB(struct mad_stream const *stream, struct mad_frame *frame)
Definition: ImportMP3.cpp:917
MP3ImportFileHandle::error_cb
static mad_flow error_cb(void *that, struct mad_stream *stream, struct mad_frame *frame)
Definition: ImportMP3.cpp:1072
MP3ImportFileHandle::mNumChannels
unsigned mNumChannels
Definition: ImportMP3.cpp:162
MAD_DELAY
#define MAD_DELAY
Definition: ImportMP3.cpp:90
TAG_TITLE
#define TAG_TITLE
Definition: Tags.h:60
TAG_ALBUM
#define TAG_ALBUM
Definition: Tags.h:62