File indexing completed on 2024-04-28 04:49:29

0001 /*
0002     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #ifndef _K3B_AUDIO_DECODER_H_
0008 #define _K3B_AUDIO_DECODER_H_
0009 
0010 #include "k3bplugin.h"
0011 #include "k3bmsf.h"
0012 #include "k3b_export.h"
0013 #include <QUrl>
0014 
0015 
0016 namespace K3b {
0017     /**
0018      * Abstract streaming class for all the audio input.
0019      * Has to output data in the following format:
0020      * MSBLeft LSBLeft MSBRight LSBRight (big endian byte order)
0021      *
0022      * Instances are created by AudioDecoderFactory
0023      **/
0024     class LIBK3B_EXPORT AudioDecoder : public QObject
0025     {
0026         Q_OBJECT
0027 
0028     public:
0029         explicit AudioDecoder( QObject* parent = 0 );
0030         ~AudioDecoder() override;
0031 
0032         /**
0033          * Set the file to decode. Be aware that one cannot rely
0034          * on the file length until analyseFile() has been called.
0035          */
0036         void setFilename( const QString& );
0037 
0038         /**
0039          * Since this may take a while depending on the filetype it is best
0040          * to run it in a separate thread.
0041          *
0042          * This method will also call initDecoder().
0043          *
0044          * \sa AudioFielAnalyzerJob
0045          */
0046         bool analyseFile();
0047 
0048         /**
0049          * @return true if the file was successfully analysed by analyseFile.
0050          */
0051         bool isValid() const;
0052 
0053         /**
0054          * Initialize the decoding.
0055          * Normally there is no need to call this as analyseFile already does so.
0056          */
0057         bool initDecoder();
0058 
0059         /**
0060          * initialize the decoding.
0061          * @param startOffset the number of frames to skip at the beginning of the file.
0062          *
0063          * This is the same as calling: initDecoder() and seek(startOffset)
0064          */
0065         bool initDecoder( const Msf& startOffset );
0066 
0067         enum MetaDataField {
0068             META_TITLE,
0069             META_ARTIST,
0070             META_SONGWRITER,
0071             META_COMPOSER,
0072             META_COMMENT
0073         };
0074 
0075         /**
0076          * This should at least support "Title" and "Artist"
0077          *
0078          * the default implementation returns the infos set via @p addMetaInfo
0079          * and uses KFileMetaData if none was set
0080          */
0081         virtual QString metaInfo( MetaDataField );
0082 
0083         /**
0084          * The filetype is only used for informational purposes.
0085          * It is not necessary but highly recommended to implement this method
0086          * as it enhances usability.
0087          * @return The filetype of the decoded file.
0088          */
0089         virtual QString fileType() const { return QString(); }
0090 
0091         /**
0092          * This method may be reimplemented to provide technical information about
0093          * the file. It should return localized strings.
0094          *
0095          * the default implementation returns the infos set via @p addTechnicalInfo
0096          */
0097         virtual QStringList supportedTechnicalInfos() const;
0098 
0099         /**
0100          * The framework will call this method with all strings returned by the
0101          * supportedTechnicalInfos() method. It should return localized strings.
0102          *
0103          * the default implementation returns the infos set via @p addTechnicalInfo
0104          */
0105         virtual QString technicalInfo( const QString& ) const;
0106 
0107         /**
0108          * returns -1 on error, 0 when finished, length of data otherwise
0109          * takes care of padding
0110          * calls decodeInternal() to actually decode data
0111          *
0112          * Fill the data buffer with maximal maxLen bytes.
0113          */
0114         int decode( char* data, int maxLen );
0115 
0116         /**
0117          * Cleanup after decoding like closing files.
0118          * Be aware that this is the counterpart to @p initDecoder().
0119          *
0120          * There might happen multiple calls to initDecoder() and cleanup().
0121          */
0122         virtual void cleanup();
0123 
0124         /**
0125          * Seek to the position pos.
0126          * Decoding is started new. That means that the data will be padded to
0127          * length() - pos.
0128          * returns true on success;
0129          */
0130         bool seek( const Msf& pos );
0131 
0132         /**
0133          * Be aware that one cannot rely
0134          * on the file length until analyseFile() has been called.
0135          */
0136         virtual Msf length() const { return m_length; }
0137 
0138         const QString& filename() const { return m_fileName; }
0139 
0140         // some helper methods
0141         static void fromFloatTo16BitBeSigned( float* src, char* dest, int samples );
0142         static void from16bitBeSignedToFloat( char* src, float* dest, int samples );
0143         static void from8BitTo16BitBeSigned( char* src, char* dest, int samples );
0144 
0145     protected:
0146         /**
0147          * Use this method if using the default implementation of @p metaInfo
0148          */
0149         void addMetaInfo( MetaDataField, const QString& );
0150 
0151         /**
0152          * Use this method if using the default implementation of @p technicalInfo
0153          * and @p supportedTechnicalInfos.
0154          */
0155         void addTechnicalInfo( const QString&, const QString& );
0156 
0157         /**
0158          * This will be called once before the first call to decodeInternal.
0159          * Use it to initialize decoding structures if necessary.
0160          *
0161          * There might happen multiple calls to initDecoder() and cleanup().
0162          */
0163         virtual bool initDecoderInternal() = 0;
0164 
0165         /**
0166          * This method should analyze the file to determine the exact length,
0167          * the samplerate in Hz, and the number of channels. The framework takes care of
0168          * resampling and converting mono to stereo data.
0169          * This method may be time consuming.
0170          */
0171         virtual bool analyseFileInternal( Msf& length, int& samplerate, int& channels ) = 0;
0172 
0173         /**
0174          * fill the already allocated data with maximal maxLen bytes of decoded samples.
0175          * The framework will take care of padding or cutting the decoded data as well
0176          * as resampling to 44100 Hz and converting mono samples to stereo.
0177          */
0178         virtual int decodeInternal( char* data, int maxLen ) = 0;
0179 
0180         virtual bool seekInternal( const Msf& ) { return false; }
0181 
0182     private:
0183         int resample( char* data, int maxLen );
0184 
0185         QString m_fileName;
0186         Msf m_length;
0187 
0188         class Private;
0189         Private* d;
0190     };
0191 
0192 
0193     /**
0194      * PluginFactory that needs to be subclassed in order to create an
0195      * audio decoder.
0196      * We need this because K3b uses multiple AudioDecoders of the same type at the
0197      * same time.
0198      */
0199     class LIBK3B_EXPORT AudioDecoderFactory : public Plugin
0200     {
0201         Q_OBJECT
0202 
0203     public:
0204         explicit AudioDecoderFactory( QObject* parent = 0 )
0205             : Plugin( parent ) {
0206         }
0207 
0208         ~AudioDecoderFactory() override {
0209         }
0210 
0211         QString category() const override { return "AudioDecoder"; }
0212 
0213         QString categoryName() const override;
0214 
0215         /**
0216          * K3b uses this flag to decide which plugins to test first
0217          * when searching for an audio decoder.
0218          *
0219          * Decoders that are specialized on one format are favored over
0220          * multi-format-decoders.
0221          */
0222         virtual bool multiFormatDecoder() const { return false; }
0223 
0224         /**
0225          * This is the most important method of the AudioDecoderFactory.
0226          * It is used to determine if a certain file can be decoded by the
0227          * decoder this factory creates.
0228          * It is important that this method does not work lazy since it will
0229          * be called with urls to every kind of files and if it returns true
0230          * a decoder of this type is used for the file.
0231          */
0232         virtual bool canDecode( const QUrl& filename ) = 0;
0233 
0234         virtual AudioDecoder* createDecoder( QObject* parent = 0 ) const = 0;
0235 
0236         /**
0237          * Searching for an audiodecoder for @p filename.
0238          *
0239          * It first searches the single format decoder and the multiformat decoder.
0240          *
0241          * @returns a newly created decoder on success and 0 when no decoder could be found.
0242          */
0243         static AudioDecoder* createDecoder( const QUrl& url );
0244     };
0245 }
0246 
0247 #endif