// Deduce m_FromFrequency from the samples at the beginning of // the selection. Then set some other params accordingly. void EffectChangePitch::DeduceFrequencies() { // As a neat trick, attempt to get the frequency of the note at the // beginning of the selection. SelectedTrackListOfKindIterator iter(Track::Wave, inputTracks()); WaveTrack *track = (WaveTrack *) iter.First(); if (track) { double rate = track->GetRate(); // Auto-size window -- high sample rates require larger windowSize. // Aim for around 2048 samples at 44.1 kHz (good down to about 100 Hz). // To detect single notes, analysis period should be about 0.2 seconds. // windowSize must be a power of 2. const size_t windowSize = // windowSize < 256 too inaccurate std::max(256, wxRound(pow(2.0, floor((log(rate / 20.0)/log(2.0)) + 0.5)))); // we want about 0.2 seconds to catch the first note. // number of windows rounded to nearest integer >= 1. const unsigned numWindows = std::max(1, wxRound((double)(rate / (5.0f * windowSize)))); double trackStart = track->GetStartTime(); double t0 = mT0 < trackStart? trackStart: mT0; auto start = track->TimeToLongSamples(t0); auto analyzeSize = windowSize * numWindows; Floats buffer{ analyzeSize }; Floats freq{ windowSize / 2 }; Floats freqa{ windowSize / 2, true }; track->Get((samplePtr) buffer.get(), floatSample, start, analyzeSize); for(unsigned i = 0; i < numWindows; i++) { ComputeSpectrum(buffer.get() + i * windowSize, windowSize, windowSize, rate, freq.get(), true); for(size_t j = 0; j < windowSize / 2; j++) freqa[j] += freq[j]; } size_t argmax = 0; for(size_t j = 1; j < windowSize / 2; j++) if (freqa[j] > freqa[argmax]) argmax = j; auto lag = (windowSize / 2 - 1) - argmax; m_dStartFrequency = rate / lag; } double dFromMIDInote = FreqToMIDInote(m_dStartFrequency); double dToMIDInote = dFromMIDInote + m_dSemitonesChange; m_nFromPitch = PitchIndex(dFromMIDInote); m_nFromOctave = PitchOctave(dFromMIDInote); m_nToPitch = PitchIndex(dToMIDInote); m_nToOctave = PitchOctave(dToMIDInote); m_FromFrequency = m_dStartFrequency; Calc_PercentChange(); Calc_ToFrequency(); }
void EffectChangePitch::OnText_FromFrequency(wxCommandEvent & WXUNUSED(evt)) { if (m_bLoopDetect) return; // Empty string causes unpredictable results with ToDouble() and later calculations. // Non-positive frequency makes no sense, but user might still be editing, // so it's not an error, but we do not want to update the values/controls. if (!m_pTextCtrl_FromFrequency->GetValidator()->TransferFromWindow()) { EnableApply(false); return; } double newFromMIDInote = FreqToMIDInote(m_FromFrequency); m_nFromPitch = PitchIndex(newFromMIDInote); m_nFromOctave = PitchOctave(newFromMIDInote); Calc_ToPitch(); Calc_ToFrequency(); Calc_ToOctave(); // Call after Calc_ToFrequency(). m_bLoopDetect = true; { Update_Choice_FromPitch(); Update_Spin_FromOctave(); Update_Choice_ToPitch(); Update_Spin_ToOctave(); Update_Text_ToFrequency(); } m_bLoopDetect = false; // Success. Make sure OK and Preview are enabled, in case we disabled above during editing. EnableApply(true); }
void EffectChangePitch::Calc_ToOctave() { m_nToOctave = PitchOctave(FreqToMIDInote(m_ToFrequency)); }
// Deduce m_FromFrequency from the samples at the beginning of // the selection. Then set some other params accordingly. void EffectChangePitch::DeduceFrequencies() { // As a neat trick, attempt to get the frequency of the note at the // beginning of the selection. SelectedTrackListOfKindIterator iter(Track::Wave, mTracks); WaveTrack *track = (WaveTrack *) iter.First(); if (track) { double rate = track->GetRate(); // Auto-size window -- high sample rates require larger windowSize. // Aim for around 2048 samples at 44.1 kHz (good down to about 100 Hz). // To detect single notes, analysis period should be about 0.2 seconds. // windowSize must be a power of 2. int windowSize = wxRound(pow(2.0, floor((log(rate / 20.0)/log(2.0)) + 0.5))); // windowSize < 256 too inaccurate windowSize = (windowSize > 256)? windowSize : 256; // we want about 0.2 seconds to catch the first note. // number of windows rounded to nearest integer >= 1. int numWindows = wxRound((double)(rate / (5.0f * windowSize))); numWindows = (numWindows > 0)? numWindows : 1; double trackStart = track->GetStartTime(); double t0 = mT0 < trackStart? trackStart: mT0; sampleCount start = track->TimeToLongSamples(t0); int analyzeSize = windowSize * numWindows; float * buffer; buffer = new float[analyzeSize]; float * freq; freq = new float[windowSize/2]; float * freqa; freqa = new float[windowSize/2]; int i, j, argmax; int lag; for(j=0; j<windowSize/2; j++) freqa[j] = 0; track->Get((samplePtr) buffer, floatSample, start, analyzeSize); for(i=0; i<numWindows; i++) { ComputeSpectrum(buffer+i*windowSize, windowSize, windowSize, rate, freq, true); for(j=0; j<windowSize/2; j++) freqa[j] += freq[j]; } argmax=0; for(j=1; j<windowSize/2; j++) if (freqa[j] > freqa[argmax]) argmax = j; delete [] freq; delete [] freqa; delete [] buffer; lag = (windowSize/2 - 1) - argmax; m_dStartFrequency = rate / lag; } double dFromMIDInote = FreqToMIDInote(m_dStartFrequency); double dToMIDInote = dFromMIDInote + m_dSemitonesChange; m_nFromPitch = PitchIndex(dFromMIDInote); m_nFromOctave = PitchOctave(dFromMIDInote); m_nToPitch = PitchIndex(dToMIDInote); m_nToOctave = PitchOctave(dToMIDInote); m_FromFrequency = m_dStartFrequency; Calc_PercentChange(); Calc_ToFrequency(); }