File indexing completed on 2024-05-12 04:55:35

0001 /**
0002  * \file fingerprintcalculator.cpp
0003  * Chromaprint fingerprint calculator.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 21 Jan 2012
0008  *
0009  * Copyright (C) 2012-2018  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #define __STDC_CONSTANT_MACROS
0028 #include "fingerprintcalculator.h"
0029 #include "config.h"
0030 #include "abstractfingerprintdecoder.h"
0031 
0032 /**
0033  * Constructor.
0034  */
0035 FingerprintCalculator::FingerprintCalculator(QObject* parent) : QObject(parent),
0036   m_chromaprintCtx(nullptr),
0037   m_decoder(AbstractFingerprintDecoder::createFingerprintDecoder(this))
0038 {
0039   connect(m_decoder, &AbstractFingerprintDecoder::started,
0040           this, &FingerprintCalculator::startChromaprint);
0041   connect(m_decoder, &AbstractFingerprintDecoder::bufferReady,
0042           this, &FingerprintCalculator::feedChromaprint);
0043   connect(m_decoder, &AbstractFingerprintDecoder::error,
0044           this, &FingerprintCalculator::receiveError);
0045   connect(m_decoder, &AbstractFingerprintDecoder::finished,
0046           this, &FingerprintCalculator::finishChromaprint);
0047 }
0048 
0049 /**
0050  * Destructor.
0051  */
0052 FingerprintCalculator::~FingerprintCalculator()
0053 {
0054   if (m_chromaprintCtx) {
0055     ::chromaprint_free(m_chromaprintCtx);
0056   }
0057 }
0058 
0059 /**
0060  * Calculate audio fingerprint for audio file.
0061  * When the calculation is finished, finished() is emitted.
0062  *
0063  * @param fileName path to audio file
0064  */
0065 void FingerprintCalculator::start(const QString& fileName) {
0066   if (!m_chromaprintCtx) {
0067     // Lazy initialization to save resources if not used
0068     m_chromaprintCtx = ::chromaprint_new(CHROMAPRINT_ALGORITHM_DEFAULT);
0069   }
0070   m_decoder->start(fileName);
0071 }
0072 
0073 /**
0074  * Stop decoder.
0075  */
0076 void FingerprintCalculator::stop() {
0077   m_decoder->stop();
0078 }
0079 
0080 /**
0081  * Called when decoding starts.
0082  * @param sampleRate sample rate of the audio stream (in Hz)
0083  * @param channelCount numbers of channels in the audio stream (1 or 2)
0084  */
0085 void FingerprintCalculator::startChromaprint(int sampleRate, int channelCount)
0086 {
0087   ::chromaprint_start(m_chromaprintCtx, sampleRate, channelCount);
0088 }
0089 
0090 /**
0091  * Called when decoded data is available.
0092  * @param data 16-bit signed integers in native byte-order
0093  */
0094 void FingerprintCalculator::feedChromaprint(QByteArray data)
0095 {
0096   if (!::chromaprint_feed(m_chromaprintCtx,
0097                           reinterpret_cast<qint16*>(data.data()),
0098                           data.size() / 2)) {
0099     m_decoder->stop();
0100     emit finished(QString(), 0, FingerprintCalculationFailed);
0101   }
0102 }
0103 
0104 /**
0105  * Called when an error occurs.
0106  * @param err error code, enum FingerprintCalculator::Error
0107  */
0108 void FingerprintCalculator::receiveError(int err)
0109 {
0110   emit finished(QString(), 0, err);
0111 }
0112 
0113 /**
0114  * Called when decoding finished successfully.
0115  * @param duration duration of stream in seconds
0116  */
0117 void FingerprintCalculator::finishChromaprint(int duration)
0118 {
0119   int err = Ok;
0120   QString fingerprint;
0121   char* fp;
0122   if (::chromaprint_finish(m_chromaprintCtx) &&
0123       ::chromaprint_get_fingerprint(m_chromaprintCtx, &fp)) {
0124     fingerprint = QString::fromLatin1(fp);
0125     ::chromaprint_dealloc(fp);
0126   } else {
0127     err = FingerprintCalculationFailed;
0128   }
0129   emit finished(fingerprint, duration, err);
0130 }