File indexing completed on 2024-07-14 04:43:24

0001 /*
0002 
0003     SPDX-FileCopyrightText: 1998-2008 Sebastian Trueg <trueg@k3b.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 #include "k3bwavedecoder.h"
0008 #include "k3bplugin_i18n.h"
0009 
0010 #include <config-k3b.h>
0011 
0012 #include <QDebug>
0013 #include <QFile>
0014 
0015 
0016 K_PLUGIN_CLASS_WITH_JSON(K3bWaveDecoderFactory, "k3bwavedecoder.json")
0017 
0018 static unsigned short le_a_to_u_short( unsigned char* a ) {
0019     return ((unsigned short)
0020             ((a[0]       & 0xFF) |
0021              (a[1] << 8  & 0xFF00)) );
0022 }
0023 
0024 static unsigned long le_a_to_u_long( unsigned char* a ) {
0025     return ((unsigned long)
0026             ((a[0]       & 0xFF) |
0027              (a[1] << 8  & 0xFF00) |
0028              (a[2] << 16 & 0xFF0000) |
0029              (a[3] << 24 & 0xFF000000)) );
0030 }
0031 
0032 
0033 /**
0034  * Returns the length of the wave file in bytes
0035  * Otherwise 0 is returned.
0036  * leave file seek pointer past WAV header.
0037  */
0038 static unsigned long identifyWaveFile( QFile& f, int* samplerate = 0, int* channels = 0, int* samplesize = 0 )
0039 {
0040     typedef struct {
0041         unsigned char   ckid[4];
0042         unsigned char   cksize[4];
0043     } chunk_t;
0044 
0045     typedef struct {
0046         unsigned char   wave[4];
0047     } riff_chunk;
0048 
0049     typedef struct {
0050         unsigned char   fmt_tag[2];
0051         unsigned char   channels[2];
0052         unsigned char   sample_rate[4];
0053         unsigned char   av_byte_rate[4];
0054         unsigned char   block_size[2];
0055         unsigned char   bits_per_sample[2];
0056     } fmt_chunk;
0057 
0058     static const char WAV_RIFF_MAGIC[] = "RIFF";        // Magic for file format
0059     static const char WAV_WAVE_MAGIC[] = "WAVE";        // Magic for Waveform Audio
0060     static const char WAV_FMT_MAGIC[]  = "fmt ";        // Start of Waveform format
0061     static const char WAV_DATA_MAGIC[] = "data";        // Start of data chunk
0062 
0063     chunk_t chunk;
0064     riff_chunk riff;
0065     fmt_chunk fmt;
0066 
0067 
0068     // read riff chunk
0069     if( f.read( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) {
0070         qDebug() << "(K3bWaveDecoder) unable to read from " << f.fileName();
0071         return 0;
0072     }
0073     if( qstrncmp( (char*)chunk.ckid, WAV_RIFF_MAGIC, 4 ) ) {
0074         qDebug() << "(K3bWaveDecoder) " << f.fileName() << ": not a RIFF file.";
0075         return 0;
0076     }
0077 
0078     // read wave chunk
0079     if( f.read( (char*)&riff, sizeof(riff) ) != sizeof(riff) ) {
0080         qDebug() << "(K3bWaveDecoder) unable to read from " << f.fileName();
0081         return 0;
0082     }
0083     if( qstrncmp( (char*)riff.wave, WAV_WAVE_MAGIC, 4 ) ) {
0084         qDebug() << "(K3bWaveDecoder) " << f.fileName() << ": not a WAVE file.";
0085         return 0;
0086     }
0087 
0088 
0089     // read fmt chunk
0090     if( f.read( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) {
0091         qDebug() << "(K3bWaveDecoder) unable to read from " << f.fileName();
0092         return 0;
0093     }
0094     if( qstrncmp( (char*)chunk.ckid, WAV_FMT_MAGIC, 4 ) ) {
0095         qDebug() << "(K3bWaveDecoder) " << f.fileName() << ": could not find format chunk.";
0096         return 0;
0097     }
0098     if( f.read( (char*)&fmt, sizeof(fmt) ) != sizeof(fmt) ) {
0099         qDebug() << "(K3bWaveDecoder) unable to read from " << f.fileName();
0100         return 0;
0101     }
0102     if( le_a_to_u_short(fmt.fmt_tag) != 1 ||
0103         le_a_to_u_short(fmt.channels) > 2 ||
0104         ( le_a_to_u_short(fmt.bits_per_sample) != 16 &&
0105           le_a_to_u_short(fmt.bits_per_sample) != 8 ) ) {
0106         qDebug() << "(K3bWaveDecoder) " << f.fileName() << ": wrong format:" << Qt::endl
0107                  << "                format:      " << le_a_to_u_short(fmt.fmt_tag) << Qt::endl
0108                  << "                channels:    " << le_a_to_u_short(fmt.channels) << Qt::endl
0109                  << "                samplerate:  " << le_a_to_u_long(fmt.sample_rate) << Qt::endl
0110                  << "                bits/sample: " << le_a_to_u_short(fmt.bits_per_sample) << Qt::endl;
0111         return 0;
0112     }
0113 
0114     int sampleRate = le_a_to_u_long(fmt.sample_rate);
0115     int ch = le_a_to_u_short(fmt.channels);
0116     int sampleSize = le_a_to_u_short(fmt.bits_per_sample);;
0117     if( samplerate )
0118         *samplerate = sampleRate;
0119     if( channels )
0120         *channels = ch;
0121     if( samplesize )
0122         *samplesize = sampleSize;
0123 
0124     // skip all other (unknown) format chunk fields
0125     if( !f.seek( f.pos() + le_a_to_u_long(chunk.cksize) - sizeof(fmt) ) ) {
0126         qDebug() << "(K3bWaveDecoder) " << f.fileName() << ": could not seek in file.";
0127         return 0;
0128     }
0129 
0130 
0131     // find data chunk
0132     bool foundData = false;
0133     while( !foundData ) {
0134         if( f.read( (char*)&chunk, sizeof(chunk) ) != sizeof(chunk) ) {
0135             qDebug() << "(K3bWaveDecoder) unable to read from " << f.fileName();
0136             return 0;
0137         }
0138 
0139         // skip chunk data of unknown chunk
0140         if( qstrncmp( (char*)chunk.ckid, WAV_DATA_MAGIC, 4 ) ) {
0141             qDebug() << "(K3bWaveDecoder) skipping chunk: " << (char*)chunk.ckid;
0142             if( !f.seek( f.pos() + le_a_to_u_long(chunk.cksize) ) ) {
0143                 qDebug() << "(K3bWaveDecoder) " << f.fileName() << ": could not seek in file.";
0144                 return 0;
0145             }
0146         }
0147         else
0148             foundData = true;
0149     }
0150 
0151     // found data chunk
0152     unsigned long size = le_a_to_u_long(chunk.cksize);
0153     if( f.pos() + size > (unsigned long)f.size() ) {
0154         qDebug() << "(K3bWaveDecoder) " << f.fileName() << ": file length " << f.size()
0155                  << " does not match length from WAVE header " << f.pos() << " + " << size
0156                  << " - using actual length." << Qt::endl;
0157         size = (f.size() - f.pos());
0158     }
0159 
0160     return size;
0161 }
0162 
0163 
0164 class K3bWaveDecoder::Private {
0165 public:
0166     Private()
0167         : buffer(0),
0168           bufferSize(0) {
0169     }
0170 
0171     QFile file;
0172 
0173     long headerLength;
0174     int sampleRate;
0175     int channels;
0176     int sampleSize;
0177     unsigned long size;
0178     unsigned long alreadyRead;
0179 
0180     char* buffer;
0181     int bufferSize;
0182 };
0183 
0184 
0185 K3bWaveDecoder::K3bWaveDecoder( QObject* parent  )
0186     : K3b::AudioDecoder( parent ),
0187       d( new Private )
0188 {
0189 }
0190 
0191 
0192 K3bWaveDecoder::~K3bWaveDecoder()
0193 {
0194 }
0195 
0196 
0197 int K3bWaveDecoder::decodeInternal( char* _data, int maxLen )
0198 {
0199     int read = 0;
0200 
0201     maxLen = qMin( maxLen, (int)(d->size - d->alreadyRead) );
0202 
0203     if( d->sampleSize == 16 ) {
0204         read = d->file.read( _data, maxLen );
0205         if( read > 0 ) {
0206             d->alreadyRead += read;
0207 
0208             if( read % 2 > 0 ) {
0209                 qDebug() << "(K3bWaveDecoder) data length is not a multiple of 2! Cutting data.";
0210                 read -= 1;
0211             }
0212 
0213             // swap bytes
0214             char buf;
0215             for( int i = 0; i < read; i+=2 ) {
0216                 buf = _data[i];
0217                 _data[i] = _data[i+1];
0218                 _data[i+1] = buf;
0219             }
0220         }
0221     }
0222     else {
0223         if( !d->buffer ) {
0224             d->buffer = new char[maxLen/2];
0225             d->bufferSize = maxLen/2;
0226         }
0227 
0228         read = d->file.read( d->buffer, qMin(maxLen/2, d->bufferSize) );
0229         d->alreadyRead += read;
0230 
0231         // stretch samples to 16 bit
0232         from8BitTo16BitBeSigned( d->buffer, _data, read );
0233 
0234         read *= 2;
0235     }
0236 
0237     return read;
0238 }
0239 
0240 
0241 bool K3bWaveDecoder::analyseFileInternal( K3b::Msf& frames, int& samplerate, int& channels )
0242 {
0243     // handling wave files is very easy...
0244     if( initDecoderInternal() ) {
0245 
0246         //
0247         // d->size is the number of bytes in the wave file
0248         //
0249         unsigned long size = d->size;
0250         if( d->sampleRate != 44100 )
0251             size = (int)((double)size * 44100.0 / (double)d->sampleRate);
0252 
0253         if( d->sampleSize == 8 )
0254             size *= 2;
0255         if( d->channels == 1 )
0256             size *= 2;
0257 
0258         //
0259         // we pad to a multiple of 2352 bytes
0260         // (the actual padding of zero data will be done by the K3b::AudioDecoder class)
0261         //
0262         if( (size%2352) > 0 )
0263             size = (size/2352) + 1;
0264         else
0265             size = size/2352;
0266 
0267         frames = size;
0268         samplerate = d->sampleRate;
0269         channels = d->channels;
0270         return true;
0271     }
0272     else
0273         return false;
0274 }
0275 
0276 
0277 bool K3bWaveDecoder::initDecoderInternal()
0278 {
0279     cleanup();
0280 
0281     d->file.setFileName( filename() );
0282     if( !d->file.open( QIODevice::ReadOnly ) ) {
0283         qDebug() << "(K3bWaveDecoder) could not open file.";
0284         return false;
0285     }
0286 
0287     // skip the header
0288     d->size = identifyWaveFile( d->file, &d->sampleRate, &d->channels, &d->sampleSize );
0289     if( d->size <= 0 ) {
0290         qDebug() << "(K3bWaveDecoder) no supported wave file.";
0291         cleanup();
0292         return false;
0293     }
0294 
0295     d->headerLength = d->file.pos();
0296     d->alreadyRead = 0;
0297 
0298     return true;
0299 }
0300 
0301 
0302 bool K3bWaveDecoder::seekInternal( const K3b::Msf& pos )
0303 {
0304     return( d->file.seek( d->headerLength + (pos.totalFrames()*2352) ) );
0305 }
0306 
0307 
0308 void K3bWaveDecoder::cleanup()
0309 {
0310     if( d->file.isOpen() )
0311         d->file.close();
0312 }
0313 
0314 
0315 QString K3bWaveDecoder::fileType() const
0316 {
0317     return i18n("WAVE");
0318 }
0319 
0320 
0321 QStringList K3bWaveDecoder::supportedTechnicalInfos() const
0322 {
0323     return QString( i18n("Channels") + ';' +
0324                     i18n("Sampling Rate") + ';' +
0325                     i18n("Sample Size") ).split( ';' );
0326 }
0327 
0328 
0329 QString K3bWaveDecoder::technicalInfo( const QString& name ) const
0330 {
0331     if( name == i18n("Channels") )
0332         return QString::number(d->channels);
0333     else if( name == i18n("Sampling Rate") )
0334         return i18n("%1 Hz",d->sampleRate);
0335     else if( name == i18n("Sample Size") )
0336         return i18np("1 bit","%1 bits",d->sampleSize);
0337     else
0338         return QString();
0339 }
0340 
0341 
0342 K3bWaveDecoderFactory::K3bWaveDecoderFactory( QObject* parent, const QVariantList& )
0343     : K3b::AudioDecoderFactory( parent )
0344 {
0345 }
0346 
0347 
0348 K3bWaveDecoderFactory::~K3bWaveDecoderFactory()
0349 {
0350 }
0351 
0352 
0353 K3b::AudioDecoder* K3bWaveDecoderFactory::createDecoder( QObject* parent ) const
0354 {
0355     return new K3bWaveDecoder( parent );
0356 }
0357 
0358 
0359 bool K3bWaveDecoderFactory::canDecode( const QUrl& url )
0360 {
0361     QFile f( url.toLocalFile() );
0362     if( !f.open(    QIODevice::ReadOnly ) ) {
0363         qDebug() << "(K3bWaveDecoder) could not open file " << url.toLocalFile();
0364         return false;
0365     }
0366 
0367     return (identifyWaveFile( f ) > 0);
0368 }
0369 
0370 
0371 
0372 #include "k3bwavedecoder.moc"
0373 
0374 #include "moc_k3bwavedecoder.cpp"