38#define DESC XO("MP3 files")
67#include "../WaveTrack.h"
68#include "../widgets/AudacityMessageBox.h"
69#include "../widgets/ProgressDialog.h"
86#define INPUT_BUFFER_SIZE 65535
131 static mad_flow
input_cb(
void *that,
145 static mad_flow
error_cb(
void *that,
189 return wxT(
"libmad");
200 auto handle = std::make_unique<MP3ImportFileHandle>(Filename);
213 std::make_unique<MP3ImportPlugin>()
275 auto res = mad_decoder_run(&
mDecoder, MAD_DECODER_MODE_SYNC);
283 return ProgressResult::Failed;
300 double et = channel->GetEndTime();
301 double t1 = et - channel->LongSamplesToTime(
mPadding);
302 channel->Clear(t1, et);
308 double st = channel->GetStartTime();
309 double t0 = st + channel->LongSamplesToTime(
mDelay);
310 channel->Clear(st, t0);
316 outTracks.push_back(std::move(
mChannels));
344 if (
mFile.Seek(0, wxFromStart) == wxInvalidOffset ||
mFile.Error())
366 for (
int i = 0; i < 2; ++i)
374 for (
int i = 0; i < 2; ++i)
390 if (
mFile.Seek(offset, wxFromStart) == wxInvalidOffset ||
mFile.Error())
423 mFileLen -= ((hasHeader ? 32 : 0) + len);
459 if (
mFile.Seek(offset, wxFromStart) == wxInvalidOffset ||
mFile.Error())
473 wxFileOffset pos = wxMax(offset - 5100, 0);
474 size_t len = offset - pos;
477 if (
mFile.Seek(pos, wxFromStart) == wxInvalidOffset ||
mFile.Error())
489 for (
size_t i = 0; i < len; ++i)
503 if (
mFile.Seek(-15, wxFromCurrent) == wxInvalidOffset ||
mFile.Error())
525 if (
mFile.Seek(offset, wxFromStart) == wxInvalidOffset ||
mFile.Error())
537 if (memcmp(
mInputBuffer, atEnd ?
"3DI" :
"ID3", 3) != 0)
580 mad_stream_init(&stream);
585 mad_header_init(&header);
591 while (consecutive > 0)
594 if (mad_header_decode(&header, &stream))
597 if (stream.error != MAD_ERROR_NONE)
607 int used = stream.this_frame - stream.buffer;
610 mad_header_finish(&header);
611 mad_stream_finish(&stream);
641 if (got != want ||
mFile.Error())
665 struct id3_file *id3file = NULL;
666 auto cleanup =
finally([&]
670 id3_file_close(id3file);
676 id3file = id3_file_fdopen(
mFile.fd(), ID3_FILE_MODE_READONLY);
687 struct id3_tag *id3tags = id3_file_tag(id3file);
688 if (!id3tags || id3tags->nframes == 0)
698 wxMBConvUTF32 converter;
699 auto toString = [=](
const id3_ucs4_t *in)
703 for (
const id3_ucs4_t *p = in; *p; p++)
710 wxUint32 *buf = (wxUint32 *) alloca((len + 1) *
sizeof(wxUint32));
714 for (out = buf; *in; in++, out++)
716 *out = (wxUint32) (*in);
721 return wxString((
char *) buf, converter);
727 bool have_year =
false;
728 for (
unsigned int i = 0; i < id3tags->nframes; ++i)
730 struct id3_frame *frame = id3tags->frames[i];
733 wxLogDebug(
"ID: %08x '%4s'", (
int) *(
int *)frame->id, frame->id);
734 wxLogDebug(
"Desc: %s", frame->description);
735 wxLogDebug(
"Num fields: %d", frame->nfields);
737 for (
unsigned int j = 0; j < frame->nfields; ++j)
739 wxLogDebug(
"field %d type %d", j, frame->fields[j].type);
740 if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST)
742 wxLogDebug(
"num strings %d", frame->fields[j].stringlist.nstrings);
751 if (strcmp(frame->id, ID3_FRAME_TITLE) == 0)
755 else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0)
759 else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0)
763 else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0)
767 else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0)
782 else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0)
786 else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0)
795 n =
UTF8CTOWX(frame->description).BeforeFirst(wxT(
'/'));
799 const id3_ucs4_t *ustr = NULL;
803 ustr = id3_field_getfullstring(&frame->fields[3]);
805 else if (frame->nfields == 3)
807 ustr = id3_field_getstring(&frame->fields[1]);
813 ustr = id3_field_getstring(&frame->fields[2]);
815 else if (frame->nfields >= 2)
817 ustr = id3_field_getstrings(&frame->fields[1], 0);
827 if (!n.empty() && !v.empty())
869 return MAD_FLOW_STOP;
875 return MAD_FLOW_STOP;
885 if (stream->next_frame)
894 return MAD_FLOW_BREAK;
900 return MAD_FLOW_CONTINUE;
924 if (memcmp(&stream->this_frame[4 + 32],
"VBRI", 4) == 0)
926 mDelay = (stream->this_frame[4 + 32 + 6] & 0xff) << 8 |
927 (stream->this_frame[4 + 32 + 7] & 0xff);
929 return MAD_FLOW_CONTINUE;
936 auto ptr = stream->anc_ptr.byte - (frame->header.flags & MAD_FLAG_PROTECTION ? 2 : 0);
937 int len = stream->anc_bitlen / 8;
940 if (len < 4 || (memcmp(ptr,
"Xing", 4) != 0 && memcmp(ptr,
"Info", 4) != 0))
942 return MAD_FLOW_CONTINUE;
958 unsigned int flags = (((((ptr[0] << 8) + ptr[1]) << 8) + ptr[2]) << 8) + ptr[3];
963 if (len >= 4 && flags & hasFrames)
970 if (len >= 4 && flags & hasBytes)
977 if (len >= 100 && flags & hasToc)
984 if (len >= 4 && flags & hasScale)
991 if (len < 24 || memcmp(ptr,
"LAME", 4) != 0)
993 return MAD_FLOW_IGNORE;
1008 return MAD_FLOW_IGNORE;
1047 auto samples = pcm->length;
1053 float sampleBuf[1152];
1054 wxASSERT(samples <= 1152);
1057 for (
int sample = 0; sample < samples; ++sample)
1060 sampleBuf[sample] = ((float) pcm->samples[chn][sample] / (1L << MAD_F_FRACBITS));
1067 return MAD_FLOW_CONTINUE;
1090 return MAD_FLOW_CONTINUE;
1095 if (stream->error == MAD_ERROR_BADDATAPTR &&
mNumChannels == 0)
1097 return MAD_FLOW_CONTINUE;
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;
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.
wxArrayStringEx FileExtensions
std::vector< std::shared_ptr< WaveTrack > > NewChannelGroup
std::vector< std::vector< std::shared_ptr< WaveTrack > > > TrackHolders
static Importer::RegisteredImportPlugin registered
#define INPUT_BUFFER_SIZE
The interface that all file import "plugins" (if you want to call them that) must implement....
std::vector< TranslatableString > TranslatableStrings
The top-level handle to an Audacity project. It serves as a source of events that other objects can b...
An ImportFileHandle for data.
unsigned long long ByteCount
std::unique_ptr< ProgressDialog > mProgress
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...
An ImportFileHandle for MP3 data.
ProgressResult Import(WaveTrackFactory *trackFactory, TrackHolders &outTracks, Tags *tags) override
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
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...
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
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.
auto end(const Ptr< Type, BaseDeleter > &p)
Enables range-for.
auto begin(const Ptr< Type, BaseDeleter > &p)
Enables range-for.