38#define DESC XO("MP3 files")
67#include "../widgets/AudacityMessageBox.h"
68#include "../widgets/ProgressDialog.h"
85#define INPUT_BUFFER_SIZE 65535
130 static mad_flow
input_cb(
void *that,
144 static mad_flow
error_cb(
void *that,
188 return wxT(
"libmad");
199 auto handle = std::make_unique<MP3ImportFileHandle>(Filename);
212 std::make_unique<MP3ImportPlugin>()
274 auto res = mad_decoder_run(&
mDecoder, MAD_DECODER_MODE_SYNC);
282 return ProgressResult::Failed;
299 double et = channel->GetEndTime();
300 double t1 = et - channel->LongSamplesToTime(
mPadding);
301 channel->Clear(t1, et);
307 double st = channel->GetStartTime();
308 double t0 = st + channel->LongSamplesToTime(
mDelay);
309 channel->Clear(st, t0);
315 outTracks.push_back(std::move(
mChannels));
343 if (
mFile.Seek(0, wxFromStart) == wxInvalidOffset ||
mFile.Error())
365 for (
int i = 0; i < 2; ++i)
373 for (
int i = 0; i < 2; ++i)
389 if (
mFile.Seek(offset, wxFromStart) == wxInvalidOffset ||
mFile.Error())
422 mFileLen -= ((hasHeader ? 32 : 0) + len);
458 if (
mFile.Seek(offset, wxFromStart) == wxInvalidOffset ||
mFile.Error())
472 wxFileOffset pos = wxMax(offset - 5100, 0);
473 size_t len = offset - pos;
476 if (
mFile.Seek(pos, wxFromStart) == wxInvalidOffset ||
mFile.Error())
488 for (
size_t i = 0; i < len; ++i)
502 if (
mFile.Seek(-15, wxFromCurrent) == wxInvalidOffset ||
mFile.Error())
524 if (
mFile.Seek(offset, wxFromStart) == wxInvalidOffset ||
mFile.Error())
536 if (memcmp(
mInputBuffer, atEnd ?
"3DI" :
"ID3", 3) != 0)
579 mad_stream_init(&stream);
584 mad_header_init(&header);
590 while (consecutive > 0)
593 if (mad_header_decode(&header, &stream))
596 if (stream.error != MAD_ERROR_NONE)
606 int used = stream.this_frame - stream.buffer;
609 mad_header_finish(&header);
610 mad_stream_finish(&stream);
640 if (got != want ||
mFile.Error())
664 struct id3_file *id3file = NULL;
665 auto cleanup =
finally([&]
669 id3_file_close(id3file);
675 id3file = id3_file_fdopen(
mFile.fd(), ID3_FILE_MODE_READONLY);
686 struct id3_tag *id3tags = id3_file_tag(id3file);
687 if (!id3tags || id3tags->nframes == 0)
697 wxMBConvUTF32 converter;
698 auto toString = [=](
const id3_ucs4_t *in)
702 for (
const id3_ucs4_t *p = in; *p; p++)
709 wxUint32 *buf = (wxUint32 *) alloca((len + 1) *
sizeof(wxUint32));
713 for (out = buf; *in; in++, out++)
715 *out = (wxUint32) (*in);
720 return wxString((
char *) buf, converter);
726 bool have_year =
false;
727 for (
unsigned int i = 0; i < id3tags->nframes; ++i)
729 struct id3_frame *frame = id3tags->frames[i];
732 wxLogDebug(
"ID: %08x '%4s'", (
int) *(
int *)frame->id, frame->id);
733 wxLogDebug(
"Desc: %s", frame->description);
734 wxLogDebug(
"Num fields: %d", frame->nfields);
736 for (
unsigned int j = 0; j < frame->nfields; ++j)
738 wxLogDebug(
"field %d type %d", j, frame->fields[j].type);
739 if (frame->fields[j].type == ID3_FIELD_TYPE_STRINGLIST)
741 wxLogDebug(
"num strings %d", frame->fields[j].stringlist.nstrings);
750 if (strcmp(frame->id, ID3_FRAME_TITLE) == 0)
754 else if (strcmp(frame->id, ID3_FRAME_ARTIST) == 0)
758 else if (strcmp(frame->id, ID3_FRAME_ALBUM) == 0)
762 else if (strcmp(frame->id, ID3_FRAME_TRACK) == 0)
766 else if (strcmp(frame->id, ID3_FRAME_YEAR) == 0)
781 else if (strcmp(frame->id, ID3_FRAME_COMMENT) == 0)
785 else if (strcmp(frame->id, ID3_FRAME_GENRE) == 0)
794 n =
UTF8CTOWX(frame->description).BeforeFirst(
wxT(
'/'));
798 const id3_ucs4_t *ustr = NULL;
802 ustr = id3_field_getfullstring(&frame->fields[3]);
804 else if (frame->nfields == 3)
806 ustr = id3_field_getstring(&frame->fields[1]);
812 ustr = id3_field_getstring(&frame->fields[2]);
814 else if (frame->nfields >= 2)
816 ustr = id3_field_getstrings(&frame->fields[1], 0);
826 if (!n.empty() && !v.empty())
868 return MAD_FLOW_STOP;
874 return MAD_FLOW_STOP;
884 if (stream->next_frame)
893 return MAD_FLOW_BREAK;
899 return MAD_FLOW_CONTINUE;
923 if (memcmp(&stream->this_frame[4 + 32],
"VBRI", 4) == 0)
925 mDelay = (stream->this_frame[4 + 32 + 6] & 0xff) << 8 |
926 (stream->this_frame[4 + 32 + 7] & 0xff);
928 return MAD_FLOW_CONTINUE;
935 auto ptr = stream->anc_ptr.byte - (frame->header.flags & MAD_FLAG_PROTECTION ? 2 : 0);
936 int len = stream->anc_bitlen / 8;
939 if (len < 4 || (memcmp(ptr,
"Xing", 4) != 0 && memcmp(ptr,
"Info", 4) != 0))
941 return MAD_FLOW_CONTINUE;
957 unsigned int flags = (((((ptr[0] << 8) + ptr[1]) << 8) + ptr[2]) << 8) + ptr[3];
962 if (len >= 4 && flags & hasFrames)
969 if (len >= 4 && flags & hasBytes)
976 if (len >= 100 && flags & hasToc)
983 if (len >= 4 && flags & hasScale)
990 if (len < 24 || memcmp(ptr,
"LAME", 4) != 0)
992 return MAD_FLOW_IGNORE;
1007 return MAD_FLOW_IGNORE;
1046 auto samples = pcm->length;
1052 float sampleBuf[1152];
1053 wxASSERT(samples <= 1152);
1056 for (
int sample = 0; sample < samples; ++sample)
1059 sampleBuf[sample] = ((float) pcm->samples[chn][sample] / (1L << MAD_F_FRACBITS));
1072 return MAD_FLOW_CONTINUE;
1095 return MAD_FLOW_CONTINUE;
1100 if (stream->error == MAD_ERROR_BADDATAPTR &&
mNumChannels == 0)
1102 return MAD_FLOW_CONTINUE;
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;
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.