24 #include <sys/types.h>    59     m_path(source.getLocalFilename()),
    60     m_gaplessMode(gaplessMode),
    61     m_decodeErrorShown(false),
    62     m_decodeThread(nullptr)
    65             << 
"\", decode mode: " << decodeMode << 
" ("    66             << (decodeMode == 
DecodeAtOnce ? 
"DecodeAtOnce" : 
"DecodeThreaded")
    93     if (!qfile.open(QIODevice::ReadOnly)) {
    94         m_error = QString(
"Failed to open file %1 for reading.").arg(
m_path);
   105         SVDEBUG << 
"file size = " << 
m_fileSize << 
", buffer guard = " << MAD_BUFFER_GUARD << endl;
   110         m_error = QString(
"Out of memory");
   115     auto amountRead = qfile.read(reinterpret_cast<char *>(
m_fileBuffer),
   119         SVCERR << QString(
"MP3FileReader::MP3FileReader: Warning: reached EOF after only %1 of %2 bytes")
   134                 (tr(
"Decoding %1...").arg(QFileInfo(
m_path).fileName()));
   167         SVDEBUG << 
"MP3FileReader: decoding startup complete, file rate = " << 
m_fileRate << endl;
   177     Profiler profiler(
"MP3FileReader::~MP3FileReader");
   200     int id3fd = _dup(fd);
   205     id3_file *file = id3_file_fdopen(id3fd, ID3_FILE_MODE_READONLY);
   211     id3_tag *tag = id3_file_tag(file);
   213         SVDEBUG << 
"MP3FileReader::loadTags: No ID3 tag found" << endl;
   214         id3_file_close(file); 
   220     if (
m_title == 
"") 
SVDEBUG << 
"MP3FileReader::loadTags: No title found" << endl;
   224     if (
m_maker == 
"") 
SVDEBUG << 
"MP3FileReader::loadTags: No artist/maker found" << endl;
   226     for (
unsigned int i = 0; i < tag->nframes; ++i) {
   227         if (tag->frames[i]) {
   228             QString value = 
loadTag(tag, tag->frames[i]->id);
   230                 m_tags[tag->frames[i]->id] = value;
   235     id3_file_close(file); 
   238     SVDEBUG << 
"MP3FileReader::loadTags: ID3 tag support not compiled in" << endl;
   246     id3_tag *tag = (id3_tag *)vtag;
   248     id3_frame *frame = id3_tag_findframe(tag, name, 0);
   250         SVDEBUG << 
"MP3FileReader::loadTag: No \"" << name << 
"\" frame found in ID3 tag" << endl;
   254     if (frame->nfields < 2) {
   255         cerr << 
"MP3FileReader::loadTag: WARNING: Not enough fields (" << frame->nfields << 
") for \"" << name << 
"\" in ID3 tag" << endl;
   259     unsigned int nstrings = id3_field_getnstrings(&frame->fields[1]);
   261         SVDEBUG << 
"MP3FileReader::loadTag: No strings for \"" << name << 
"\" in ID3 tag" << endl;
   265     id3_ucs4_t 
const *ustr = id3_field_getstrings(&frame->fields[1], 0);
   267         SVDEBUG << 
"MP3FileReader::loadTag: Invalid or absent data for \"" << name << 
"\" in ID3 tag" << endl;
   271     id3_utf8_t *u8str = id3_ucs4_utf8duplicate(ustr);
   273         SVDEBUG << 
"MP3FileReader::loadTag: ERROR: Internal error: Failed to convert UCS4 to UTF8 in ID3 tag" << endl;
   277     QString rv = QString::fromUtf8((
const char *)u8str);
   280     SVDEBUG << 
"MP3FileReader::loadTag: Tag \"" << name << 
"\" -> \""   281             << rv << 
"\"" << endl;
   293     if (!m_reader->decode(m_reader->m_fileBuffer, m_reader->m_fileBufferSize)) {
   294         m_reader->m_error = QString(
"Failed to decode file %1.").arg(m_reader->m_path);
   297     delete[] m_reader->m_fileBuffer;
   298     m_reader->m_fileBuffer = 
nullptr;
   300     if (m_reader->m_sampleBuffer) {
   301         for (
int c = 0; c < m_reader->m_channelCount; ++c) {
   302             delete[] m_reader->m_sampleBuffer[c];
   304         delete[] m_reader->m_sampleBuffer;
   305         m_reader->m_sampleBuffer = 
nullptr;
   308     if (m_reader->isDecodeCacheInitialised()) {
   309         m_reader->finishDecodeCache();
   312     m_reader->m_done = 
true;
   313     m_reader->m_completion = 100;
   315     m_reader->endSerialised();
   322     struct mad_decoder decoder;
   324     data.
start = (
unsigned char const *)mm;
   329     mad_decoder_init(&decoder,          
   338     mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
   339     mad_decoder_finish(&decoder);
   342             << 
" mp3 frames" << endl;
   355         return MAD_FLOW_STOP;
   358     unsigned char const *start = data->
start;
   362     while (length > ID3_TAG_QUERYSIZE) {
   363         ssize_t taglen = id3_tag_query(start, ID3_TAG_QUERYSIZE);
   367         SVDEBUG << 
"MP3FileReader: ID3 tag length to skip: " << taglen << endl;
   373     mad_stream_buffer(stream, start, length);
   376     return MAD_FLOW_CONTINUE;
   381                                struct mad_stream 
const *stream,
   382                                struct mad_frame *frame)
   390     string magic(
"....");
   391     for (
int i = 0; i < 4; ++i) {
   392         magic[3-i] = char((fourcc >> (8*i)) & 0xff);
   403         return MAD_FLOW_CONTINUE;
   414         SVDEBUG << 
"MP3FileReader: Not gapless mode, not checking Xing/LAME frame"   416         return MAD_FLOW_CONTINUE;
   419     struct mad_bitptr ptr = stream->anc_ptr;
   420     string magic = 
toMagic(mad_bit_read(&ptr, 32));
   422     if (magic == 
"Xing" || magic == 
"Info") {
   424         SVDEBUG << 
"MP3FileReader: Found Xing/LAME metadata frame (magic = \""   425                 << magic << 
"\")" << endl;
   436         for (
int skip = 0; skip < 116; ++skip) {
   437             (void)mad_bit_read(&ptr, 8);
   440         magic = 
toMagic(mad_bit_read(&ptr, 32));
   442         if (magic == 
"LAME") {
   444             SVDEBUG << 
"MP3FileReader: Found LAME-specific metadata" << endl;
   446             for (
int skip = 0; skip < 5 + 12; ++skip) {
   447                 (void)mad_bit_read(&ptr, 8);
   450             auto delay = mad_bit_read(&ptr, 12);
   451             auto padding = mad_bit_read(&ptr, 12);
   455             if (paddingToDrop < 0) paddingToDrop = 0;
   457             SVDEBUG << 
"MP3FileReader: LAME encoder delay = " << delay
   458                     << 
", padding = " << padding << endl;
   460             SVDEBUG << 
"MP3FileReader: Will be trimming " << delayToDrop
   461                     << 
" samples from start and " << paddingToDrop
   462                     << 
" from end" << endl;
   467             SVDEBUG << 
"MP3FileReader: Xing frame has no LAME metadata" << endl;
   470         return MAD_FLOW_IGNORE;
   473         return MAD_FLOW_CONTINUE;
   479                                struct mad_header 
const *header,
   490     int channels = pcm->channels;
   491     int frames = pcm->length;
   498     if (frames < 1) 
return MAD_FLOW_CONTINUE;
   505         SVDEBUG << 
"MP3FileReader::accept: file rate = " << pcm->samplerate
   506                 << 
", channel count = " << channels << 
", about to init "   507                 << 
"decode cache" << endl;
   515                 return MAD_FLOW_STOP;
   522         double duration = double(
m_fileSize * 8) / bitrate;
   524         double percent = 100;
   525         if (duration > 0.0) percent = ((elapsed * 100.0) / duration);
   526         int p = int(percent);
   536         SVDEBUG << 
"MP3FileReader: Decoding cancelled" << endl;
   537         return MAD_FLOW_STOP;
   541         SVDEBUG << 
"MP3FileReader::accept: fallback case: file rate = " << pcm->samplerate
   542                 << 
", channel count = " << channels << 
", about to init "   543                 << 
"decode cache" << endl;
   550             for (
int c = 0; c < channels; ++c) {
   554         for (
int c = 0; c < channels; ++c) {
   561     int activeChannels = int(
sizeof(pcm->samples) / 
sizeof(pcm->samples[0]));
   563     for (
int ch = 0; ch < channels; ++ch) {
   565         for (
int i = 0; i < frames; ++i) {
   567             mad_fixed_t sample = 0;
   568             if (ch < activeChannels) {
   569                 sample = pcm->samples[ch][i];
   571             float fsample = float(sample) / float(MAD_F_ONE);
   581     return MAD_FLOW_CONTINUE;
   586                               struct mad_stream *stream,
   593     if (stream->error == MAD_ERROR_LOSTSYNC &&
   597         return MAD_FLOW_CONTINUE;
   602         snprintf(buffer, 255,
   603                  "MP3 decoding error 0x%04x (%s) at byte offset %lld",
   604                  stream->error, mad_stream_errorstr(stream), (
long long int)ix);
   606                << buffer << 
" (continuing; will not report any further decode errors for this file)" << endl;
   610     return MAD_FLOW_CONTINUE;
   616     extensions.insert(
"mp3");
   622     std::set<QString> extensions;
   624     return (extensions.find(extension.toLower()) != extensions.end());
   630     return (type == 
"audio/mpeg");
 double sv_samplerate_t
Sample rate. 
unsigned char const * start
QString loadTag(void *vtag, const char *name)
enum mad_flow filter(struct mad_stream const *, struct mad_frame *)
int64_t sv_frame_t
Frame index, the unit of our time axis. 
static void getSupportedExtensions(std::set< QString > &extensions)
GaplessMode
How the MP3FileReader should handle leading and trailing gaps. 
static sv_frame_t DEFAULT_DECODER_DELAY
DecodeThread * m_decodeThread
unsigned char * m_fileBuffer
size_t m_sampleBufferSize
GaplessMode m_gaplessMode
enum mad_flow accept(struct mad_header const *, struct mad_pcm *)
static enum mad_flow filter_callback(void *, struct mad_stream const *, struct mad_frame *)
void startSerialised(QString id, const std::atomic< bool > *cancelled)
static string toMagic(unsigned long fourcc)
MP3FileReader(FileSource source, DecodeMode decodeMode, CacheMode cacheMode, GaplessMode gaplessMode, sv_samplerate_t targetRate=0, bool normalised=false, ProgressReporter *reporter=0)
Trim unwanted samples from the start and end of the decoded audio. 
bool decode(void *mm, sv_frame_t sz)
FileSource is a class used to refer to the contents of a file that may be either local or at a remote...
void addSamplesToDecodeCache(float **samples, sv_frame_t nframes)
QString getContentType() const 
Return the MIME content type of this file, if known. 
sv_samplerate_t m_fileRate
static enum mad_flow output_callback(void *, struct mad_header const *, struct mad_pcm *)
virtual void setProgress(int percentage)=0
static bool supports(FileSource &source)
ProgressReporter * m_reporter
void setFramesToTrim(sv_frame_t fromStart, sv_frame_t fromEnd)
void initialiseDecodeCache()
virtual void setMessage(QString text)=0
QString getExtension() const 
Return the file extension for this file, if any. 
static enum mad_flow error_callback(void *, struct mad_stream *, struct mad_frame *)
std::atomic< bool > m_cancelled
sv_samplerate_t m_sampleRate
bool isDecodeCacheInitialised() const 
static bool supportsExtension(QString ext)
static bool supportsContentType(QString type)
static enum mad_flow input_callback(void *, struct mad_stream *)
Profile point instance class.