func (vis *basic) Push(samples []float32) { po := &spectral.PwelchOptions{ NFFT: 64, } powers, _ := spectral.Pwelch(float32To64(samples), vis.freq, po) vis.Set(float64ToInt(powers, 10)) }
func findNextCandidate(samples []float64, sampleRate, min, max float64, c0 int) int { sr := int(sampleRate) for c := 0; c+sr < len(samples); c += sr { pxx, freqs := spectral.Pwelch(samples[c:c+sr], sampleRate, pwOpts) globalPeakPower, globalPeakFreq := findPeak(pxx, freqs, 32, 880) localPeakPower, localPeakFreq := findPeak(pxx, freqs, min, max) if !dsputils.Float64Equal(globalPeakPower, localPeakPower) { if globalPeakFreq < localPeakFreq || !areHarmonic(globalPeakFreq, localPeakFreq) { continue } } if localPeakPower < purrMinPower { continue } fmt.Printf("Candidate at %v (local peak: %f Hz (%.2f), global peak: %f Hz (%.2f))\n", fmtSeconds(float64(c+c0)/sampleRate), localPeakFreq, localPeakPower, globalPeakFreq, globalPeakPower) findRepeats(samples[c:], sampleRate, localPeakFreq, true, true) return c + c0 } return -1 }
func findRepeats(samples []float64, sampleRate, baseFreq float64, lookBelow, lookAbove bool) { if !lookBelow && !lookAbove { fmt.Println("findRepeats: both lookBelow and lookAbove are false.") } win0 := int(2.9 * sampleRate) if win0 >= len(samples) { fmt.Println("findRepeats: reached the end of the samples.") return } win1 := minInt(int(6.1*sampleRate), len(samples)) if win1-win0 < int(sampleRate) { fmt.Println("findRepeats: reached near the end of the samples.") return } freqBelow := baseFreq / 1.5 freqAbove := baseFreq * 1.5 pxx, freqs := spectral.Pwelch(samples[win0:win1], sampleRate, pwOpts) peakPowerBelow, peakFreqBelow := findPeak(pxx, freqs, freqBelow/1.1, freqBelow*1.1) peakPowerAbove, peakFreqAbove := findPeak(pxx, freqs, freqAbove/1.1, freqAbove*1.1) var repeatPower float64 = 0 var repeatFreq float64 = 0 foundBelow := false foundAbove := false if lookBelow { if lookAbove { if peakPowerBelow > peakPowerAbove { repeatPower = peakPowerBelow repeatFreq = peakFreqBelow foundBelow = true } else { repeatPower = peakPowerAbove repeatFreq = peakFreqAbove foundAbove = true } } else { repeatPower = peakPowerBelow repeatFreq = peakFreqBelow foundBelow = true } } else { repeatPower = peakPowerAbove repeatFreq = peakFreqAbove foundAbove = true } if repeatPower >= purrMinPower { fmt.Printf("Repeat candidate: %f Hz (%.2f)\n", repeatFreq, repeatPower) findRepeats(samples[int(4*sampleRate):], sampleRate, baseFreq, lookBelow && foundBelow, lookAbove && foundAbove) } else { fmt.Println("No further repeat candidates found.") } }
func getHits() ([]hit, error) { w, err := wav.New(os.Stdin) if err != nil { return nil, err } log.Printf("format: %d, channels: %d, sample rate: %d, byte rate: %d, bps: %d, samples: %d, duration: %v\n", w.Header.AudioFormat, w.Header.NumChannels, w.Header.SampleRate, w.Header.ByteRate, w.Header.BitsPerSample, w.Samples, w.Duration) winSize := int(w.Header.SampleRate * uint32(w.Header.NumChannels) / winDenom) cursor := 0 hits := make([]hit, 0) for { rawSamples, err := w.ReadFloats(winSize) if err != nil { if err == io.EOF || err == io.ErrUnexpectedEOF { break } else { return nil, err } } if len(rawSamples) < winSize { break } samples := flattenChannels(int(w.Header.NumChannels), rawSamples) pxx, freqs := spectral.Pwelch(samples, float64(w.Header.SampleRate), &spectral.PwelchOptions{NFFT: 16384, Scale_off: true}) maxPower, maxPowerFreq := findPeak(pxx, freqs, 32, 880) pMaxPower, pMaxPowerFreq := findPeak(pxx, freqs, 55, 170) harmonic := true if !dsputils.Float64Equal(maxPowerFreq, pMaxPowerFreq) { if maxPowerFreq < pMaxPowerFreq || !areHarmonic(maxPower, pMaxPower) { fmt.Printf("t = %v: %f !~ %f\n", fmtSeconds(float64(cursor)/float64(w.Header.SampleRate)), maxPowerFreq, pMaxPowerFreq) harmonic = false } } v1Freq := pMaxPowerFreq * 1.1 v1Pow := powerAtFreq(v1Freq, pxx, freqs) p1Freq := pMaxPowerFreq * 1.2 p1Pow := powerAtFreq(p1Freq, pxx, freqs) v2Freq := pMaxPowerFreq * 1.3 v2Pow := powerAtFreq(v2Freq, pxx, freqs) p2Freq := pMaxPowerFreq * 1.4 p2Pow := powerAtFreq(p2Freq, pxx, freqs) if harmonic && pMaxPower >= 0.00 && pMaxPowerFreq >= 55.0 && pMaxPowerFreq <= 160.0 && v1Pow < p1Pow && v2Pow < p2Pow { hits = append(hits, hit{t: float64(cursor) / float64(w.Header.SampleRate), freq: pMaxPowerFreq, pow: pMaxPower}) } cursor += len(rawSamples) / int(w.Header.NumChannels) } return hits, nil }