static void setmsounders(sounder *dst, int ndst, const msounder *src, int nsrc){ int i; msounder *list[numof(msounders)]; assert(nsrc <= numof(list)); for(i = 0; i < nsrc; i++) list[i] = &src[i]; qsort(list, numof(list), sizeof(*list), louder); for(i = 0; i < nsrc; i++){ unsigned short ld; msounder *ms = list[i]; ld = 256 * loudness(ms, g_listener); if(numof(sounders) <= list[i]->serial){ int j; for(j = 0; j < ndst; j++) if(!dst[j].priority && dst[j].vol < ld){ list[i]->serial = j; break; } } else if(ld <= 0) list[i]->serial = numof(sounders); if(list[i]->serial < numof(sounders)){ sounder *s = &dst[list[i]->serial]; s->src = list[i]->src; } /* set contents of sounder by msounder */ /*ms->src += */ } }
void KeyFinderWorkerThread::run(){ if(!haveParams){ emit failed("No parameters."); return; } // initialise stream and decode file into it AudioStream* astrm = NULL; AudioFileDecoder* dec = AudioFileDecoder::getDecoder(filePath.toUtf8().data()); try{ astrm = dec->decodeFile(filePath.toUtf8().data()); }catch(Exception){ delete astrm; delete dec; emit failed("Could not decode file."); return; } delete dec; emit decoded(); // make audio stream monaural astrm->reduceToMono(); emit madeMono(); // downsample if necessary if(prefs.getDFactor() > 1){ Downsampler* ds = Downsampler::getDownsampler(prefs.getDFactor(),astrm->getFrameRate(),prefs.getLastFreq()); try{ astrm = ds->downsample(astrm,prefs.getDFactor()); }catch(Exception){ delete astrm; delete ds; emit failed("Downsampler failed."); return; } delete ds; emit downsampled(); } // start spectrum analysis SpectrumAnalyser* sa = NULL; Chromagram* ch = NULL; sa = SpectrumAnalyserFactory::getInstance()->getSpectrumAnalyser(astrm->getFrameRate(),prefs); ch = sa->chromagram(astrm); delete astrm; // note we don't delete the spectrum analyser; it stays in the centralised factory for reuse. ch->reduceTuningBins(prefs); emit producedFullChromagram(*ch); // reduce chromagram ch->reduceToOneOctave(prefs); emit producedOneOctaveChromagram(*ch); // get energy level across track to weight segments std::vector<float> loudness(ch->getHops()); for(int h=0; h<ch->getHops(); h++) for(int b=0; b<ch->getBins(); b++) loudness[h] += ch->getMagnitude(h,b); // get harmonic change signal Segmentation* hcdf = Segmentation::getSegmentation(prefs); std::vector<double> harmonicChangeSignal = hcdf->getRateOfChange(ch,prefs); emit producedHarmonicChangeSignal(harmonicChangeSignal); // get track segmentation std::vector<int> changes = hcdf->getSegments(harmonicChangeSignal,prefs); changes.push_back(ch->getHops()); // It used to be getHops()-1. But this doesn't crash. So we like it. // batch output of keychange locations for Beatles experiment //for(int i=1; i<changes.size(); i++) // don't want the leading zero // std::cout << filePath.substr(53) << "\t" << std::fixed << std::setprecision(2) << changes[i]*(prefs.getHopSize()/(44100.0/prefs.getDFactor())) << std::endl; // end experiment output // get key estimates for segments KeyClassifier hc(prefs); std::vector<int> keys(0); std::vector<float> keyWeights(24); for(int i=0; i<(signed)changes.size()-1; i++){ std::vector<double> chroma(ch->getBins()); for(int j=changes[i]; j<changes[i+1]; j++) for(int k=0; k<ch->getBins(); k++) chroma[k] += ch->getMagnitude(j,k); int key = hc.classify(chroma); for(int j=changes[i]; j<changes[i+1]; j++){ keys.push_back(key); if(key < 24) // ignore parts that were classified as silent keyWeights[key] += loudness[j]; } } keys.push_back(keys[keys.size()-1]); // put last key on again to match length of track delete ch; emit producedKeyEstimates(keys); // get global key int mostCommonKey = 24; float mostCommonKeyWeight = 0.0; for(int i=0; i<(signed)keyWeights.size(); i++){ if(keyWeights[i] > mostCommonKeyWeight){ mostCommonKeyWeight = keyWeights[i]; mostCommonKey = i; } } emit producedGlobalKeyEstimate(mostCommonKey); return; }
static int louder(const msounder **a, const msounder **b){ double la, lb; la = loudness(*a, g_listener); lb = loudness(*b, g_listener); return la < lb ? 1 : lb < la ? -1 : 0; }
int main(int argc, char** argv) { bool validToProcess = false; bool showTime = false; bool enableOptimization = true; std::vector<int> standards; std::vector<std::string> filenames; time_t start, end; for(int i = 1; i < argc; i++) { if(strcmp(argv[i], "--progress") == 0) { showProgress = true; } if(strcmp(argv[i], "--verbose") == 0) { showProgress = true; showResults = true; } if(strcmp(argv[i], "--time") == 0) { showTime = true; } if(strcmp(argv[i], "--disable-optimization") == 0) { enableOptimization = false; } if(strncmp(argv[i], "--standard=", 11) == 0) { if(strcmp(argv[i], "--standard=cst") == 0) { standards.push_back(0); } else { if(strcmp(argv[i], "--standard=ebu") == 0) { standards.push_back(1); } else { if(strcmp(argv[i], "--standard=atsc") == 0) { standards.push_back(2); } else { std::cout << "Error: unknown standard specified in command line" << std::endl; return -100; } } } } if(standards.empty()) { standards.push_back(1); // default standard : EBU R128 } std::string ext(argv[i]); ext.erase(0, ext.length() - 5); std::string ext4 = ext; ext4.erase(0, 1); if(strcmp(ext.c_str(), ".aiff") == 0 || strcmp(ext4.c_str(), ".aif") == 0 || strcmp(ext4.c_str(), ".wav") == 0) { filenames.push_back(argv[i]); validToProcess = true; } } if(validToProcess) { for(size_t i = 0; i < filenames.size(); i++) { std::cout << filenames.at(i) << std::endl; std::string filename(filenames.at(i)); if(filename.at(filename.length() - 4) == '.') filename.erase(filename.length() - 4, 4); else if(filename.at(filename.length() - 5) == '.') filename.erase(filename.length() - 5, 5); filename.append("_PLoud.xml"); Loudness::tools::WriteXml writerXml(filename, filenames.at(i)); for(size_t j = 0; j < standards.size(); j++) { Loudness::io::SoundFile audioFile; Loudness::analyser::LoudnessLevels levels = standards.at(j) == 0 ? Loudness::analyser::LoudnessLevels::Loudness_CST_R017() : standards.at(j) == 1 ? Loudness::analyser::LoudnessLevels::Loudness_EBU_R128() : Loudness::analyser::LoudnessLevels::Loudness_ATSC_A85(); Loudness::analyser::LoudnessAnalyser loudness(levels); if(!audioFile.open_read(filenames.at(i).c_str())) { time(&start); Loudness::io::AnalyseFile analyser(loudness, audioFile); analyser.enableOptimization(enableOptimization); analyser(progress); time(&end); if(showResults) loudness.printPloudValues(); audioFile.close(); writerXml.writeResults("unknown", loudness); double dif = difftime(end, start); if(showTime) std::cout << "processing time: " << dif << " seconds." << std::endl; } } } } else { std::cout << "Loudness Analyser" << std::endl; std::cout << "Author: Marc-Antoine ARNAUD" << std::endl << std::endl; std::cout << "Common usage :" << std::endl; std::cout << "\tloudness-analyser [options] filename.ext" << std::endl << std::endl; std::cout << "Options :" << std::endl; std::cout << "\t--standard=ebu/cst/atsc : select one standard to validate the Loudness" << std::endl; std::cout << "\t\t\tebu: EBU R 128 (default)" << std::endl; std::cout << "\t\t\tcst: CST RT 017" << std::endl; std::cout << "\t\t\tatsc: ATSC A/85" << std::endl; return -1; } return 0; }