Audacity 3.2.0
ImportMP3_MAD.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 ImportMP3_MAD.cpp
6
7 Joshua Haberman
8 Leland Lucius
9
10*//****************************************************************//****************************************************************//*******************************************************************/
28
29
30
31#include <wx/defs.h>
32
33#include "Import.h"
34#include "BasicUI.h"
35#include "ImportPlugin.h"
36#include "Project.h"
37
38#define DESC XO("MP3 files")
39
40static const auto exts =
41{
42 wxT("mp3"),
43 wxT("mp2"),
44 wxT("mpa")
45};
46
47#ifndef USE_LIBMAD
48
50{
51 std::make_unique<UnusableImportPlugin>(DESC, FileExtensions(exts.begin(), exts.end()))
52};
53
54#else
55
56#if defined(__WXMSW__)
57#include <malloc.h>
58#else
59#include <stdlib.h>
60#endif
61
62#include <wx/file.h>
63
64#include "Prefs.h"
65#include "../Tags.h"
66#include "WaveTrack.h"
67#include "../widgets/AudacityMessageBox.h"
68#include "../widgets/ProgressDialog.h"
69
70// PRL: include these last,
71// and correct some preprocessor namespace pollution from wxWidgets that
72// caused a warning about duplicate definition
73#undef SIZEOF_LONG
74extern "C"
75{
76#include "mad.h"
77
78#ifdef USE_LIBID3TAG
79#include <id3tag.h>
80#endif
81}
82
83// Specifies the number of bytes in the input buffer. This also controls
84// how many bytes will be scanned when searching for the first MP3 frame.
85#define INPUT_BUFFER_SIZE 65535
86
87// This is the number of decoded samples libmad adds at the beginning
88// (This is an "observed" value.)
89#define MAD_DELAY 529
90
91class MP3ImportPlugin final : public ImportPlugin
92{
93public:
96
97 wxString GetPluginStringID() override;
99 std::unique_ptr<ImportFileHandle> Open(const FilePath &Filename, AudacityProject*) override;
100};
101
102using NewChannelGroup = std::vector< std::shared_ptr<WaveTrack> >;
103
105{
106public:
107 MP3ImportFileHandle(const FilePath &filename);
109
112 ProgressResult Import(WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override;
113 wxInt32 GetStreamCount() override;
114 const TranslatableStrings &GetStreamInfo() override;
115 void SetStreamUsage(wxInt32 StreamID, bool Use) override;
116
117private:
118 bool Open();
119 void CheckTags();
120 void CheckAPETags(bool atEnd);
121 void CheckID3V1Tags();
122 void CheckID3V2Tags(bool atEnd);
123 void CheckLyrics();
124 bool CheckMP3();
125 bool FillBuffer();
126 void LoadID3(Tags *tags);
127
128 // The MAD callbacks
129
130 static mad_flow input_cb(void *that,
131 struct mad_stream *stream);
132 mad_flow InputCB(struct mad_stream *stream);
133
134 static mad_flow filter_cb(void *that,
135 struct mad_stream const *stream,
136 struct mad_frame *frame);
137 mad_flow FilterCB(struct mad_stream const *stream, struct mad_frame *frame);
138
139 static mad_flow output_cb(void *that,
140 struct mad_header const *header,
141 struct mad_pcm *pcm);
142 mad_flow OutputCB(struct mad_header const *header, struct mad_pcm *pcm);
143
144 static mad_flow error_cb(void *that,
145 struct mad_stream *stream,
146 struct mad_frame *frame);
147 mad_flow ErrorCB(struct mad_stream *stream, struct mad_frame *frame);
148
149private:
151
152 wxFile mFile;
153 wxFileOffset mFilePos;
154 wxFileOffset mFileLen;
155
156 unsigned char mInputBuffer[INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD];
158
161 unsigned mNumChannels;
162
164
167
169
171};
172
173// ============================================================================
174// MP3ImportPlugin
175// ============================================================================
176
179{
180}
181
183{
184}
185
187{
188 return wxT("libmad");
189}
190
192{
193 return DESC;
194}
195
196std::unique_ptr<ImportFileHandle> MP3ImportPlugin::Open(
197 const FilePath &Filename, AudacityProject *)
198{
199 auto handle = std::make_unique<MP3ImportFileHandle>(Filename);
200
201 if (!handle->Open())
202 {
203 return nullptr;
204 }
205
206 return handle;
207}
208
210{
211 "MP3",
212 std::make_unique<MP3ImportPlugin>()
213};
214
215// ============================================================================
216// MP3ImportFileHandle
217// ============================================================================
218
220: ImportFileHandle(filename)
221{
222}
223
225{
226}
227
229{
230 return DESC;
231}
232
234{
235 // TODO
236 return 0;
237}
238
240{
241 return 1;
242}
243
245{
246 static TranslatableStrings empty;
247 return empty;
248}
249
250void MP3ImportFileHandle::SetStreamUsage(wxInt32 WXUNUSED(StreamID), bool WXUNUSED(Use))
251{
252}
253
255 TrackHolders &outTracks,
256 Tags *tags)
257{
258 outTracks.clear();
259
261
262 mTrackFactory = trackFactory;
264 mNumChannels = 0;
265
266 // Set delay and padding to best possible in case the LAME tag is not present
268 mPadding = 0;
269
270 // Initialize decoder
271 mad_decoder_init(&mDecoder, this, input_cb, 0, filter_cb, output_cb, error_cb, 0);
272
273 // Send the decoder on its way!
274 auto res = mad_decoder_run(&mDecoder, MAD_DECODER_MODE_SYNC);
275
276 // Terminate decoder
277 mad_decoder_finish(&mDecoder);
278
279 // Decoding failed, so pass it on
280 if (res != 0)
281 {
282 return ProgressResult::Failed;
283 }
284
285 // The user canceled the decoding, so bail without saving tracks or tags
287 {
288 return mUpdateResult;
289 }
290
291 // Flush and trim the channels
292 for (const auto &channel : mChannels)
293 {
294 channel->Flush();
295
296 // Trim any padding
297 if (mPadding)
298 {
299 double et = channel->GetEndTime();
300 double t1 = et - channel->LongSamplesToTime(mPadding);
301 channel->Clear(t1, et);
302 }
303
304 // And delay
305 if (mDelay)
306 {
307 double st = channel->GetStartTime();
308 double t0 = st + channel->LongSamplesToTime(mDelay);
309 channel->Clear(st, t0);
310 }
311 }
312
313 // Copy the WaveTrack pointers into the Track pointer list that
314 // we are expected to fill
315 outTracks.push_back(std::move(mChannels));
316
317 // Load ID3 tags from the file
318 LoadID3(tags);
319
320 return mUpdateResult;
321}
322
324{
325 mInputBufferLen = 0;
326 mFilePos = 0;
327 mHaveID3 = false;
328
329 // Open the file
330 if (!mFile.Open(mFilename))
331 {
332 return false;
333 }
334
335 // Get the length of the file
336 mFileLen = mFile.Seek(0, wxFromEnd);
337 if (mFileLen == wxInvalidOffset || mFile.Error())
338 {
339 mFile.Close();
340 return false;
341 }
342
343 if (mFile.Seek(0, wxFromStart) == wxInvalidOffset || mFile.Error())
344 {
345 mFile.Close();
346 return false;
347 }
348
349 // Check for ID3 tags
350 CheckTags();
351
352 // Scan for the first MP3 frame
353 if (!CheckMP3())
354 {
355 mFile.Close();
356 return false;
357 }
358
359 return true;
360}
361
363{
364 // We do this twice to allow them to be in any order
365 for (int i = 0; i < 2; ++i)
366 {
367 CheckAPETags(false);
368 CheckID3V2Tags(false);
369 }
370
371 // We do this twice to allow them to be in any order. Even though ID3v1 is
372 // supposed to at the end, some apps put the v2 tags after the v1 tags.
373 for (int i = 0; i < 2; ++i)
374 {
375 CheckAPETags(true);
377 CheckLyrics();
378 CheckID3V2Tags(true);
379 }
380
381 return;
382}
383
385{
386 int offset = atEnd ? mFileLen - 32 : mFilePos;
387
388 // Ensure file is positioned to start of (possible) tags
389 if (mFile.Seek(offset, wxFromStart) == wxInvalidOffset || mFile.Error())
390 {
391 return;
392 }
393
394 // An APE tag header is 32 bytes
395 if (mFile.Read(mInputBuffer, 32) != 32 || mFile.Error())
396 {
397 return;
398 }
399
400 // Do we have an APE preamble?
401 if (memcmp(mInputBuffer, "APETAGEX", 8) != 0)
402 {
403 return;
404 }
405
406 // Get the (little endian) length
407 wxFileOffset len = (mInputBuffer[12] & 0xff) |
408 ((mInputBuffer[13] & 0xff) << 8) |
409 ((mInputBuffer[14] & 0xff) << 16) |
410 ((mInputBuffer[15] & 0xff) << 24);
411
412 // Get needed flags
413 bool hasHeader = mInputBuffer[23] & 0x80;
414
415 // Skip the tags
416 if (!atEnd)
417 {
418 mFilePos += (32 + len);
419 }
420 else
421 {
422 mFileLen -= ((hasHeader ? 32 : 0) + len);
423 }
424}
425
427{
428 // Ensure file is positioned to start of (possible) tags
429 if (mFile.Seek(mFileLen - 128, wxFromStart) == wxInvalidOffset || mFile.Error())
430 {
431 return;
432 }
433
434 // An ID3v1 tag header is 3 bytes
435 if (mFile.Read(mInputBuffer, 3) != 3 || mFile.Error())
436 {
437 return;
438 }
439
440 // Do we have ID3v1 tags?
441 if (memcmp(mInputBuffer, "TAG", 3) != 0)
442 {
443 return;
444 }
445
446 // Adjust file length
447 mFileLen -= 128;
448
449 // Remember that we have tags
450 mHaveID3 = true;
451}
452
454{
455 int offset = mFileLen - 9;
456
457 // Ensure file is positioned to start of (possible) lyrics
458 if (mFile.Seek(offset, wxFromStart) == wxInvalidOffset || mFile.Error())
459 {
460 return;
461 }
462
463 // An Lyrics3 footeris 9 bytes
464 if (mFile.Read(mInputBuffer, 9) != 9 || mFile.Error())
465 {
466 return;
467 }
468
469 // Found a v1 Lyrics footer?
470 if (memcmp(mInputBuffer, "LYRICSEND", 9) == 0)
471 {
472 wxFileOffset pos = wxMax(offset - 5100, 0);
473 size_t len = offset - pos;
474
475 // Ensure file is positioned to start of (possible) lyrics
476 if (mFile.Seek(pos, wxFromStart) == wxInvalidOffset || mFile.Error())
477 {
478 return;
479 }
480
481 // Read the lyrics
482 if (mFile.Read(mInputBuffer, len) != len || mFile.Error())
483 {
484 return;
485 }
486
487 // Search forward to find the beginning of the lyrics
488 for (size_t i = 0; i < len; ++i)
489 {
490 if (memcmp(&mInputBuffer[i], "LYRICSBEGIN", 11) == 0)
491 {
492 // Adjust the file length to exclude the lyrics
493 mFileLen = pos + i;
494 break;
495 }
496 }
497 }
498 // Found a v2 Lyrics footer?
499 else if (memcmp(mInputBuffer, "LYRICS200", 9) == 0)
500 {
501 // Ensure file is positioned to start of (possible) lyrics
502 if (mFile.Seek(-15, wxFromCurrent) == wxInvalidOffset || mFile.Error())
503 {
504 return;
505 }
506
507 // An Lyrics3v2 length is 6 bytes
508 if (mFile.Read(mInputBuffer, 6) != 6 || mFile.Error())
509 {
510 return;
511 }
512
513 // Adjust the file length to exclude the lyrics
514 mInputBuffer[6] = 0;
515 mFileLen -= (wxAtoi((char *) mInputBuffer) + 15);
516 }
517}
518
520{
521 int offset = atEnd ? mFileLen - 10 : mFilePos;
522
523 // Ensure file is positioned to start of (possible) tags
524 if (mFile.Seek(offset, wxFromStart) == wxInvalidOffset || mFile.Error())
525 {
526 return;
527 }
528
529 // An ID3v2 tag header is 10 bytes
530 if (mFile.Read(mInputBuffer, 10) != 10 || mFile.Error())
531 {
532 return;
533 }
534
535 // Do we have an ID3v2 header or footer?
536 if (memcmp(mInputBuffer, atEnd ? "3DI" : "ID3", 3) != 0)
537 {
538 return;
539 }
540
541 // Get and decode the length
542 wxFileOffset len = (mInputBuffer[6] & 0x7f);
543 len = (len << 7) | (mInputBuffer[7] & 0x7f);
544 len = (len << 7) | (mInputBuffer[8] & 0x7f);
545 len = (len << 7) | (mInputBuffer[9] & 0x7f);
546
547 // Skip the tags
548 if (!atEnd)
549 {
550 mFilePos += (10 + len);
551 }
552 else
553 {
554 mFileLen -= (10 + len + 10);
555 }
556
557 // Remember that we have tags
558 mHaveID3 = true;
559}
560
562{
563 wxFileOffset savedPos = mFilePos;
564
565 // Ensure file is positioned to start of 1st mp3 frame
566 if (mFile.Seek(mFilePos, wxFromStart) == wxInvalidOffset || mFile.Error())
567 {
568 return false;
569 }
570
571 // Load as much as will fit into the buffer
572 if (!FillBuffer())
573 {
574 return false;
575 }
576
577 // Initialize mad stream
578 mad_stream stream;
579 mad_stream_init(&stream);
580 mad_stream_buffer(&stream, mInputBuffer, mInputBufferLen);
581
582 // And header
583 mad_header header;
584 mad_header_init(&header);
585
586 // Scan the input buffer for 2 consecutive MP3 frames. When the header
587 // decoder finds a frame, it decodes it and ensures it is followed by
588 // another frame or EOF...thus 2 (or 1) consecutive frame(s) are detected.
589 int consecutive = 1;
590 while (consecutive > 0)
591 {
592 // Decode the header at the current stream position.
593 if (mad_header_decode(&header, &stream))
594 {
595 // End of buffer.
596 if (stream.error != MAD_ERROR_NONE)
597 {
598 break;
599 }
600 }
601
602 consecutive -= 1;
603 }
604
605 // Remember how many bytes were processed
606 int used = stream.this_frame - stream.buffer;
607
608 // Cleanup
609 mad_header_finish(&header);
610 mad_stream_finish(&stream);
611
612 // Did we find all that we wanted?
613 if (consecutive)
614 {
615 return false;
616 }
617
618 // Reset file controls
619 mInputBufferLen = 0;
620
621 // Reposition file to start of mp3 frames to prepare for the Import.
622 mFilePos = savedPos + used;
623 if (mFile.Seek(mFilePos, wxFromStart) == wxInvalidOffset || mFile.Error())
624 {
625 return false;
626 }
627
628 // Looks like an MP3...
629 return true;
630}
631
633{
634 // We either want enough to fill the input buffer or what's left in the file
635 auto want = wxMin(INPUT_BUFFER_SIZE - mInputBufferLen, mFileLen - mFilePos);
636 if (want > 0)
637 {
638 // We should always get what we ask for
639 auto got = mFile.Read(&mInputBuffer[mInputBufferLen], want);
640 if (got != want || mFile.Error())
641 {
642 return false;
643 }
644
645 // Adjust input control
646 mInputBufferLen += got;
647 mFilePos += got;
648 }
649
650 // MAD requires that we add MAD_BUFFER_GUARD extra bytes when we've processed
651 // all of the MP3 frames. Otherwise, we will drop the last frame.
652 if (mFilePos == mFileLen)
653 {
654 memset(&mInputBuffer[mInputBufferLen], 0, MAD_BUFFER_GUARD);
655 mInputBufferLen += MAD_BUFFER_GUARD;
656 }
657
658 return true;
659}
660
662{
663#ifdef USE_LIBID3TAG
664 struct id3_file *id3file = NULL;
665 auto cleanup = finally([&]
666 {
667 if (id3file)
668 {
669 id3_file_close(id3file);
670 }
671 });
672
673 // Use id3_file_fdopen() instead of id3_file_open since wxWidgets can open a
674 // file with a Unicode name and id3_file_open() can't (under Windows).
675 id3file = id3_file_fdopen(mFile.fd(), ID3_FILE_MODE_READONLY);
676 if (!id3file)
677 {
678 return;
679 }
680
681 // The file descriptor is now owned by "id3file", so we must tell "mFile" to forget
682 // about it.
683 mFile.Detach();
684
685 // Load the tags
686 struct id3_tag *id3tags = id3_file_tag(id3file);
687 if (!id3tags || id3tags->nframes == 0)
688 {
689 return;
690 }
691
692 // Convert from libid3tag's ucs4 type to wxString.
693 //
694 // The ucs4 type is unsigned long which can be 8 bytes instead
695 // of the expected 4 bytes for a UTF-32 character, so we have
696 // to convert to unsigned int and then to wxString.
697 wxMBConvUTF32 converter;
698 auto toString = [=](const id3_ucs4_t *in)
699 {
700 // Count the number of characters
701 size_t len = 0;
702 for (const id3_ucs4_t *p = in; *p; p++)
703 {
704 len++;
705 }
706
707 // Would like to use std::dynarray or runtime-sized array,
708 // but VS doesn't support either.
709 wxUint32 *buf = (wxUint32 *) alloca((len + 1) * sizeof(wxUint32));
710
711 // Copy and convert to unsigned int
712 wxUint32 *out;
713 for (out = buf; *in; in++, out++)
714 {
715 *out = (wxUint32) (*in);
716 }
717 *out = 0;
718
719 // Finally convert to and return wxString
720 return wxString((char *) buf, converter);
721 };
722
723 tags->Clear();
724
725 // Extract tags from ID3 frames and add to our tags
726 bool have_year = false;
727 for (unsigned int i = 0; i < id3tags->nframes; ++i)
728 {
729 struct id3_frame *frame = id3tags->frames[i];
730
731#if 0
732 wxLogDebug("ID: %08x '%4s'", (int) *(int *)frame->id, frame->id);
733 wxLogDebug("Desc: %s", frame->description);
734 wxLogDebug("Num fields: %d", frame->nfields);
735
736 for (unsigned int j = 0; j < frame->nfields; ++j)
737 {
738 wxLogDebug("field %d type %d", j, frame->fields[j].type);
739 if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST)
740 {
741 wxLogDebug("num strings %d", frame->fields[j].stringlist.nstrings);
742 }
743 }
744#endif
745
746 wxString n;
747 wxString v;
748
749 // Determine the tag name
750 if (strcmp(frame->id, ID3_FRAME_TITLE) == 0)
751 {
752 n = TAG_TITLE;
753 }
754 else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0)
755 {
756 n = TAG_ARTIST;
757 }
758 else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0)
759 {
760 n = TAG_ALBUM;
761 }
762 else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0)
763 {
764 n = TAG_TRACK;
765 }
766 else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0)
767 {
768 // LLL: When libid3tag encounters the "TYER" tag, it converts it to a
769 // "ZOBS" (obsolete) tag and adds a "TDRC" tag at the end of the
770 // list of tags using the first 4 characters of the "TYER" tag.
771 // Since we write both the "TDRC" and "TYER" tags, the "TDRC" tag
772 // will always be encountered first in the list. We want to use
773 // it since the converted "TYER" tag may have been truncated.
774 if (have_year)
775 {
776 continue;
777 }
778 n = TAG_YEAR;
779 have_year = true;
780 }
781 else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0)
782 {
783 n = TAG_COMMENTS;
784 }
785 else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0)
786 {
787 n = TAG_GENRE;
788 }
789 else
790 {
791 // Use frame description as default tag name. The descriptions
792 // may include several "meanings" separated by "/" characters, so
793 // we just use the first meaning
794 n = UTF8CTOWX(frame->description).BeforeFirst(wxT('/'));
795 }
796
797 // Now get the tag value
798 const id3_ucs4_t *ustr = NULL;
799
800 if (n == TAG_COMMENTS)
801 {
802 ustr = id3_field_getfullstring(&frame->fields[3]);
803 }
804 else if (frame->nfields == 3)
805 {
806 ustr = id3_field_getstring(&frame->fields[1]);
807 if (ustr)
808 {
809 n = toString(ustr);
810 }
811
812 ustr = id3_field_getstring(&frame->fields[2]);
813 }
814 else if (frame->nfields >= 2)
815 {
816 ustr = id3_field_getstrings(&frame->fields[1], 0);
817 }
818
819 // Convert the value
820 if (ustr)
821 {
822 v = toString(ustr);
823 }
824
825 // And add it to the list of tags
826 if (!n.empty() && !v.empty())
827 {
828 tags->SetTag(n, v);
829 }
830 }
831
832 // Convert v1 genre to name
833 if (tags->HasTag(TAG_GENRE))
834 {
835 long g = -1;
836 if (tags->GetTag(TAG_GENRE).ToLong(&g))
837 {
838 tags->SetTag(TAG_GENRE, tags->GetGenre(g));
839 }
840 }
841#else
842 (void) tags;
843#endif
844}
845
846//
847// MAD Callbacks
848//
849
850// The input callback is called when the decoder wants more data
852 struct mad_stream *stream)
853{
854 auto cb = [&]()
855 {
856 return ((MP3ImportFileHandle *) that)->InputCB(stream);
857 };
858
859 return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
860}
861
863{
864 // Update the progress
865 mUpdateResult = mProgress->Update((wxLongLong_t) mFilePos, (wxLongLong_t) mFileLen);
867 {
868 return MAD_FLOW_STOP;
869 }
870
871 // Stop if we've consumed all of the MP3 data
872 if (mFilePos == mFileLen)
873 {
874 return MAD_FLOW_STOP;
875 }
876
877 // "Each time you refill your buffer, you need to preserve the data in
878 // your existing buffer from stream.next_frame to the end.
879 //
880 // This usually amounts to calling memmove() on this unconsumed portion
881 // of the buffer and appending NEW data after it, before calling
882 // mad_stream_buffer()
883 // -- Rob Leslie, on the mad-dev mailing list
884 if (stream->next_frame)
885 {
886 mInputBufferLen -= (stream->next_frame - mInputBuffer);
887 memmove(mInputBuffer, stream->next_frame, mInputBufferLen);
888 }
889
890 // Refill the buffer
891 if (!FillBuffer())
892 {
893 return MAD_FLOW_BREAK;
894 }
895
896 // And give it back to MAD
897 mad_stream_buffer(stream, mInputBuffer, mInputBufferLen);
898
899 return MAD_FLOW_CONTINUE;
900}
901
902// The filter callback lets us examine each frame and decide if it should be
903// kept or tossed. We use this to detect the Xing or LAME tags.
905 struct mad_stream const *stream,
906 struct mad_frame *frame)
907{
908 auto cb = [&]()
909 {
910 return ((MP3ImportFileHandle *) that)->FilterCB(stream, frame);
911 };
912
913 return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
914}
915
916mad_flow MP3ImportFileHandle::FilterCB(struct mad_stream const *stream,
917 struct mad_frame *frame)
918{
919 // We only want to jinspect the first frame, so disable future calls
920 mDecoder.filter_func = nullptr;
921
922 // Is it a VBRI info frame?
923 if (memcmp(&stream->this_frame[4 + 32], "VBRI", 4) == 0)
924 {
925 mDelay = (stream->this_frame[4 + 32 + 6] & 0xff) << 8 |
926 (stream->this_frame[4 + 32 + 7] & 0xff);
927
928 return MAD_FLOW_CONTINUE;
929 }
930
931 // Look for Xing/Info information
932
933 // Get the ancillary data ptr and length. If the frame has CRC protection, we make
934 // a small adjustment to get around an apparent bug in libmad.
935 auto ptr = stream->anc_ptr.byte - (frame->header.flags & MAD_FLAG_PROTECTION ? 2 : 0);
936 int len = stream->anc_bitlen / 8;
937
938 // Ensure it's something we can understand
939 if (len < 4 || (memcmp(ptr, "Xing", 4) != 0 && memcmp(ptr, "Info", 4) != 0))
940 {
941 return MAD_FLOW_CONTINUE;
942 }
943
944 // Skip the tag
945 ptr += 4;
946 len -= 4;
947
948 enum flagBits
949 {
950 hasFrames = 0x0001,
951 hasBytes = 0x0002,
952 hasToc = 0x0004,
953 hasScale = 0x0008
954 };
955
956 // Extract the flags
957 unsigned int flags = (((((ptr[0] << 8) + ptr[1]) << 8) + ptr[2]) << 8) + ptr[3];
958 ptr += 4;
959 len -= 4;
960
961 // Skip the number of frames
962 if (len >= 4 && flags & hasFrames)
963 {
964 ptr += 4;
965 len -= 4;
966 }
967
968 // Skip the number of bytes
969 if (len >= 4 && flags & hasBytes)
970 {
971 ptr += 4;
972 len -= 4;
973 }
974
975 // Skip the TOC
976 if (len >= 100 && flags & hasToc)
977 {
978 ptr += 100;
979 len -= 100;
980 }
981
982 // Skip the VBR Scale
983 if (len >= 4 && flags & hasScale)
984 {
985 ptr += 4;
986 len -= 4;
987 }
988
989 // Bail if LAME wasn't the encoder or we don't have enough ancillary data left
990 if (len < 24 || memcmp(ptr, "LAME", 4) != 0)
991 {
992 return MAD_FLOW_IGNORE;
993 }
994
995 // Skip down to the delay and padding
996 ptr += 21;
997 len -= 21;
998
999 // Extract the delay and padding and adjust for decoder delay
1000 mDelay = (ptr[0] << 4) + (ptr[1] >> 4) + MAD_DELAY;
1001 mPadding = ((ptr[1] & 0x0f) << 8) + ptr[2] - MAD_DELAY;
1002 if (mPadding < 0)
1003 {
1004 mPadding = 0;
1005 }
1006
1007 return MAD_FLOW_IGNORE;
1008}
1009
1010// The output callback is called every time the decoder has finished decoding
1011 // a frame, allowing us to use the decoded data
1013 struct mad_header const *header,
1014 struct mad_pcm *pcm)
1015{
1016 auto cb = [&]()
1017 {
1018 return ((MP3ImportFileHandle *) that)->OutputCB(header, pcm);
1019 };
1020
1021 return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
1022}
1023
1024enum mad_flow MP3ImportFileHandle::OutputCB(struct mad_header const * WXUNUSED(header),
1025 struct mad_pcm *pcm)
1026{
1027 // If this is the first run, we need to create the WaveTracks that
1028 // will hold the data. We do this now because now is the first
1029 // moment when we know how many channels there are.
1030 if (mChannels.empty())
1031 {
1032 mNumChannels = pcm->channels;
1033
1034 mChannels.resize(mNumChannels);
1035
1036 for (auto &channel: mChannels)
1037 {
1038 // Mad library header explains the 32 bit fixed point format with
1039 // 28 fractional bits. Effective sample format must therefore be
1040 // more than 24, and this is our only choice now.
1041 channel = NewWaveTrack(*mTrackFactory, floatSample, pcm->samplerate);
1042 }
1043 }
1044
1045 // Get the number of samples in each channel
1046 auto samples = pcm->length;
1047
1048 // Convert libmad samples to float and append to WaveTracks
1049 for (int chn = 0; chn < mNumChannels; ++chn)
1050 {
1051 // Number of samples will never be more than 1152
1052 float sampleBuf[1152];
1053 wxASSERT(samples <= 1152);
1054
1055 // Copy over the samples
1056 for (int sample = 0; sample < samples; ++sample)
1057 {
1058 // Convert libmad's fixed point representation to float
1059 sampleBuf[sample] = ((float) pcm->samples[chn][sample] / (1L << MAD_F_FRACBITS));
1060 }
1061
1062 // And append to the channel
1063 mChannels[chn]->Append(
1064 (samplePtr) sampleBuf, floatSample, samples, 1,
1065 // Samples were 28 bit fixed-point converted to float:
1066 // see explanation above MAD_F_FRACBITS in mad.h
1067 // Effective sample format must therefore be
1068 // more than 24 bits, so this is our only choice.
1069 floatSample);
1070 }
1071
1072 return MAD_FLOW_CONTINUE;
1073}
1074
1075// The error callback is used when MAD encounters an error and needs to know
1076// how it should proceed
1078 struct mad_stream *stream,
1079 struct mad_frame *frame)
1080{
1081 auto cb = [&]()
1082 {
1083 return ((MP3ImportFileHandle *) that)->ErrorCB(stream, frame);
1084 };
1085
1086 return GuardedCall<mad_flow>(cb, MakeSimpleGuard(MAD_FLOW_BREAK));
1087}
1088
1089enum mad_flow MP3ImportFileHandle::ErrorCB(struct mad_stream *stream,
1090 struct mad_frame *frame)
1091{
1092 // You always get a LOSTSYNC error at EOF, so just ignore it
1093 if (stream->error == MAD_ERROR_LOSTSYNC && mFilePos == mFileLen)
1094 {
1095 return MAD_FLOW_CONTINUE;
1096 }
1097
1098 // This can happen when parsing the first frame. We can use the number of channels
1099 // to test for this since it hasn't been determined yet.
1100 if (stream->error == MAD_ERROR_BADDATAPTR && mNumChannels == 0)
1101 {
1102 return MAD_FLOW_CONTINUE;
1103 }
1104
1105 // Let the user know about the error
1106 using namespace BasicUI;
1107 ShowErrorDialog( {},
1109 XO("Import failed\n\nThis is likely caused by a malformed MP3.\n\n"),
1110 "Opening_malformed_MP3_files");
1111 return MAD_FLOW_BREAK;
1112}
1113
1114#endif
wxT("CloseDown"))
SimpleGuard< R > MakeSimpleGuard(R value) noexcept(noexcept(SimpleGuard< R >{ value }))
Convert a value to a handler function returning that value, suitable for GuardedCall<R>
Toolkit-neutral facade for basic user interface services.
XO("Cut/Copy/Paste")
wxArrayStringEx FileExtensions
Definition: Identifier.h:225
std::vector< std::shared_ptr< WaveTrack > > NewChannelGroup
Definition: Import.cpp:59
std::vector< std::vector< std::shared_ptr< WaveTrack > > > TrackHolders
Definition: Import.h:39
static const auto exts
#define DESC
static Importer::RegisteredImportPlugin registered
#define INPUT_BUFFER_SIZE
#define MAD_DELAY
The interface that all file import "plugins" (if you want to call them that) must implement....
#define UTF8CTOWX(X)
Definition: Internat.h:157
wxString FilePath
Definition: Project.h:21
char * samplePtr
Definition: SampleFormat.h:55
#define TAG_TRACK
Definition: Tags.h:61
#define TAG_COMMENTS
Definition: Tags.h:64
#define TAG_GENRE
Definition: Tags.h:63
#define TAG_ALBUM
Definition: Tags.h:60
#define TAG_YEAR
Definition: Tags.h:62
#define TAG_TITLE
Definition: Tags.h:58
#define TAG_ARTIST
Definition: Tags.h:59
std::vector< TranslatableString > TranslatableStrings
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
Definition: Project.h:90
An ImportFileHandle for data.
Definition: ImportPlugin.h:112
FilePath mFilename
Definition: ImportPlugin.h:163
unsigned long long ByteCount
Definition: ImportPlugin.h:132
std::unique_ptr< ProgressDialog > mProgress
Definition: ImportPlugin.h:164
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.
Base class for FlacImportPlugin, LOFImportPlugin, MP3ImportPlugin, OggImportPlugin and PCMImportPlugi...
Definition: ImportPlugin.h:68
An ImportFileHandle for MP3 data.
ProgressResult Import(WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override
void LoadID3(Tags *tags)
ByteCount GetFileUncompressedBytes() override
MP3ImportFileHandle(const FilePath &filename)
const TranslatableStrings & GetStreamInfo() override
void SetStreamUsage(wxInt32 StreamID, bool Use) override
static mad_flow output_cb(void *that, struct mad_header const *header, struct mad_pcm *pcm)
mad_flow ErrorCB(struct mad_stream *stream, struct mad_frame *frame)
mad_flow InputCB(struct mad_stream *stream)
void CheckID3V2Tags(bool atEnd)
mad_flow FilterCB(struct mad_stream const *stream, struct mad_frame *frame)
static mad_flow filter_cb(void *that, struct mad_stream const *stream, struct mad_frame *frame)
static mad_flow error_cb(void *that, struct mad_stream *stream, struct mad_frame *frame)
TranslatableString GetFileDescription() override
static mad_flow input_cb(void *that, struct mad_stream *stream)
wxInt32 GetStreamCount() override
mad_flow OutputCB(struct mad_header const *header, struct mad_pcm *pcm)
void CheckAPETags(bool atEnd)
unsigned char mInputBuffer[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD]
ProgressResult mUpdateResult
NewChannelGroup mChannels
WaveTrackFactory * mTrackFactory
An ImportPlugin for MP3 data.
TranslatableString GetPluginFormatDescription() override
wxString GetPluginStringID() override
std::unique_ptr< ImportFileHandle > Open(const FilePath &Filename, AudacityProject *) override
ID3 Tags (for MP3)
Definition: Tags.h:73
void Clear()
Definition: Tags.cpp:308
bool HasTag(const wxString &name) const
Definition: Tags.cpp:407
wxString GetGenre(int value)
Definition: Tags.cpp:383
void SetTag(const wxString &name, const wxString &value, const bool bSpecialTag=false)
Definition: Tags.cpp:441
wxString GetTag(const wxString &name) const
Definition: Tags.cpp:416
Holds a msgid for the translation catalog; may also bind format arguments.
Used to create or clone a WaveTrack, with appropriate context from the project that will own the trac...
Definition: WaveTrack.h:743
struct in the MPEG library, used for MP3 compression by MP3Exporter
struct in the MPEG library, used for MP3 compression by MP3Exporter
struct in the MPEG library, used for MP3 compression by MP3Exporter
struct in the MPEG library, used for MP3 compression by MP3Exporter
struct in the MPEG library, used for MP3 compression by MP3Exporter
Extend wxArrayString with move operations and construction and insertion fromstd::initializer_list.
TranslatableString DefaultCaption()
"Message", suitably translated
Definition: BasicUI.cpp:253
ProgressResult
Definition: BasicUI.h:147
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:259
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:159
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
Definition: PackedArray.h:150