Chris@148: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@148: Chris@148: /* Chris@148: Sonic Visualiser Chris@148: An audio file viewer and annotation editor. Chris@148: Centre for Digital Music, Queen Mary, University of London. Chris@148: This file copyright 2006 Chris Cannam. Chris@148: Chris@148: This program is free software; you can redistribute it and/or Chris@148: modify it under the terms of the GNU General Public License as Chris@148: published by the Free Software Foundation; either version 2 of the Chris@148: License, or (at your option) any later version. See the file Chris@148: COPYING included with this distribution for more information. Chris@148: */ Chris@148: Chris@148: #ifndef _MP3_FILE_READER_H_ Chris@148: #define _MP3_FILE_READER_H_ Chris@148: Chris@148: #ifdef HAVE_MAD Chris@148: Chris@148: #include "CodedAudioFileReader.h" Chris@148: Chris@263: #include "base/Thread.h" Chris@148: #include Chris@148: Chris@157: #include Chris@157: Chris@392: class ProgressReporter; Chris@148: Chris@148: class MP3FileReader : public CodedAudioFileReader Chris@148: { Chris@392: Q_OBJECT Chris@392: Chris@148: public: Chris@1305: /** Chris@1305: * How the MP3FileReader should handle leading and trailing gaps. Chris@1305: * See http://lame.sourceforge.net/tech-FAQ.txt for a technical Chris@1305: * explanation of the numbers here. Chris@1305: */ Chris@1305: enum GaplessMode { Chris@1305: /** Chris@1305: * Trim unwanted samples from the start and end of the decoded Chris@1305: * audio. From the start, trim a number of samples equal to Chris@1305: * the decoder delay (a fixed 529 samples) plus any encoder Chris@1305: * delay that may be specified in Xing/LAME metadata. From the Chris@1305: * end, trim any padding specified in Xing/LAME metadata, less Chris@1305: * the fixed decoder delay. This usually results in "gapless" Chris@1305: * audio, i.e. with no spurious zero padding at either end. Chris@1305: */ Chris@1305: Gapless, Chris@1305: Chris@1305: /** Chris@1305: * Do not trim any samples. Also do not suppress any frames Chris@1305: * from being passed to the mp3 decoder, even Xing/LAME Chris@1305: * metadata frames. This will result in the audio being padded Chris@1305: * with zeros at either end: at the start, typically Chris@1305: * 529+576+1152 = 2257 samples for LAME-encoded mp3s; at the Chris@1305: * end an unknown number depending on the fill ratio of the Chris@1305: * final coded frame, but typically less than 1152-529 = 623. Chris@1305: * Chris@1305: * This mode produces the same output as produced by older Chris@1305: * versions of this code before the gapless option was added, Chris@1305: * and is present mostly for backward compatibility. Chris@1305: */ Chris@1305: Gappy Chris@1305: }; Chris@1305: Chris@317: MP3FileReader(FileSource source, Chris@297: DecodeMode decodeMode, Chris@297: CacheMode cacheMode, Chris@1305: GaplessMode gaplessMode, Chris@1040: sv_samplerate_t targetRate = 0, Chris@920: bool normalised = false, Chris@392: ProgressReporter *reporter = 0); Chris@148: virtual ~MP3FileReader(); Chris@148: Chris@290: virtual QString getError() const { return m_error; } Chris@290: Chris@345: virtual QString getLocation() const { return m_source.getLocation(); } Chris@290: virtual QString getTitle() const { return m_title; } Chris@334: virtual QString getMaker() const { return m_maker; } Chris@632: virtual TagMap getTags() const { return m_tags; } Chris@271: Chris@290: static void getSupportedExtensions(std::set &extensions); Chris@316: static bool supportsExtension(QString ext); Chris@316: static bool supportsContentType(QString type); Chris@317: static bool supports(FileSource &source); Chris@316: Chris@265: virtual int getDecodeCompletion() const { return m_completion; } Chris@265: Chris@263: virtual bool isUpdating() const { Chris@263: return m_decodeThread && m_decodeThread->isRunning(); Chris@263: } Chris@263: Chris@392: public slots: Chris@392: void cancelled(); Chris@392: Chris@148: protected: Chris@317: FileSource m_source; Chris@290: QString m_path; Chris@290: QString m_error; Chris@290: QString m_title; Chris@333: QString m_maker; Chris@632: TagMap m_tags; Chris@1305: GaplessMode m_gaplessMode; Chris@1038: sv_frame_t m_fileSize; Chris@148: double m_bitrateNum; Chris@929: int m_bitrateDenom; Chris@1288: int m_mp3FrameCount; Chris@265: int m_completion; Chris@263: bool m_done; Chris@263: Chris@1290: unsigned char *m_fileBuffer; Chris@1290: size_t m_fileBufferSize; Chris@1290: Chris@1290: float **m_sampleBuffer; Chris@1290: size_t m_sampleBufferSize; Chris@148: Chris@392: ProgressReporter *m_reporter; Chris@148: bool m_cancelled; Chris@148: Chris@1284: bool m_decodeErrorShown; Chris@1284: Chris@1290: struct DecoderData { Chris@148: unsigned char const *start; Chris@1288: sv_frame_t length; Chris@148: MP3FileReader *reader; Chris@148: }; Chris@148: Chris@1038: bool decode(void *mm, sv_frame_t sz); Chris@1288: enum mad_flow filter(struct mad_stream const *, struct mad_frame *); Chris@148: enum mad_flow accept(struct mad_header const *, struct mad_pcm *); Chris@148: Chris@1288: static enum mad_flow input_callback(void *, struct mad_stream *); Chris@1288: static enum mad_flow output_callback(void *, struct mad_header const *, Chris@1288: struct mad_pcm *); Chris@1288: static enum mad_flow filter_callback(void *, struct mad_stream const *, Chris@1288: struct mad_frame *); Chris@1288: static enum mad_flow error_callback(void *, struct mad_stream *, Chris@1288: struct mad_frame *); Chris@263: Chris@263: class DecodeThread : public Thread Chris@263: { Chris@263: public: Chris@263: DecodeThread(MP3FileReader *reader) : m_reader(reader) { } Chris@263: virtual void run(); Chris@263: Chris@263: protected: Chris@263: MP3FileReader *m_reader; Chris@263: }; Chris@263: Chris@263: DecodeThread *m_decodeThread; Chris@271: Chris@271: void loadTags(); Chris@333: QString loadTag(void *vtag, const char *name); Chris@148: }; Chris@148: Chris@148: #endif Chris@148: Chris@148: #endif