func Xcorr(x, y []float64, maxDelay int) (corr []float64) {
	N := len(x)
	corr = make([]float64, maxDelay)
	for k := 0; k < maxDelay; k++ {
		for n := 0; n < N-k; n++ {
			corr[k] += x[n] * y[n+k]
		}
		corr[k] /= float64(N)
	}
	return
}
/*
Xcorr returns the cross correlation of x with y for maxDelay.
package godsp
import (
	"bufio"
	"bytes"
	"fmt"
	"io/ioutil"
	"math"
	"strconv"
	"strings"
	myioutil "github.com/goccmack/goutil/ioutil"
)
func Abs(x []float64) []float64 {
	x1 := make([]float64, len(x))
	for i, f := range x {
		x1[i] = math.Abs(f)
	}
	return x1
}
func AbsInt(x []int) []int {
	x1 := make([]int, len(x))
	for i, e := range x {
		if e < 0 {
			x1[i] = -e
		} else {
			x1[i] = e
		}
	}
	return x1
}
func AbsAll(X [][]float64) [][]float64 {
	x1 := make([][]float64, len(X))
	for i, x := range X {
		x1[i] = Abs(x)
	}
	return x1
}
func Average(x []float64) float64 {
	return Sum(x) / float64(len(x))
}
func DivS(x []float64, s float64) []float64 {
	y := make([]float64, len(x))
	for i := range x {
		y[i] = x[i] / s
	}
	return y
}
func DownSampleAll(xs [][]float64) [][]float64 {
	N := len(xs[0])
	for _, x := range xs {
		if len(x) < N {
			N = len(x)
		}
	}
	ys := make([][]float64, len(xs))
	for i, x := range xs {
		ys[i] = DownSample(x, len(x)/N)
	}
	return ys
}
func DownSample(x []float64, n int) []float64 {
	if len(x)%n != 0 {
		panic(fmt.Sprintf("len(x) (%d) is not an integer multiple of n (%d)", len(x), n))
	}
	x1 := make([]float64, len(x)/n)
	for i, j := 0, 0; j < len(x1); i, j = i+n, j+1 {
		x1[j] = x[i]
	}
	return x1
}
func FindMax(x []float64) (value float64, index int) {
	value, index = x[0], 0
	for i := 1; i < len(x)-1; i++ {
		if x[i] > value {
			value, index = x[i], i
		}
	}
	return
}
func FindMaxI(x []int) (value int, index int) {
	value, index = x[0], 0
	for i := 1; i < len(x)-1; i++ {
		if x[i] > value {
			value, index = x[i], i
		}
	}
	return
}
func FindMin(x []float64) (value float64, index int) {
	value, index = x[0], 0
	for i := 1; i < len(x)-1; i++ {
		if x[i] < value {
			value, index = x[i], i
		}
	}
	return
}
func Float32ToFloat64(x []float32) []float64 {
	y := make([]float64, len(x))
	for i, f := range x {
		y[i] = float64(f)
	}
	return y
}
func IsPowerOf2(x int) bool {
	return (x != 0) && ((x & (x - 1)) == 0)
}
func LoadFloats(fname string) []float64 {
	data, err := ioutil.ReadFile(fname)
	if err != nil {
		panic(err)
	}
	rdr := bufio.NewReader(bytes.NewBuffer(data))
	x := make([]float64, 0, 1024)
	for s, err := rdr.ReadString('\n'); err == nil; s, err = rdr.ReadString('\n') {
		f, err := strconv.ParseFloat(strings.TrimSuffix(s, "\n"), 64)
		if err != nil {
			panic(err)
		}
		x = append(x, f)
	}
	return x
}
func Log2(n int) int {
	return int(math.Log2(float64(n)))
}
func LowpassFilterAll(xs [][]float64, alpha float64) [][]float64 {
	ys := make([][]float64, len(xs))
	for i, x := range xs {
		ys[i] = LowpassFilter(x, alpha)
	}
	return ys
}
func LowpassFilter(x []float64, alpha float64) []float64 {
	y := make([]float64, len(x))
	y[0] = alpha * x[0]
	for i := 1; i < len(x); i++ {
		y[i] = y[i-1] + alpha*(x[i]-y[i-1])
	}
	return y
}
func Max(x []float64) float64 {
	max := x[0]
	for _, f := range x {
		if f > max {
			max = f
		}
	}
	return max
}
func MaxInt(x []int) int {
	max := x[0]
	for _, f := range x {
		if f > max {
			max = f
		}
	}
	return max
}
func MovAvg(x []float64, w int) []float64 {
	y := make([]float64, len(x))
	for i := w; i < len(x)-w; i++ {
		y[i] = Sum(x[i-w:i+w]) / float64(2*w)
	}
	return y
}
func Multiplex(channels [][]float64) []float64 {
	numChans := len(channels)
	chanLen := len(channels[0])
	buf := make([]float64, numChans*chanLen)
	for i := 0; i < chanLen; i++ {
		k := i * numChans
		for j := 0; j < numChans; j++ {
			buf[k+j] = channels[j][i]
		}
	}
	return buf
}
func Normalise(x []float64) []float64 {
	x1 := make([]float64, len(x))
	sum := Max(x)
	for i, f := range x {
		x1[i] = f / sum
	}
	return x1
}
func NormaliseAll(xs [][]float64) [][]float64 {
	x1 := make([][]float64, len(xs))
	for i, x := range xs {
		x1[i] = Normalise(x)
	}
	return x1
}
func Pow2(x int) int {
	if x < 0 {
		panic(fmt.Sprintf("X = %d", x))
	}
	pw := 1
	for i := 1; i <= x; i++ {
		pw *= 2
	}
	return pw
}
func Range(n int) []int {
	rng := make([]int, n)
	for i := range rng {
		rng[i] = i
	}
	return rng
}
func RemoveAvgAllZ(xs [][]float64) [][]float64 {
	xs1 := make([][]float64, len(xs))
	for i, x := range xs {
		xs1[i] = RemoveAvg(x)
	}
	return xs1
}
func RemoveAvg(x []float64) []float64 {
	x1 := make([]float64, len(x))
	avg := Sum(x) / float64(len(x))
	for i, f := range x {
		x1[i] = f - avg
		if x1[i] < 0 {
			x1[i] = 0
		}
	}
	return x1
}
func Smooth(x []float64, wdw int) {
	for i := 0; i < wdw; i++ {
		x[i] = 0
	}
	for i := wdw; i < len(x)-wdw; i++ {
		x[i] = Sum(x[i-wdw:i+wdw]) / float64((2 * wdw))
	}
}
func Sub(x, y []float64) []float64 {
	if len(x) != len(y) {
		panic("len(x) != len(y)")
	}
	x1 := make([]float64, len(x))
	for i := range x {
		x1[i] = x[i] - y[i]
	}
	return x1
}
func Sum(x []float64) float64 {
	sum := 0.0
	for _, f := range x {
		sum += f
	}
	return sum
}
func SumVectors(X [][]float64) []float64 {
	N := len(X[0])
	for i, x := range X {
		if len(x) != N {
			panic(fmt.Sprintf("N=%d but len(X[%d]=%d", N, i, len(x)))
		}
	}
	sum := make([]float64, N)
	for i := 0; i < N; i++ {
		for j := range X {
			sum[i] += X[j][i]
		}
	}
	return sum
}
func ToFloat(x []int) []float64 {
	y := make([]float64, len(x))
	for i, e := range x {
		y[i] = float64(e) / float64(math.MaxInt64)
	}
	return y
}
func ToInt(x []float64, bitsPerSample int) []int {
	y := make([]int, len(x))
	if bitsPerSample != 8 && bitsPerSample != 16 && bitsPerSample != 32 {
		panic(fmt.Sprintf("Invalid bitsPerSample %d", bitsPerSample))
	}
	max := float64(int(1)<<bitsPerSample - 1)
	for i, f := range x {
		y[i] = int(f * max)
	}
	return y
}
func ToIntS(x float64, bitsPerSample int) int {
	max := float64(int(1)<<bitsPerSample - 1)
	return int(x * max)
}
func findLocalMax(x []float64, from, wdw, step int) (maxI, slopeEnd int) {
	i, slp := from+wdw, 0
	for slp >= 0 && i < len(x)-wdw {
		slp = slope(x[i : i+wdw])
		i += step
	}
	_, maxI = FindMax(x[from:i])
	maxI += from
	slopeEnd = i
	return
}
func findLocalMin(x []float64, from, wdw, step int) (minI, slopeEnd int) {
	i, slp := from+wdw, 0
	for slp <= 0 && i < len(x)-wdw {
		slp = slope(x[i : i+wdw])
		i += step
	}
	_, minI = FindMin(x[from:i])
	minI += from
	slopeEnd = i
	return
}
func findNon0Slope(x []float64, from, wdw int) (slp, end int) {
	for i := from; i < len(x)-wdw; i++ {
		slp := slope(x[i : i+wdw])
		if slp != 0 {
			return slp, i
		}
	}
	return 0, len(x)
}
func slope(x []float64) int {
	end := len(x) - 1
	if x[0] < x[end] {
		return -1
	}
	if x[0] == x[end] {
		return 0
	}
	return 1
}
func ivecContain(x []int, v int) bool {
	for _, v1 := range x {
		if v1 == v {
			return true
		}
	}
	return false
}
func WriteAllDataFile(xs [][]float64, fname string) {
	for i, xs := range xs {
		WriteDataFile(xs, fmt.Sprintf("%s_%d", fname, i))
	}
}
func WriteDataFile(x []float64, fname string) {
	buf := new(bytes.Buffer)
	for _, f := range x {
		fmt.Fprintf(buf, "%f\n", f)
	}
	if err := myioutil.WriteFile(fname+".txt", buf.Bytes()); err != nil {
		panic(err)
	}
}
func WriteIntDataFile(x []int, fname string) {
	buf := new(bytes.Buffer)
	for _, f := range x {
		fmt.Fprintf(buf, "%d\n", f)
	}
	if err := myioutil.WriteFile(fname+".txt", buf.Bytes()); err != nil {
		panic(err)
	}
}
func WriteIntMatrixDataFile(x [][]int, fname string) {
	buf := new(bytes.Buffer)
	for _, row := range x {
		for i, col := range row {
			if i > 0 {
				fmt.Fprint(buf, ",")
			}
			fmt.Fprintf(buf, "%d", col)
		}
		fmt.Fprintln(buf)
	}
	if err := myioutil.WriteFile(fname+".csv", buf.Bytes()); err != nil {
		panic(err)
	}
}