Example #1
0
// Pwelch estimates the power spectral density of x using Welch's method.
// Fs is the sampling frequency (samples per time unit) of x. Fs is used
// to calculate freqs.
// Returns the power spectral density Pxx and corresponding frequencies freqs.
// Designed to be similar to the matplotlib implementation below.
// Reference: http://matplotlib.org/api/mlab_api.html#matplotlib.mlab.psd
// See also: http://www.mathworks.com/help/signal/ref/pwelch.html
func Pwelch(x []float64, Fs float64, o *PwelchOptions) (Pxx, freqs []float64) {
	if len(x) == 0 {
		return []float64{}, []float64{}
	}

	nfft := o.NFFT
	pad := o.Pad
	noverlap := o.Noverlap
	wf := o.Window
	enable_scaling := !o.Scale_off

	if nfft == 0 {
		nfft = 256
	}

	if wf == nil {
		wf = window.Hann
	}

	if pad == 0 {
		pad = nfft
	}

	if len(x) < nfft {
		x = dsputils.ZeroPadF(x, nfft)
	}

	lp := pad/2 + 1
	var scale float64 = 2

	segs := Segment(x, nfft, noverlap)

	Pxx = make([]float64, lp)
	for _, x := range segs {
		x = dsputils.ZeroPadF(x, pad)
		window.Apply(x, wf)

		pgram := fft.FFTReal(x)

		for j := range Pxx {
			d := real(cmplx.Conj(pgram[j])*pgram[j]) / float64(len(segs))

			if j > 0 && j < lp-1 {
				d *= scale
			}

			Pxx[j] += d
		}
	}

	w := wf(nfft)
	var norm float64
	for _, x := range w {
		norm += math.Pow(x, 2)
	}

	if enable_scaling {
		norm *= Fs
	}

	for i := range Pxx {
		Pxx[i] /= norm
	}

	freqs = make([]float64, lp)
	coef := Fs / float64(pad)
	for i := range freqs {
		freqs[i] = float64(i) * coef
	}

	return
}
Example #2
0
func (self *Server) startAudio() error {
	in := make([]int32, self.Config.FftSize)
	stream, err := self.openAudioStream(in)
	if err = stream.Start(); err != nil {
		return err
	}

	go func() {
		defer stream.Close()
		defer stream.Stop()

		fftSize := self.Config.FftSize
		halfFftSize := fftSize / 2
		phaseI := make([]float64, fftSize)
		phaseQ := make([]float64, fftSize)
		complexIQ := make([]complex128, fftSize)
		fftResult := make([]float32, fftSize)
		fftCorrection := func(freq float64) float64 {
			return math.Pow(2.0, freq/41000)
		}
		fftBinBandWidth := stream.Info().SampleRate / float64(fftSize)

		for self.running {
			if err = stream.Read(); err != nil {
				log.Printf("portaudio: stream.Read() failed: %s", err)
				continue
			}

			if len(self.sessions) == 0 {
				continue
			}

			waitingClient := 0
			now := time.Now().UnixNano()
			for _, session := range self.sessions {
				if !session.initialized {
					continue
				}
				if now-session.lastTime < session.rateLimit {
					continue
				}
				waitingClient++
			}

			if waitingClient == 0 {
				continue
			}

			for i := 0; i < len(in); i += 2 {
				// left
				phaseI[i/2] = float64(in[i]) / 0x1000000
				// right
				phaseQ[i/2] = float64(in[i+1]) / 0x1000000
			}

			windowFunc := window.Hamming
			window.Apply(phaseI, windowFunc)
			window.Apply(phaseQ, windowFunc)

			for i := 0; i < fftSize; i++ {
				complexIQ[i] = complex(phaseI[i], phaseQ[i])
			}

			result := fft.FFT(complexIQ)
			// real
			for i := 0; i < halfFftSize; i++ {
				power := math.Sqrt(real(result[i])*real(result[i]) + imag(result[i])*imag(result[i]))
				fftResult[i+halfFftSize] = float32(20 * math.Log10(power*fftCorrection(float64(i)*fftBinBandWidth)))
			}
			// imag
			for i := halfFftSize; i < fftSize; i++ {
				power := math.Sqrt(real(result[i])*real(result[i]) + imag(result[i])*imag(result[i]))
				fftResult[i-halfFftSize] = float32(20 * math.Log10(power*fftCorrection(float64(fftSize-i)*fftBinBandWidth)))
			}

			self.fftResult <- fftResult
		}
	}()
	return nil
}