diff --git a/examples/audiospectrum/main.go b/examples/audiospectrum/main.go new file mode 100644 index 0000000..08a0976 --- /dev/null +++ b/examples/audiospectrum/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "image/color" + "math/rand" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/theme" + "git.martyn.berlin/martyn/fyne-widgets/pkg/audiospectrum" + "git.martyn.berlin/martyn/fyne-widgets/pkg/layouts" +) + +func main() { + a := app.New() + w := a.NewWindow("VUMeter") + randomAudioData := make([]int32, 1200) + for i := 0; i < 1200; i++ { + randomAudioData[i] = rand.Int31() + } + as := audiospectrum.NewAudioSpectrum(randomAudioData) + as2 := audiospectrum.NewAudioSpectrum(randomAudioData) + as2.OverrideBackground = true + as2.OverrideBackgroundColor = color.RGBA{0, 0, 0xff, 0xff} // no effect because of the next line + as2.TransparentBackground = true + as2.SetMinSize(fyne.NewSize(1200, 64)) + as3 := audiospectrum.NewAudioSpectrum(randomAudioData) + as3.StretchSamples = true + as3.SetMinSize(fyne.NewSize(100, 64)) + as3.OverrideForeground = true + as3.OverrideForegroundColor = color.RGBA{0xff, 0, 0, 0xff} + as3.TransparentBackground = false + + layout := layouts.NewFloatingControlsLayout() + layout.FloatingControlsLocation = layouts.FloatingControlsCenter + image := canvas.NewImageFromResource(theme.FyneLogo()) + image.SetMinSize(fyne.NewSize(200, 64*3)) + + contain := container.New(&layout, container.NewBorder(image, as, nil, nil, as3), container.NewBorder(nil, nil, nil, nil, as2)) + w.SetContent(contain) + w.ShowAndRun() +} diff --git a/go.mod b/go.mod index d1f8382..51c7144 100644 --- a/go.mod +++ b/go.mod @@ -15,12 +15,13 @@ require ( fyne.io/fyne v1.4.3 // indirect github.com/blackjack/webcam v0.0.0-20200313125108-10ed912a8539 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/disintegration/imaging v1.6.2 // indirect github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 // indirect - github.com/fsnotify/fsnotify v1.4.9 // indirect - github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f // indirect - github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be // indirect - github.com/godbus/dbus/v5 v5.0.4 // indirect - github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff // indirect + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 // indirect + github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec // indirect + github.com/godbus/dbus/v5 v5.0.6 // indirect + github.com/goki/freetype v0.0.0-20220119013949-7a161fd3728c // indirect github.com/google/uuid v1.3.0 // indirect github.com/pion/datachannel v1.5.2 // indirect github.com/pion/dtls/v2 v2.0.10 // indirect @@ -43,15 +44,13 @@ require ( github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564 // indirect github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9 // indirect github.com/stretchr/testify v1.7.0 // indirect - github.com/yuin/goldmark v1.3.8 // indirect + github.com/yuin/goldmark v1.4.5 // indirect golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect - golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 // indirect - golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d // indirect - golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 // indirect - golang.org/x/net v0.0.0-20211020060615-d418f374d309 // indirect - golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 // indirect - golang.org/x/text v0.3.6 // indirect + golang.org/x/image v0.0.0-20211028202545-6944b10bf410 // indirect + golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect + golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect + gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect ) diff --git a/go.sum b/go.sum index 137025f..343b631 100644 --- a/go.sum +++ b/go.sum @@ -13,27 +13,39 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c= +github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3 h1:FDqhDm7pcsLhhWl1QtD8vlzI4mm59llRvNzrFg6/LAA= github.com/fredbi/uri v0.0.0-20181227131451-3dcfdacbaaf3/go.mod h1:CzM2G82Q9BDUvMTGHnXf/6OExw/Dz2ivDj48nVg7Lg8= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= +github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= github.com/gen2brain/malgo v0.10.35/go.mod h1:zHSUNZAXfCeNsZou0RtQ6Zk7gDYLIcKOrUWtAdksnEs= github.com/gen2brain/shm v0.0.0-20200228170931-49f9650110c5/go.mod h1:uF6rMu/1nvu+5DpiRLwusA6xB8zlkNoGzKn8lmYONUo= github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76wBquMVETx7uveQD9MCIQoU= github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM= +github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6 h1:zDw5v7qm4yH7N8C8uWd+8Ii9rROdgWxQuGoJ9WDXxfk= +github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be h1:Z28GdQBfKOL8tNHjvaDn3wHDO7AzTRkmAXvHvnopp98= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211024062804-40e447a793be/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec h1:3FLiRYO6PlQFDpUU7OEFlWgjGD1jnBIVSJ5SYRWk+9c= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20211213063430-748e38ca8aec/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6 h1:mkgN1ofwASrYnJ5W6U/BxG15eXXXjirgZc7CLqkcaro= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff h1:W71vTCKoxtdXgnm1ECDFkfQnpdqAO00zzGXLA5yaEX8= github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= +github.com/goki/freetype v0.0.0-20220119013949-7a161fd3728c h1:JGCm/+tJ9gC6THUxooTldS+CUDsba0qvkvU3DHklqW8= +github.com/goki/freetype v0.0.0-20220119013949-7a161fd3728c/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= @@ -142,6 +154,8 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.8 h1:Nw158Q8QN+CPgTmVRByhVwapp8Mm1e2blinhmx4wx5E= github.com/yuin/goldmark v1.3.8/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.5 h1:4OEQwtW2uLXjEdgnGM3Vg652Pq37X7NOIRzFWb3BzIc= +github.com/yuin/goldmark v1.4.5/go.mod h1:rmuwmfZ0+bvzB24eSC//bk1R1Zp3hM0OXYv/G2LIilg= github.com/zergon321/reisen v0.1.2-0.20211204174623-8f03055a3ab7 h1:PFx9rpfn0C64bcnHU2rNkDIqk+ViDhzlQZb3Nk6dNQ0= github.com/zergon321/reisen v0.1.2-0.20211204174623-8f03055a3ab7/go.mod h1:gOVU64eHyJF83zePqcJffuPATKC+GQrztIZJs6sR0xM= gocv.io/x/gocv v0.29.0 h1:Zg5ZoIFSY4oBehoIRoSaSeY+KF+nvqv1O1qNmALiMec= @@ -159,16 +173,15 @@ golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56 h1:estk1glOnSVeJ9tdEZZc5mAMD golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200430140353-33d19683fad8 h1:6WW6V3x1P/jokJBpRQYUJnMHRP6isStQwCozxnU7XQw= golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20200801110659-972c09e46d76 h1:U7GPaoQyQmX+CBRWXKrvRzWTbd+slqeSh8uARsIyhAw= golang.org/x/image v0.0.0-20200801110659-972c09e46d76/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 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-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554 h1:3In5TnfvnuXTF/uflgpYxSCEGP2NdYT37KsPh3VjZYU= -golang.org/x/mobile v0.0.0-20210716004757-34ab1303b554/go.mod h1:jFTmtFYCV0MFtXBU+J5V/+5AUeVS0ON/0WkE/KSrl6E= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ= +golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -192,6 +205,8 @@ golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211005001312-d4b1ae081e3b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309 h1:A0lJIi+hcTR6aajJH4YqKWwohY4aW9RO7oRMcdv+HKI= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd h1:O7DYs+zxREGLKzKoMQrtrEacpb0ZVXA5rIwylE2Xchk= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -218,6 +233,8 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359 h1:2B5p2L5IfGiD7+b9BOoRMC6DgObAVZV+Fsp050NqXik= golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -225,6 +242,8 @@ golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= golang.org/x/text v0.3.3/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/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -259,3 +278,5 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/audiospectrum/audiospectrum.go b/pkg/audiospectrum/audiospectrum.go new file mode 100644 index 0000000..dc9dea6 --- /dev/null +++ b/pkg/audiospectrum/audiospectrum.go @@ -0,0 +1,183 @@ +package audiospectrum + +import ( + "image" + "image/color" + "math" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/theme" + "fyne.io/fyne/v2/widget" + "github.com/disintegration/imaging" +) + +// +// Widget code starts here +// +// A visualisation of an audio stream widget with themed or overridden background and foreground +// +type AudioSpectrum struct { + widget.BaseWidget // Inherit from BaseWidget + audioData []int32 // The data to display in the widget + StretchSamples bool + TransparentBackground bool + OverrideForeground bool + OverrideForegroundColor color.Color + OverrideBackground bool + OverrideBackgroundColor color.Color + minSize fyne.Size +} + +// +// Create a Widget and Extend (initialiase) the BaseWidget +// +func NewAudioSpectrum(data []int32) *AudioSpectrum { + w := &AudioSpectrum{ // Create this widget with an initial text value + audioData: data, + StretchSamples: false, + TransparentBackground: false, + OverrideForeground: false, + OverrideForegroundColor: color.RGBA{0, 0, 0, 0xff}, + OverrideBackground: false, + OverrideBackgroundColor: color.RGBA{0xff, 0xff, 0xff, 0xff}, + minSize: fyne.NewSize(200, 64), + } + w.ExtendBaseWidget(w) // Initialiase the BaseWidget + return w +} + +// +// Create the renderer. This is called by the fyne application +// +func (w *AudioSpectrum) CreateRenderer() fyne.WidgetRenderer { + // Pass this widget to the renderer so it can access the text field + return newAudioSpectrumRenderer(w) +} + +// +// Set the minsize (default is 200x64) +// +func (w *AudioSpectrum) SetMinSize(newSize fyne.Size) { + // Pass this widget to the renderer so it can access the text field + w.minSize = newSize +} + +// +// Widget Renderer code starts here +// +type audioSpectrumRenderer struct { + widget *AudioSpectrum // Reference to the widget holding the current state + background *canvas.Rectangle // A background rectangle + canvas *canvas.Raster // The waveform +} + +// +// Create the renderer with a reference to the widget +// Note: The background and foreground colours are set from the current theme. +// +// Do not size or move canvas objects here. +// +func newAudioSpectrumRenderer(theWidget *AudioSpectrum) *audioSpectrumRenderer { + r := &audioSpectrumRenderer{ + widget: theWidget, + background: canvas.NewRectangle(theme.BackgroundColor()), + } + r.canvas = canvas.NewRaster(r.audioDataToImage) + return r +} + +// From arduino map() lol +func int32Map(x int32, in_min int32, in_max int32, out_min int32, out_max int32) int32 { + var _x = int64(x) + var _in_min = int64(in_min) + var _in_max = int64(in_max) + var _out_min = int64(out_min) + var _out_max = int64(out_max) + var r = int64((_x-_in_min)*(_out_max-_out_min)/(_in_max-_in_min) + _out_min) + return int32(r) +} + +func (r *audioSpectrumRenderer) audioDataToImage(w, h int) image.Image { + foregroundColor := theme.ForegroundColor() + if r.widget.OverrideForeground { + foregroundColor = r.widget.OverrideForegroundColor + } + upLeft := image.Point{0, 0} + lowRight := image.Point{w, h} + if r.widget.StretchSamples { + lowRight = image.Point{len(r.widget.audioData), h} + } + + img := image.NewRGBA(image.Rectangle{upLeft, lowRight}) + i := int32(0) + for i = 0; i < int32(len(r.widget.audioData)); i++ { + sample := r.widget.audioData[i] + // /2 because we draw spectrums with 0 at the middle! + sampleheight := int32Map(sample, 0, math.MaxInt32, 0, int32(h/2)) + y := int32(0) + //center line + img.Set(int(i), int(h/2), foregroundColor) + for y = int32(h); y > int32(h)-sampleheight; y-- { + img.Set(int(i), int(y)-(h/2), foregroundColor) + } + for y = int32(h / 2); y < sampleheight+(int32(h)/2); y++ { + img.Set(int(i), int(y), foregroundColor) + } + } + if r.widget.StretchSamples { + return imaging.Resize(img, w, h, imaging.NearestNeighbor) + } + return img +} + +// +// The Refresh() method is called if the state of the widget changes or the +// theme is changed +// +// Note: The background and foreground colours are set from the current theme +// +func (r *audioSpectrumRenderer) Refresh() { + backgroundColor := theme.BackgroundColor() + if r.widget.OverrideBackground { + backgroundColor = color.RGBA{0, 0, 0xff, 0xff} //r.widget.OverrideBackgroundColor + } + r.background.FillColor = backgroundColor + r.background.Refresh() // Redraw the background first + r.canvas.Refresh() // Redraw the waveform on top +} + +// +// Given the size required by the fyne application move and re-size the +// canvas objects. +// +func (r *audioSpectrumRenderer) Layout(s fyne.Size) { + // Make sure the background fills the widget + r.background.Resize(s) + r.canvas.Resize(s) + r.Refresh() +} + +// +// Create a minimum size for the widget. +// The smallest size is the size of the text with a border defined by the theme padding +// +func (r *audioSpectrumRenderer) MinSize() fyne.Size { + // Default is set in newSpectrumRenderer, overridable by users + return r.widget.minSize +} + +// +// Return a list of each canvas object. +// +func (r *audioSpectrumRenderer) Objects() []fyne.CanvasObject { + if r.widget.TransparentBackground { + return []fyne.CanvasObject{r.canvas} + } + return []fyne.CanvasObject{r.background, r.canvas} +} + +// +// Cleanup if resources have been allocated +// +func (r *audioSpectrumRenderer) Destroy() {}