void KeyAnalysisThread::analyzeSingleKey() { DBG("Thread: " << this->getThreadName() << " analyzing single key of: " << fileToAnalyze->getUUID()); //skip already-analyzed files if (fileToAnalyze->isFileAnalyzed() == "Yes") { DBG("Skipping analysis of " << fileToAnalyze->getFileName() << " : Already analyzed."); return; } //DBG("File being analyzed: " << fileToAnalyze.getFileToBeAnalyzed().getFileName()); // r> audioFormatReader = audioFormatManager.createReaderFor(fileToAnalyze.getFileToBeAnalyzed()); size_t numSamples = audioFormatReader->lengthInSamples; size_t numChannels = audioFormatReader->numChannels; size_t sampleRate = audioFormatReader->sampleRate; //size_t numFrames = numSamples / numChannels; //DBG("Samples:" + String(numSamples) + " Channels:" + String(numChannels) + " Frames:" + String(numFrames)); audioData.addToSampleCount(numSamples*numChannels); audioData.setChannels(numChannels); audioData.setFrameRate(sampleRate); AudioBuffer<float> audioBuffer(numChannels, numSamples); // #TODO(Casey): Fix either audiobuffer or audioData to allow direct move of sample array (Performance) // #TODO(Casey): integrate libsndfile as primary choice //DBG("Reading wav to buffer"); audioFormatReader->read(&audioBuffer, 0, numSamples, 0, true, true); //DBG("Copying buffer samples to audioData"); for (size_t i = 0; i < numSamples; ++i) { //DBG("On sample " + String(i) + " of " + String(numSamples)); for (size_t currChannel = 0; currChannel < numChannels; ++currChannel) { audioData.setSampleByFrame(i, currChannel, audioBuffer.getSample(currChannel, i)); } //audioData.setSampleByFrame(i, 1, audioBuffer.getSample(1, i)); } //DBG("Detecting key..."); static KeyFinder::KeyFinder keyFinder; KeyFinder::key_t key = keyFinder.keyOfAudio(audioData); //KeyFinder::key_t key = KeyFinder::key_t::C_MAJOR; fileToAnalyze->setDetectedKey(key); String foundKey(fileToAnalyze->getDetectedKeyAsString()); DBG("Detected key in analyzeAudioFiles: " + foundKey); }
KeyFinderResultWrapper keyDetectionProcess(const AsyncFileObject& object){ KeyFinderResultWrapper result; result.batchRow = object.batchRow; // initialise stream and decode file into it. KeyFinder::AudioData* audio = NULL; AudioFileDecoder* decoder = NULL; try{ decoder = AudioFileDecoder::getDecoder(); }catch(KeyFinder::Exception& e){ delete decoder; result.errorMessage = QString(e.what().c_str()); return result; } try{ audio = decoder->decodeFile(object.filePath); delete decoder; }catch(KeyFinder::Exception& e){ delete audio; delete decoder; result.errorMessage = QString(e.what().c_str()); return result; } // make audio stream monaural ahead of downsample to reduce load audio->reduceToMono(); // downsample if necessary if(object.prefs.getDFactor() > 1){ Downsampler* ds = Downsampler::getDownsampler(object.prefs.getDFactor(),audio->getFrameRate(),object.prefs.getLastFreq()); try{ audio = ds->downsample(audio,object.prefs.getDFactor()); }catch(KeyFinder::Exception& e){ delete audio; delete ds; result.errorMessage = QString(e.what().c_str()); return result; } delete ds; } KeyFinder::KeyFinder* kf = LibKeyFinderSingleton::getInstance()->getKeyFinder(); result.core = kf->findKey(*audio, object.prefs.core); delete audio; return result; }
KeyFinderResultWrapper keyDetectionProcess(const AsyncFileObject& object) { KeyFinderResultWrapper result; result.batchRow = object.batchRow; AudioFileDecoder* decoder = NULL; try { decoder = new AudioFileDecoder(object.filePath, object.prefs.getMaxDuration()); } catch (std::exception& e) { delete decoder; result.errorMessage = QString(e.what()); return result; } catch (...) { delete decoder; result.errorMessage = "Unknown exception initialising decoder"; return result; } KeyFinder::Workspace workspace; static KeyFinder::KeyFinder kf; try { while (true) { KeyFinder::AudioData* tempAudio = decoder->decodeNextAudioPacket(); if (tempAudio == NULL) break; kf.progressiveChromagram(*tempAudio, workspace); delete tempAudio; } delete decoder; decoder = NULL; kf.finalChromagram(workspace); result.fullChromagram = KeyFinder::Chromagram(*workspace.chromagram); result.core = kf.keyOfChromagram(workspace); } catch (std::exception& e) { if (decoder != NULL) delete decoder; result.errorMessage = QString(e.what()); return result; } catch (...) { if (decoder != NULL) { delete decoder; result.errorMessage = "Unknown exception while decoding"; } else { result.errorMessage = "Unknown exception while analysing"; } return result; } return result; }
KeyFinderResultWrapper keyDetectionProcess(const AsyncFileObject& object) { KeyFinderResultWrapper result; result.batchRow = object.batchRow; AudioFileDecoder* decoder = NULL; try { decoder = new AudioFileDecoder(object.filePath, object.prefs.getMaxDuration()); } catch (std::exception& e) { delete decoder; result.errorMessage = QString(e.what()); return result; } catch (...) { delete decoder; result.errorMessage = "Unknown exception initialising decoder"; return result; } KeyFinder::Workspace workspace; static KeyFinder::KeyFinder kf; try { while (true) { KeyFinder::AudioData* tempAudio = decoder->decodeNextAudioPacket(); if (tempAudio == NULL) break; kf.progressiveChromagram(*tempAudio, workspace, object.prefs.core); delete tempAudio; } delete decoder; decoder = NULL; kf.finalChromagram(workspace, object.prefs.core); result.fullChromagram = KeyFinder::Chromagram(*workspace.chromagram); result.core = kf.keyOfChromagram(workspace, object.prefs.core); result.oneOctaveChromagram = result.fullChromagram; result.oneOctaveChromagram.reduceToOneOctave(); } catch (std::exception& e) { if (decoder != NULL) delete decoder; result.errorMessage = QString(e.what()); return result; } catch (...) { if (decoder != NULL) { delete decoder; result.errorMessage = "Unknown exception while decoding"; } else { result.errorMessage = "Unknown exception while analysing"; } return result; } for (unsigned int i = 0; i < result.core.segments.size(); i++) { qDebug( "Chroma vector for segment %d of file %s: [%.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f, %.0f]", i, object.filePath.toUtf8().constData(), result.core.segments[i].chromaVector[0], result.core.segments[i].chromaVector[1], result.core.segments[i].chromaVector[2], result.core.segments[i].chromaVector[3], result.core.segments[i].chromaVector[4], result.core.segments[i].chromaVector[5], result.core.segments[i].chromaVector[6], result.core.segments[i].chromaVector[7], result.core.segments[i].chromaVector[8], result.core.segments[i].chromaVector[9], result.core.segments[i].chromaVector[10], result.core.segments[i].chromaVector[11] ); } return result; }
const char* kfinder_get_key(short signed int *samples, unsigned int nb_samples, short unsigned int frame_rate, short unsigned int nb_channels) { // Check input parameter. if ((samples == NULL) || (nb_samples == 0) || (frame_rate == 0) || (nb_channels == 0)) { return ""; } // Build the main computing object. KeyFinder::KeyFinder k; // Build an empty audio object KeyFinder::AudioData a; // Prepare the object for your audio stream a.setFrameRate(frame_rate); a.setChannels(nb_channels); a.addToSampleCount(nb_samples); // Copy your audio into the object (as float). for (unsigned int i = 0; i < nb_samples; i++) { a.setSample(i, (float)samples[i]); } // Run the analysis KeyFinder::key_t r; try { r = k.keyOfAudio(a); } catch(const std::exception& e) { cerr << "libKeyFinder: exception: " << e.what() << endl; return ""; } catch(...) { cerr << "libKeyFinder: unknown exception" << endl; return ""; } // And do something with the result! switch(r) { case KeyFinder::A_MAJOR: return "AM"; case KeyFinder::A_MINOR: return "Am"; case KeyFinder::B_FLAT_MAJOR: return "BbM"; case KeyFinder::B_FLAT_MINOR: return "Bbm"; case KeyFinder::B_MAJOR: return "BM"; case KeyFinder::B_MINOR: return "Bm"; case KeyFinder::C_MAJOR: return "CM"; case KeyFinder::C_MINOR: return "Cm"; case KeyFinder::D_FLAT_MAJOR: return "DbM"; case KeyFinder::D_FLAT_MINOR: return "Dbm"; case KeyFinder::D_MAJOR: return "DM"; case KeyFinder::D_MINOR: return "Dm"; case KeyFinder::E_FLAT_MAJOR: return "EbM"; case KeyFinder::E_FLAT_MINOR: return "Ebm"; case KeyFinder::E_MAJOR: return "EM"; case KeyFinder::E_MINOR: return "Em"; case KeyFinder::F_MAJOR: return "FM"; case KeyFinder::F_MINOR: return "Fm"; case KeyFinder::G_FLAT_MAJOR: return "GbM"; case KeyFinder::G_FLAT_MINOR: return "Gbm"; case KeyFinder::G_MAJOR: return "GM"; case KeyFinder::G_MINOR: return "Gm"; case KeyFinder::A_FLAT_MAJOR: return "AbM"; case KeyFinder::A_FLAT_MINOR: return "Abm"; case KeyFinder::SILENCE: return ""; default: return ""; } }