-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5648099
commit 43cc4ee
Showing
6 changed files
with
291 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,10 @@ | ||
# ambiantgo | ||
# AmbiantGo | ||
Plays ambiant sounds in system tray | ||
|
||
## Todo | ||
|
||
* WIP | ||
* Add more non copyright ambiant sounds | ||
|
||
## Sound Credits | ||
* Audio Library PH (https://www.youtube.com/@AudioLibrary69) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,187 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
"time" | ||
|
||
"github.com/faiface/beep" | ||
"github.com/faiface/beep/effects" | ||
"github.com/faiface/beep/mp3" | ||
"github.com/faiface/beep/speaker" | ||
"github.com/getlantern/systray" | ||
) | ||
|
||
type SoundPlayer struct { | ||
sounds []string | ||
currentSound string | ||
currentStreamer beep.StreamSeekCloser | ||
format beep.Format | ||
isPlaying bool | ||
volume float64 | ||
} | ||
|
||
func (sp *SoundPlayer) loadSound(filename string) error { | ||
// Close existing streamer if open | ||
if sp.currentStreamer != nil { | ||
sp.currentStreamer.Close() | ||
} | ||
|
||
// Open new sound file | ||
f, err := os.Open(filename) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
streamer, format, err := mp3.Decode(f) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
sp.currentStreamer = streamer | ||
sp.format = format | ||
sp.currentSound = filename | ||
|
||
return nil | ||
} | ||
|
||
func (sp *SoundPlayer) play() error { | ||
if sp.currentStreamer == nil { | ||
return fmt.Errorf("no sound loaded") | ||
} | ||
|
||
// Initialize speaker if not already initialized | ||
if err := speaker.Init(sp.format.SampleRate, sp.format.SampleRate.N(time.Second/10)); err != nil { | ||
return err | ||
} | ||
|
||
// Reset streamer to beginning | ||
sp.currentStreamer.Seek(0) | ||
|
||
// Create a looping streamer | ||
loopStreamer := beep.Loop(-1, sp.currentStreamer) | ||
|
||
// Create a volume-controlled streamer | ||
volumeCtrl := &beep.Ctrl{Streamer: loopStreamer, Paused: false} | ||
|
||
volume := &effects.Volume{ | ||
Streamer: loopStreamer, | ||
Base: 2, | ||
Volume: 0, | ||
Silent: false, | ||
} | ||
|
||
volume.Volume = sp.volume | ||
|
||
speaker.Play(volume) | ||
sp.isPlaying = true | ||
return volumeCtrl.Streamer.Err() | ||
} | ||
|
||
func (sp *SoundPlayer) pause() { | ||
speaker.Clear() | ||
sp.isPlaying = false | ||
} | ||
|
||
func (sp *SoundPlayer) setVolume(vol float64) { | ||
sp.volume = vol | ||
if sp.isPlaying { | ||
|
||
// Replay with new volume | ||
sp.pause() | ||
sp.play() | ||
} | ||
} | ||
|
||
func main() { | ||
soundPlayer := &SoundPlayer{ | ||
sounds: []string{ | ||
"./sounds/Mountain Stream.mp3", | ||
}, | ||
volume: 0, | ||
} | ||
|
||
// Try to load first sound by default | ||
if len(soundPlayer.sounds) > 0 { | ||
soundPlayer.loadSound(soundPlayer.sounds[0]) | ||
} | ||
|
||
systray.Run(func() { | ||
// Set the icon from ICO file | ||
systray.SetIcon(loadIcon("ambiantgo.ico")) | ||
|
||
// Create menu items | ||
mPlay := systray.AddMenuItem("Play", "Play sound") | ||
mPause := systray.AddMenuItem("Pause", "Pause sound") | ||
|
||
// Volume submenu | ||
mVolume := systray.AddMenuItem("Volume", "Adjust Volume") | ||
mVolumeLow := mVolume.AddSubMenuItem("Low", "Set low volume") | ||
mVolumeMedium := mVolume.AddSubMenuItem("Medium", "Set medium volume") | ||
mVolumeHigh := mVolume.AddSubMenuItem("High", "Set high volume") | ||
|
||
// Sounds submenu | ||
mSounds := systray.AddMenuItem("Sounds", "Select Sound") | ||
soundMenuItems := make([]*systray.MenuItem, len(soundPlayer.sounds)) | ||
for i, sound := range soundPlayer.sounds { | ||
soundMenuItems[i] = mSounds.AddSubMenuItem(filepath.Base(sound), "Select this sound") | ||
} | ||
|
||
mQuit := systray.AddMenuItem("Quit", "Quit the app") | ||
|
||
go func() { | ||
for { | ||
select { | ||
case <-mPlay.ClickedCh: | ||
soundPlayer.play() | ||
case <-mPause.ClickedCh: | ||
soundPlayer.pause() | ||
case <-mVolumeLow.ClickedCh: | ||
soundPlayer.setVolume(-3) | ||
case <-mVolumeMedium.ClickedCh: | ||
soundPlayer.setVolume(-1) | ||
case <-mVolumeHigh.ClickedCh: | ||
soundPlayer.setVolume(0) | ||
case <-mQuit.ClickedCh: | ||
systray.Quit() | ||
return | ||
} | ||
|
||
// Handle sound selection | ||
for i, item := range soundMenuItems { | ||
select { | ||
case <-item.ClickedCh: | ||
err := soundPlayer.loadSound(soundPlayer.sounds[i]) | ||
if err != nil { | ||
log.Println("Error loading sound:", err) | ||
} | ||
// If currently playing, restart with new sound | ||
if soundPlayer.isPlaying { | ||
soundPlayer.play() | ||
} | ||
default: | ||
} | ||
} | ||
} | ||
}() | ||
}, func() { | ||
// Cleanup | ||
if soundPlayer.currentStreamer != nil { | ||
soundPlayer.currentStreamer.Close() | ||
} | ||
speaker.Close() | ||
}) | ||
} | ||
|
||
// loadIcon reads an ICO file and returns its byte content | ||
func loadIcon(filename string) []byte { | ||
// Read the entire ICO file | ||
iconBytes, err := os.ReadFile(filename) | ||
if err != nil { | ||
log.Printf("Error loading icon: %v", err) | ||
return nil | ||
} | ||
return iconBytes | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
module rogverse.fyi/ambiantgo | ||
|
||
go 1.23.4 | ||
|
||
require ( | ||
github.com/faiface/beep v1.1.0 | ||
github.com/getlantern/systray v1.2.2 | ||
) | ||
|
||
require ( | ||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect | ||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect | ||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect | ||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect | ||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect | ||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect | ||
github.com/go-stack/stack v1.8.0 // indirect | ||
github.com/hajimehoshi/go-mp3 v0.3.0 // indirect | ||
github.com/hajimehoshi/oto v0.7.1 // indirect | ||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect | ||
github.com/pkg/errors v0.9.1 // indirect | ||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 // indirect | ||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 // indirect | ||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 // indirect | ||
golang.org/x/sys v0.1.0 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= | ||
github.com/d4l3k/messagediff v1.2.2-0.20190829033028-7e0a312ae40b/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo= | ||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= | ||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/faiface/beep v1.1.0 h1:A2gWP6xf5Rh7RG/p9/VAW2jRSDEGQm5sbOb38sf5d4c= | ||
github.com/faiface/beep v1.1.0/go.mod h1:6I8p6kK2q4opL/eWb+kAkk38ehnTunWeToJB+s51sT4= | ||
github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= | ||
github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= | ||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= | ||
github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= | ||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So= | ||
github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= | ||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk= | ||
github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc= | ||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0= | ||
github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= | ||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc= | ||
github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= | ||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA= | ||
github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= | ||
github.com/getlantern/systray v1.2.2 h1:dCEHtfmvkJG7HZ8lS/sLklTH4RKUcIsKrAD9sThoEBE= | ||
github.com/getlantern/systray v1.2.2/go.mod h1:pXFOI1wwqwYXEhLPm9ZGjS2u/vVELeIgNMY5HvhHhcE= | ||
github.com/go-audio/audio v1.0.0/go.mod h1:6uAu0+H2lHkwdGsAY+j2wHPNPpPoeg5AaEFh9FlA+Zs= | ||
github.com/go-audio/riff v1.0.0/go.mod h1:l3cQwc85y79NQFCRB7TiPoNiaijp6q8Z0Uv38rVG498= | ||
github.com/go-audio/wav v1.0.0/go.mod h1:3yoReyQOsiARkvPl3ERCi8JFjihzG6WhjYpZCf5zAWE= | ||
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= | ||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= | ||
github.com/hajimehoshi/go-mp3 v0.3.0 h1:fTM5DXjp/DL2G74HHAs/aBGiS9Tg7wnp+jkU38bHy4g= | ||
github.com/hajimehoshi/go-mp3 v0.3.0/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0UbtXShQcnfyMM= | ||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI= | ||
github.com/hajimehoshi/oto v0.7.1 h1:I7maFPz5MBCwiutOrz++DLdbr4rTzBsbBuV2VpgU9kk= | ||
github.com/hajimehoshi/oto v0.7.1/go.mod h1:wovJ8WWMfFKvP587mhHgot/MBr4DnNy9m6EepeVGnos= | ||
github.com/icza/bitio v1.0.0/go.mod h1:0jGnlLAx8MKMr9VGnn/4YrvZiprkvBelsVIbA9Jjr9A= | ||
github.com/icza/mighty v0.0.0-20180919140131-cfd07d671de6/go.mod h1:xQig96I1VNBDIWGCdTt54nHt6EeI639SmHycLYL7FkA= | ||
github.com/jfreymuth/oggvorbis v1.0.1/go.mod h1:NqS+K+UXKje0FUYUPosyQ+XTVvjmVjps1aEZH1sumIk= | ||
github.com/jfreymuth/vorbis v1.0.0/go.mod h1:8zy3lUAm9K/rJJk223RKy6vjCZTWC61NA2QD06bfOE0= | ||
github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= | ||
github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= | ||
github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= | ||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= | ||
github.com/mewkiz/flac v1.0.7/go.mod h1:yU74UH277dBUpqxPouHSQIar3G1X/QIclVbFahSd1pU= | ||
github.com/mewkiz/pkg v0.0.0-20190919212034-518ade7978e2/go.mod h1:3E2FUC/qYUfM8+r9zAwpeHJzqRVVMIYnpzD/clwWxyA= | ||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= | ||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= | ||
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/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= | ||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | ||
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= | ||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | ||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8 h1:idBdZTd9UioThJp8KpM/rTSinK/ChZFBE43/WtIy8zg= | ||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||
golang.org/x/image v0.0.0-20190220214146-31aff87c08e9/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067 h1:KYGJGHOQy8oSi1fDlSpcZF0+juKwk/hEMv5SiwHogR0= | ||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= | ||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6 h1:vyLBGJPIl9ZYbcQFM2USFmJBK6KI+t+z6jL0lbwjrnc= | ||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= | ||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20190429190828-d89cdac9e872/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20190626150813-e07cf5db2756/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= | ||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
gopkg.in/Knetic/govaluate.v3 v3.0.0/go.mod h1:csKLBORsPbafmSCGTEh3U7Ozmsuq8ZSIlKk1bcqph0E= |
Binary file not shown.