From d029038db9db3ec599b210bb78671453c005f970 Mon Sep 17 00:00:00 2001 From: ausocean-david Date: Mon, 19 Dec 2022 20:46:20 +1030 Subject: [PATCH] Audiofiltering: Interface the function with pre-existing data structures. The filters can now be generated into a filter type using a generic Generate function. This generates a filter off of the specifications within the filter struct. There is a generic Apply function which takes in a buffer of PCM data (defined in pcm.go), and outputs to a []byte. --- cmd/audiofiltering/go.mod | 5 - cmd/audiofiltering/go.sum | 2 - cmd/audiofiltering/main.go | 273 +++++-------------------------------- codec/pcm/filters.go | 198 +++++++++++++++++++++++++++ codec/pcm/pcm.go | 6 +- go.mod | 5 +- go.sum | 32 ++--- 7 files changed, 249 insertions(+), 272 deletions(-) delete mode 100644 cmd/audiofiltering/go.mod delete mode 100644 cmd/audiofiltering/go.sum create mode 100644 codec/pcm/filters.go diff --git a/cmd/audiofiltering/go.mod b/cmd/audiofiltering/go.mod deleted file mode 100644 index 65df9827..00000000 --- a/cmd/audiofiltering/go.mod +++ /dev/null @@ -1,5 +0,0 @@ -module bitbucket.org/ausocean/av/cmd/audiofiltering - -go 1.19 - -require github.com/mjibson/go-dsp v0.0.0-20180508042940-11479a337f12 diff --git a/cmd/audiofiltering/go.sum b/cmd/audiofiltering/go.sum deleted file mode 100644 index c029ccc0..00000000 --- a/cmd/audiofiltering/go.sum +++ /dev/null @@ -1,2 +0,0 @@ -github.com/mjibson/go-dsp v0.0.0-20180508042940-11479a337f12 h1:dd7vnTDfjtwCETZDrRe+GPYNLA1jBtbZeyfyE8eZCyk= -github.com/mjibson/go-dsp v0.0.0-20180508042940-11479a337f12/go.mod h1:i/KKcxEWEO8Yyl11DYafRPKOPVYTrhxiTRigjtEEXZU= diff --git a/cmd/audiofiltering/main.go b/cmd/audiofiltering/main.go index fb56e774..5ff73afe 100644 --- a/cmd/audiofiltering/main.go +++ b/cmd/audiofiltering/main.go @@ -1,259 +1,56 @@ package main -import( - "math" +import ( "fmt" + "math" "os" - "encoding/binary" - "github.com/mjibson/go-dsp/fft" - "github.com/mjibson/go-dsp/window" - "math/cmplx" "time" - "sync" + + "bitbucket.org/ausocean/av/codec/pcm" ) -// Define the constants to be used in the generation of the sound files. -const( - SampleRate float64 = 44100 - Duration = 2 - tau = math.Pi * 2 - length int = 88200 -) - -// main is a driver function which generates a sound file which contains sine waves from across the spectrum. -// Filters can then be generated and applied to the audio, in order to test their frequency response. +// main is a driver function for testing the filters defined in codec/pcm/filters.go func main() { - // Create waitgroups to ensure program runs correctly. - var wg1, wg2 sync.WaitGroup - - // Take a measurement of the starting point of the program execution to use for execution timing. + // Define start time for execution timing. start := time.Now() - - // Generate sine waves with different frequencies to test frequency response. - n := 100 - wg1.Add(n) - audio := make([][]float64, n) - for i:=0; i runMax { - runMax = math.Abs(a[i]) - } - } - - return runMax - -} - -// LowPass returns an array of coeffiecients over the given channel that can be used in a convolution with a signal to perform -// a lowpass filtering with the given cut-off frequency fc. -func LowPass (taps int, fc float64, wg *sync.WaitGroup, ch chan []float64) { - - size := taps + 1 - fd := fc/SampleRate - b := (2*math.Pi) * fd - filter := make([]float64, size) - winData := window.FlatTop(size) - for n:=0; n<(taps/2); n++ { - c := float64(n) - float64(taps)/2 - y := math.Sin(c*b) / (math.Pi * c) - filter[n] = y * winData[n] - filter[size-1-n] = filter[n] - } - filter[taps/2] = 2*fd*winData[taps/2] - ch <- filter - wg.Done() - -} - -// HighPass returns an array of coeffiecients over the given channel that can be used in a convolution with a signal to perform -// a highpass filtering with the given cut-off frequency fc. -func HighPass (taps int, fc float64, wg *sync.WaitGroup, ch chan []float64) { - - size := taps + 1 - fd := fc/SampleRate - b := (2*math.Pi) * fd - filter := make([]float64, size) - winData := window.FlatTop(size) - for n:=0; n<(taps/2); n++ { - c := float64(n) - float64(taps)/2 - y := math.Sin(c*b) / (math.Pi * c) - filter[n] = -y * winData[n] - filter[size-1-n] = filter[n] - } - filter[taps/2] = (1 - 2*fd) * winData[taps/2] - ch <- filter - wg.Done() - -} - -// BandPass returns an array of coeffiecients over the given channel that can be used in a convolution with a signal to perform -// a bandpass filtering with the given lower and upper cutoff frequencies (using the low and highpass filter functions). -func BandPass (taps int, lower, upper float64, wg *sync.WaitGroup, ch chan []float64) { - - // Create a waitgroup and channel to be used internally within the function. - var bpwg sync.WaitGroup - bpch := make(chan []float64, 2) - - // Call low and highpass filter functions. - filters := make([][]float64, 2) - bpwg.Add(2) - go LowPass(taps, upper, &bpwg, bpch) - go HighPass(taps, lower, &bpwg, bpch) - bpwg.Wait() - for i:=0; i<2; i++ { - filters[i] = <- bpch - } - - // Convolve lowpass filter with highpass filter to get bandpass filter. - bpwg.Add(1) - bpFilter := Convolve(filters[0], filters[1], &bpwg) - ch <- bpFilter - - wg.Done() - -} - - - -// Convolve returns the real convolution of the 2 given arrays. -func Convolve (x, h []float64, wg *sync.WaitGroup) []float64 { - - // Create a waitgroup to be used in goroutines called by Convolution - var convwg sync.WaitGroup - - // Compute the convolution - convLen := len(x)+len(h)-1 - y := make([]float64, convLen) - for n:=0; n= 0 && n-k < len(h) { - sum += x[k]*h[n-k] - } - } - y[n] = sum - wg.Done() - } (n, y, &convwg) - } - wg.Done() - return y - -} - -// SaveAudioData takes an input signal and filename and saves the frequency spectrum (to .txt) and the audio signal (to .bin). -func SaveAudioData (signal []float64, fileName string, wg1 *sync.WaitGroup) { - - // Compute the FFT of the signal - FFTaudio := fft.FFTReal(signal) - - // Normalise the frequency response (-1:1). - spectrum := make([]float64, len(signal)) - for i := range FFTaudio { - spectrum[i] = cmplx.Abs(FFTaudio[i])/float64(length) - } - maximum := max(spectrum) - for i := range spectrum { - spectrum[i] = spectrum[i]/maximum - } - - // Save the frequency response/spectrum. - wg1.Add(2) - go func (fileName string, length int, spectrum []float64, wg1 *sync.WaitGroup) { - file := fileName + ".txt" - f, _ := os.Create(file) - for i:=0; i 32767 { + inputAsFloat[i] -= 32768 * 2 + } + inputAsFloat[i] /= (32767) + } + + // Convolve input with filter. + var wg sync.WaitGroup + ch := make(chan []float64, 1) + wg.Add(1) + go Convolve(inputAsFloat, filter.Coeffs, &wg, ch) + wg.Wait() + convolution := <-ch + + // Convert convolution output back to bytes. + var output []byte + buf := make([]byte, 2) + for i := range convolution { + convolution[i] = convolution[i] * 32767 + if convolution[i] < 0 { + convolution[i] = convolution[i] + 32768*2 + } + binary.LittleEndian.PutUint16(buf[:], uint16(convolution[i])) + output = append(output, buf[0], buf[1]) + } + + return output + +} + +func Convolve(x, h []float64, wg *sync.WaitGroup, ch chan []float64) { + + // Create a waitgroup to be used in goroutines called by Convolution + var convwg sync.WaitGroup + + // Compute the convolution + convLen := len(x) + len(h) - 1 + y := make([]float64, convLen) + for n := 0; n < convLen; n++ { + convwg.Add(1) + go func(n int, y []float64, convwg *sync.WaitGroup) { + var sum float64 = 0 + for k := 0; k < len(x); k++ { + if n-k >= 0 && n-k < len(h) { + sum += x[k] * h[n-k] + } else if n-k < 0 { + break + } + } + y[n] = sum + convwg.Done() + }(n, y, &convwg) + } + ch <- y + close(ch) + wg.Done() +} + +// LEGACY FUNCTION FOR TESTING +// Max returns the absolute highest value in a given array. +func Max(a []float64) float64 { + + var runMax float64 = -1 + for i := range a { + if math.Abs(a[i]) > runMax { + runMax = math.Abs(a[i]) + } + } + + return runMax + +} diff --git a/codec/pcm/pcm.go b/codec/pcm/pcm.go index eb93bce7..dda88e93 100644 --- a/codec/pcm/pcm.go +++ b/codec/pcm/pcm.go @@ -73,9 +73,9 @@ func DataSize(rate, channels, bitDepth uint, period float64) int { // Resample takes Buffer c and resamples the pcm audio data to 'rate' Hz and returns a Buffer with the resampled data. // Notes: -// - Currently only downsampling is implemented and c's rate must be divisible by 'rate' or an error will occur. -// - If the number of bytes in c.Data is not divisible by the decimation factor (ratioFrom), the remaining bytes will -// not be included in the result. Eg. input of length 480002 downsampling 6:1 will result in output length 80000. +// - Currently only downsampling is implemented and c's rate must be divisible by 'rate' or an error will occur. +// - If the number of bytes in c.Data is not divisible by the decimation factor (ratioFrom), the remaining bytes will +// not be included in the result. Eg. input of length 480002 downsampling 6:1 will result in output length 80000. func Resample(c Buffer, rate uint) (Buffer, error) { if c.Format.Rate == rate { return c, nil diff --git a/go.mod b/go.mod index 8ba7ec85..7a7b1257 100644 --- a/go.mod +++ b/go.mod @@ -12,10 +12,11 @@ require ( github.com/google/go-cmp v0.4.1 github.com/kidoman/embd v0.0.0-20170508013040-d3d8c0c5c68d github.com/mewkiz/flac v1.0.5 + github.com/mjibson/go-dsp v0.0.0-20180508042940-11479a337f12 github.com/pkg/errors v0.9.1 github.com/yobert/alsa v0.0.0-20180630182551-d38d89fa843e gocv.io/x/gocv v0.29.0 - gonum.org/v1/gonum v0.9.3 - gonum.org/v1/plot v0.10.0 + gonum.org/v1/gonum v0.8.2 + gonum.org/v1/plot v0.9.0 gopkg.in/natefinch/lumberjack.v2 v2.0.0 ) diff --git a/go.sum b/go.sum index d340b280..cc2a47a7 100644 --- a/go.sum +++ b/go.sum @@ -16,13 +16,11 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWso github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/adrianmo/go-nmea v1.1.1-0.20190109062325-c448653979f7/go.mod h1:HHPxPAm2kmev+61qmkZh7xgZF/7qHtSpsWppip2Ipv8= github.com/aerth/playwav v0.0.0-20170324024803-17dfe21a406f/go.mod h1:aTANbm/GXj1ilCRMsIiSpX0i7LUkqjAPj6R0fpWbLNA= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af h1:wVe6/Ea46ZMeNkQjjBW6xcqyQA/j5e0D6GytH95g0gQ= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/ajstarks/svgo v0.0.0-20210923152817-c3b6e2f0c527 h1:NImof/JkF93OVWZY+PINgl6fPtQyF6f+hNUtZ0QZA1c= -github.com/ajstarks/svgo v0.0.0-20210923152817-c3b6e2f0c527/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/boombuler/barcode v1.0.1/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= github.com/cheekybits/is v0.0.0-20150225183255-68e9c0620927/go.mod h1:h/aW8ynjgkuj+NQRlZcDbAbM1ORAbXjXX77sX7T289U= github.com/cocoonlife/goalsa v0.0.0-20160812085113-b711ae6f3eff/go.mod h1:5aLO409bJnd+jCw0t/SB/DhHkVBhPAE31lnHJnYQxy0= github.com/cocoonlife/testify v0.0.0-20160218172820-792cc1faeb64/go.mod h1:LoCAz53rbPcqs8Da2BjB/yDy4gxMtiSQmqnYI/DGH+U= @@ -46,18 +44,13 @@ github.com/go-audio/wav v0.0.0-20181013172942-de841e69b884 h1:2TaXIaVA4ff/MHHezO github.com/go-audio/wav v0.0.0-20181013172942-de841e69b884/go.mod h1:UiqzUyfX0zs3pJ/DPyvS5v8sN6s5bXPUDDIVA5v8dks= github.com/go-fonts/dejavu v0.1.0 h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= -github.com/go-fonts/latin-modern v0.2.0 h1:5/Tv1Ek/QCr20C6ZOz15vw3g7GELYL98KWr8Hgo+3vk= github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks= +github.com/go-fonts/liberation v0.1.1 h1:wBrPaMkrXFBW3qXpXAjiKljdVUMxn9bX2ia3XjPHoik= github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= -github.com/go-fonts/liberation v0.2.0 h1:jAkAWJP4S+OsrPLZM4/eC9iW7CtHy+HBXrEwZXWo5VM= -github.com/go-fonts/liberation v0.2.0/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY= github.com/go-fonts/stix v0.1.0/go.mod h1:w/c1f0ldAUlJmLBvlbkvVXLAD+tAMqobIIQpmnUIzUY= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07 h1:OTlfMvwR1rLyf9goVmXfuS5AJn80+Vmj4rTf4n46SOs= github.com/go-latex/latex v0.0.0-20210118124228-b3d85cf34e07/go.mod h1:CO1AlKB2CSIqUrmQPqA0gdRIlnLEY0gK5JGjh37zN5U= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81 h1:6zl3BbBhdnMkpSj2YY30qV3gDcVBGtFgVsV3+/i+mKQ= -github.com/go-latex/latex v0.0.0-20210823091927-c0d11ff05a81/go.mod h1:SX0U8uGpxhq9o2S/CELCSUxEWWAuoCUcVCQWv7G2OCk= -github.com/go-pdf/fpdf v0.5.0 h1:GHpcYsiDV2hdo77VTOuTF9k1sN8F8IY7NjnCo9x+NPY= -github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-ping/ping v0.0.0-20201115131931-3300c582a663/go.mod h1:35JbSyV/BYqHwwRA6Zr1uVDm1637YlNOU61wI797NPI= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= @@ -79,17 +72,18 @@ github.com/mattetti/audio v0.0.0-20180912171649-01576cde1f21 h1:Hc1iKlyxNHp3CV59 github.com/mattetti/audio v0.0.0-20180912171649-01576cde1f21/go.mod h1:LlQmBGkOuV/SKzEDXBPKauvN2UqCgzXO2XjecTGj40s= github.com/mewkiz/flac v1.0.5 h1:dHGW/2kf+/KZ2GGqSVayNEhL9pluKn/rr/h/QqD9Ogc= github.com/mewkiz/flac v1.0.5/go.mod h1:EHZNU32dMF6alpurYyKHDLYpW1lYpBZ5WrXi/VuNIGs= +github.com/mjibson/go-dsp v0.0.0-20180508042940-11479a337f12 h1:dd7vnTDfjtwCETZDrRe+GPYNLA1jBtbZeyfyE8eZCyk= +github.com/mjibson/go-dsp v0.0.0-20180508042940-11479a337f12/go.mod h1:i/KKcxEWEO8Yyl11DYafRPKOPVYTrhxiTRigjtEEXZU= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ= github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= -github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= -github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -129,10 +123,8 @@ golang.org/x/image v0.0.0-20200119044424-58c23975cae1/go.mod h1:FeLwcggjj3mMvU+o golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200618115811-c13761719519/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20201208152932-35266b937fa6/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20210216034530-4410531fe030 h1:lP9pYkih3DUSC641giIXa2XqfTIbbbRr0w2EOTA7wHA= golang.org/x/image v0.0.0-20210216034530-4410531fe030/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.0.0-20210607152325-775e3b0c77b9/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d h1:RNPAfi2nHY7C2srAV8A49jpsYr0ADedCk1wq6fTMTvs= -golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -152,9 +144,8 @@ golang.org/x/sys v0.0.0-20210909193231-528a39cd75f3/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -163,20 +154,17 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.8.2 h1:CCXrcPKiGGotvnN6jfUsKk4rRqm7q09/YbKb5xCEvtM= gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0= -gonum.org/v1/gonum v0.9.3 h1:DnoIG+QAMaF5NvxnGe/oKsgKcAc6PcUyl8q0VetfQ8s= -gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0 h1:OE9mWmgKkjJyEmDAAtGMPjXu+YNeGvK9VTSHY6+Qihc= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +gonum.org/v1/plot v0.9.0 h1:3sEo36Uopv1/SA/dMFFaxXoL5XyikJ9Sf2Vll/k6+2E= gonum.org/v1/plot v0.9.0/go.mod h1:3Pcqqmp6RHvJI72kgb8fThyUnav364FOsdDo2aGW5lY= -gonum.org/v1/plot v0.10.0 h1:ymLukg4XJlQnYUJCp+coQq5M7BsUJFk6XQE4HPflwdw= -gonum.org/v1/plot v0.10.0/go.mod h1:JWIHJ7U20drSQb/aDpTetJzfC1KlAPldJLpkSy88dvQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8= gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=