// Copyright 2004-07 "Gilles Degottex" // This file is part of "Music" // "Music" is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2.1 of the License, or // (at your option) any later version. // // "Music" is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "FreqAnalysis.h" #include #include using namespace std; using namespace Math; #include "Music.h" #include namespace Music { double PeakRefinementLogParabola(const vector > spectrum, int peak_index) { assert(peak_index>0 && peak_index0 && is_peak(spectrum, peak_index-1)) peak_index--; } double a,b,c,xapex,yapex; FitParabola(peak_index-1, log(mod(spectrum[peak_index-1])+numeric_limits::min()), peak_index, log(mod(spectrum[peak_index])+numeric_limits::min()), peak_index+1, log(mod(spectrum[peak_index+1])+numeric_limits::min()), a, b, c, xapex, yapex); return xapex; } /*! * M. Abe and J. O. Smith III * “Design Criteria for Simple Sinusoidal Parameter Estimation based on Quadratic * Interpolation of FFT Magnitude Peaks AM/FM Rate Estimation and Bias Correction * for Time-Varying Sinusoidal Modeling,” * Convention Paper Audio Engineering Society, * Dept. of Music, Stanford University, August, (2004). */ double PeakRefinementLogParabolaUnbiased(const vector > spectrum, int peak_index, double zp) { double f = PeakRefinementLogParabola(spectrum, peak_index); double df = f - peak_index; double c0 = 0.247560; // hann coefs double c1 = 0.084372; double xi_zp = c0/(zp*zp) + c1/(zp*zp*zp*zp); double df2 = xi_zp*(df-0.5)*(df+0.5)*df; // double c2 = −0.090608; // double c3 = −0.055781; // double nu_zp = c2/(zp*zp*zp*zp) + c3/(zp*zp*zp*zp*zp*zp); // double da = nu_zp*df*df; return f+df2; } vector GetHarmonicStruct(const vector >& spectrum, double approx_f0, int nb_harm, double used_zp, double offset_tresh) { double approx_f0_rel = approx_f0*spectrum.size()/double(GetSamplingRate()); assert(approx_f0_rel>1 && approx_f0_rel<=spectrum.size()/2-1); vector harms; for(int h=1; h<=nb_harm && int(h*approx_f0_rel)llimit) cl_is_peak = is_peak(spectrum, --cl); int cr = c; bool cr_is_peak = false; while(!cr_is_peak && cr+10) { Harmonic harm; harm.mod = mod(spectrum[peak_index]); harm.freq = PeakRefinementLogParabolaUnbiased(spectrum, peak_index, used_zp)*double(GetSamplingRate())/spectrum.size(); harm.harm_number = h; harms.push_back(harm); } } return harms; } double FundFreqRefinementOfHarmonicStruct(const vector >& spectrum, double approx_f0, int nb_harm, double used_zp) { double approx_f0_rel = approx_f0*spectrum.size()/double(GetSamplingRate()); assert(approx_f0_rel>1 && approx_f0_rel<=spectrum.size()/2-1); vector harms = GetHarmonicStruct(spectrum, approx_f0, nb_harm, used_zp, 0.2); if(harms.empty()) return 0.0; double sum_f0 = 0.0; for(size_t i=0; i& buff) { for(size_t h=0; happly(buff); m_harmonics[h] = m_convolutions[h]->m_value; m_components[h] = mod(m_harmonics[h]); } } SingleResConvolutionTransform::~SingleResConvolutionTransform() { for(size_t i=0; i& buff) { // cerr << "NeuralNetGaussAlgo::apply " << m_components_treshold << endl; m_components_max = 0.0; for(size_t h=0; happly(buff); m_harmonics[h] = m_convolutions[h]->m_value; m_components[h] = mod(m_harmonics[h]); m_components_max = max(m_components_max, m_components[h]); } m_first_fond = UNDEFINED_SEMITONE; for(size_t h=0; hm_components_treshold && m_first_fond==UNDEFINED_SEMITONE) { m_first_fond = h; m_is_fondamental[h] = true; } } } NeuralNetGaussAlgo::~NeuralNetGaussAlgo() { } // MonophonicAlgo MonophonicAlgo::MonophonicAlgo(double latency_factor, double gauss_factor) : SingleResConvolutionTransform(latency_factor, gauss_factor) { init(); } int MonophonicAlgo::getSampleAlgoLatency() const { return m_convolutions[0]->size(); } void MonophonicAlgo::apply(const deque& buff) { for(size_t h=0; h getComponentsTreshold()) { // m_components[h] = min(formant_mod, max_value); m_components[h] = formant_mod; m_components_max = max(m_components_max, m_components[h]); m_first_fond = h; } // else m_components[h] = 0.0; } else m_components[h] = 0.0; } for(;h>=0; h--) m_components[h] = 0.0; // smash all components below a treshold of the max component // for(size_t h=0; h 0.0) // m_first_fond = h; // correction: the note is the nearest maximum of m_note // if(m_first_fond!=-1) // while(m_first_fond+1 m_components[m_first_fond]) // m_first_fond++; // cerr << "m_first_fond=" << m_first_fond << endl; } TwoVoiceMHT::TwoVoiceMHT(double AFreq, int dataBySecond, double rep, double win_factor, int minHT, int maxHT) : m_mht(new MHT(AFreq, dataBySecond, rep, win_factor, minHT, maxHT)) , m_last_sol(m_mht->m_components.size()) { int nbHT = maxHT - minHT + 1; m_components.resize(nbHT); for(size_t i=0; i(0.0,0.0); } void TwoVoiceMHT::apply(deque& buff) { // cout << "TwoVoiceMHT::apply" << endl; m_mht->apply(buff); // double earingTreshold = 0.05; // double modArgTreshold = 0.2; // double modModTreshold = 0.2; // ComputeDiffs(m_mht->m_components, fp, argpfp, modfp); // int count = 0; for(size_t h=0;hm_components[h]!=complex(0.0,0.0) && count<2) { m_components[h] = m_mht->m_components[h]; // count++; // if(fabs(argpfp[0][h])>modArgTreshold) count++; } // else m_components[h] = complex(0.0,0.0); } // m_last_sol = m_mht->m_components; } TwoVoiceMHT::~TwoVoiceMHT() { delete m_mht; } RemoveSyncMHT::RemoveSyncMHT(double AFreq, int dataBySecond, double rep, double win_factor, int minHT, int maxHT) : m_mht(new MHT(AFreq, dataBySecond, rep, win_factor, minHT, maxHT)) , m_last_sol(m_mht->m_components.size()) { int nbHT = maxHT - minHT + 1; m_components.resize(nbHT); for(size_t i=0; i(0.0,0.0); } void RemoveSyncMHT::apply(deque& buff) { m_mht->apply(buff); double earingTreshold = 0.05; double syncArgTreshold = 0.3; // 0.02 0.25 0.2 // double syncModTreshold = 0.2; // 0.05 0.1 0.3 double fourier_amplitude = 0.0; for(size_t h=0; hm_components.size(); h++) fourier_amplitude = max(fourier_amplitude, normm(m_mht->m_components[h])); vector notes; for(size_t h=0; hm_components.size(); h++) // for each half tone { bool is_fond = false; if(normm(m_mht->m_components[h])>earingTreshold*fourier_amplitude) // if we can ear it { is_fond = true; // search for syncronisation with each discovered fondamentals for(size_t i=0; im_convolutions[h]->m_freq/m_mht->m_convolutions[notes[i]]->m_freq; int k = int(rk+0.5); if(abs(k-rk)<0.05) // TODO // if k is nearly an integer, a potential harmonic { complex ft = m_mht->m_components[notes[i]] / normm(m_mht->m_components[notes[i]]); complex ftm1 = m_last_sol[notes[i]] / normm(m_last_sol[notes[i]]); complex rpt = m_mht->m_components[h]/pow(ft, k); complex rptm1 = m_last_sol[h]/pow(ftm1, k); // if(h==25 && k==4) // cout << abs(log(normm(rpt))-log(normm(rptm1))) << " "; // cout << k << "=(arg=" << abs(arg(rpt)-arg(rptm1)) << " mod=" << abs(log(normm(rpt))-log(normm(rptm1))) << ") "; is_fond = abs(arg(rpt)-arg(rptm1)) > syncArgTreshold; // is_fond = is_fond || abs(log(normm(rpt))-log(normm(rptm1))) > syncModTreshold; } // is_fond = false; } if(is_fond) notes.push_back(h); // it's a fondamentals } // cout << endl; if(is_fond) m_components[h] = m_mht->m_components[h]; else m_components[h] = complex(0.0,0.0); } m_last_sol = m_mht->m_sol; } RemoveSyncMHT::~RemoveSyncMHT() { delete m_mht; } #if 0 NeuralNetMHT::NeuralNetMHT(double AFreq, int dataBySecond, double rep, double win_factor, int minHT, int maxHT, const string& file_name) : m_mht(new MHT(AFreq, dataBySecond, rep, win_factor, minHT, maxHT)) , m_nn(new LayeredNeuralNet()) { m_nbHT = maxHT - minHT + 1; m_components.resize(m_nbHT); m_nn->load(file_name.c_str()); assert(m_nbHT==m_nn->getInputLayer()->getNeurons().size()); assert(m_nbHT==m_nn->getOutputLayer()->getNeurons().size()); cout << "topology: " << m_nn->getInputLayer()->getNeurons().size(); for(LayeredNeuralNet::LayerIterator it = ++(m_nn->m_layerList.begin()); it !=m_nn->m_layerList.end(); it++) cout << " => " << (*it)->getNeurons().size(); cout << " [" << m_nn->getNbWeights() << " weights]" << endl; } void NeuralNetMHT::apply(deque& buff) { // cout << "NeuralNetMHT::apply" << endl; m_mht->apply(buff); vector inputs(m_nbHT); for(int h=0; hm_components[h]); m_nn->computeOutputs(inputs); for(int h=0; h(m_nn->getOutputLayer()->getNeurons()[h].o); } NeuralNetMHT::~NeuralNetMHT() { delete m_nn; delete m_mht; } #endif #endif }