Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No sound on macOS #145

Closed
flowchartsman opened this issue Jan 25, 2024 · 22 comments · Fixed by #151
Closed

No sound on macOS #145

flowchartsman opened this issue Jan 25, 2024 · 22 comments · Fixed by #151
Labels
documentation Improvements or additions to documentation

Comments

@flowchartsman
Copy link

OS version: 14.1.1 (Sonoma)

Running the to buffer or not to buffer example does not play any sound when enter is struck. No errors are displayed, it's simply silent.

@MarkKremer
Copy link
Contributor

Does the audio work in other examples? I suspect the fmt.Scanln() may not detect the enter press in the desired way and be blocking.

@flowchartsman
Copy link
Author

flowchartsman commented Feb 4, 2024

Whatever it is, it's not the call to Scanln() the following also does not play anything:

package main

import (
        "log"
        "os"
        "time"

        "github.com/gopxl/beep"
        "github.com/gopxl/beep/mp3"
        "github.com/gopxl/beep/speaker"
)

func main() {
        f, err := os.Open("gunshot.mp3")
        if err != nil {
                log.Fatal(err)
        }

        streamer, format, err := mp3.Decode(f)
        if err != nil {
                log.Fatal(err)
        }

        speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/60))

        buffer := beep.NewBuffer(format)
        buffer.Append(streamer)
        streamer.Close()

        for {
                shot := buffer.Streamer(0, buffer.Len())
                speaker.Play(shot)
                time.Sleep(1 * time.Second)
        }
}

I can confirm, however, that at least the tone generator works.

@MarkKremer
Copy link
Contributor

Hmm, that's going to be a bit hard to debug. Your example works for me.

If the tone generator works, that would suggest that the speaker works. If you have no errors, I would assume the mp3 can be read and parsed successfully. And I'm assuming you're using the same gunshot.mp3 file as me so I don't see why that would fail. The buffer doesn't do anything that would be different for us either.

I think this is going to be a game of test a lot of stuff to narrow it down. Below are some things to try. But if you can narrow it down further that would be great.

Just to confirm, this works?

package main

import (
	"log"
	"time"

	"github.com/gopxl/beep"
	"github.com/gopxl/beep/generators"
	"github.com/gopxl/beep/speaker"
)

func main() {
	format := beep.Format{
		SampleRate:  44100,
		NumChannels: 2,
		Precision:   2,
	}
	sine, err := generators.SineTone(format.SampleRate, 400)
	if err != nil {
		log.Fatal(err)
	}
	streamer := beep.Take(format.SampleRate.N(time.Second/2), sine)

	speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/60))

	buffer := beep.NewBuffer(format)
	buffer.Append(streamer)

	for {
		shot := buffer.Streamer(0, buffer.Len())
		speaker.Play(shot)
		time.Sleep(1 * time.Second)
	}
}

Could you also check the other functions for errors and check if the buffer is filled. I've also increased the speaker buffer size here.

package main

import (
	"fmt"
	"log"
	"os"
	"time"

	"github.com/gopxl/beep"
	"github.com/gopxl/beep/mp3"
	"github.com/gopxl/beep/speaker"
)

func main() {
	f, err := os.Open("gunshot.mp3")
	if err != nil {
		log.Fatal(err)
	}

	streamer, format, err := mp3.Decode(f)
	if err != nil {
		log.Fatal(err)
	}

	err = speaker.Init(format.SampleRate, format.SampleRate.N(time.Second/30))
	if err != nil {
		log.Fatal(err)
	}

	buffer := beep.NewBuffer(format)
	buffer.Append(streamer)
	err = streamer.Close()
	if err != nil {
		log.Fatal(err)
	}

	fmt.Printf("Buffer size: %d\n", buffer.Len())
	
	for {
		shot := buffer.Streamer(0, buffer.Len())
		speaker.Play(shot)
		time.Sleep(1 * time.Second)
	}
}

@flowchartsman
Copy link
Author

flowchartsman commented Feb 7, 2024

Just to confirm, this works?

Kind of. This first example makes a brief popping sound with perhaps a few millis of the tone before going silent.

I've also increased the speaker buffer size here.

This works as intended!

@MarkKremer
Copy link
Contributor

Can this issue be marked as solved?

@flowchartsman
Copy link
Author

Up to you! I have tested and every other example works fine, but the core of the issue, really, is that I cannot run beep/examples/tutorial/3-to-buffer-or-not-to-buffer/main.go on my system as it is, and it was difficult to figure out that it was buffer size related, so maybe there's room for a doc issue in this.

The tutorial mentions increasing the buffer size if latency is observed, but I think it might be helpful to mention that this could also include no sound whatsoever. I think a comment in the tutorial and a comment in the example file itself might go a long way, but there's probably also room for some heuristics that could attempt to determine the ideal sample rate.

The documentation could probably also use a treatment on selecting speaker sample rate for use cases that involve playing more than one sample. I imagine many users will want to use this library as I am attempting to, which is to play one of a few different samples as unique notification sounds. The current documents and examples all involve initializing the speaker with the sample rate of the file being played, which makes complete sense if you're only playing one sound, but I think there's room for docs on selecting a speaker sample rate independent of any of the files as well as how you might select that and how to go about ensuring all of your files play as they're intended.

It might even be worth having a func ResampleAuto(quality int, audioSampleRate SampleRate, s Streamer) (or ResampleForSpeaker) that can reach into beep/speaker and get the current sample rate and scale the sample appropriately.

@MarkKremer MarkKremer added the documentation Improvements or additions to documentation label Feb 10, 2024
@atljoseph
Copy link

atljoseph commented Mar 2, 2024

This has GOT to be a bug, but just not with beep, specifically.

I ran into this same issue. I cannot use ANY package to which I import github.com/gopxl/beep/speaker. Simply hangs and never does anything. Even happens when importing _, like this: _ "github.com/gopxl/beep/speaker".

This is useless code, as it doesn't produce any output or fatal error or panics:

package filesystem

import (
	"fmt"
	_ "github.com/gopxl/beep/speaker"
)

func Debug(filename string) error {
	fmt.Println("file", filename)
	return nil
}

Can't even play a tone from the tone-player example in this repo.

  • Same behavior... Doesn't do a single thing. It just keeps hanging.
  • If i remove all the beep imports and code, then the code actually completes.
  • No errors, no panics, no nothing...

I'd expect a failure at the least.... Not just ... nothing.

After much time, it seems that the importation of github.com/ebitengine/oto/v3 is responsible for this bad behavior.

  • Tried with CGO_ENABLED=1, too.

On an M1 Mac.

Link: ebitengine/oto#233

@MarkKremer
Copy link
Contributor

Hey, you are very disrespectful in the linked issue and don't seem to help us debug the problem in any meaningful way up untill now.

You said to have moved on to using a different project. So I won't be helping you with this further. Goodbye

@atljoseph
Copy link

atljoseph commented Mar 3, 2024 via email

@atljoseph
Copy link

Came back to this for a few minutes today, to make sure there was actually an issue still there... Seems to be.

This file represents a program that produces logs and completes:

package main

import (
	"fmt"

	"github.com/gopxl/beep"
	// "github.com/gopxl/beep/speaker"
)

func main() {
	fmt.Println("before")
	_ = beep.SampleRate(48000)
	fmt.Println("during")
	// speaker.Init(sr, 4800)
	fmt.Println("after")
}

But this one runs, never completes, and doesn't log anything:

package main

import (
	"fmt"

	"github.com/gopxl/beep"
	"github.com/gopxl/beep/speaker"
)

func main() {
	fmt.Println("before")
	sr := beep.SampleRate(48000)
	fmt.Println("during")
	speaker.Init(sr, 4800)
	fmt.Println("after")
}

The importation of github.com/gopxl/beep/speaker introduces the behavior change.

  • Maybe it has to do with oto/v3 but was able to get that to work in the ebiten repo, which uses oto/v3.
  • So, maybe it is just how it is used in the beeps speaker package.

Versions:

  • MacOS 14.3.1
  • github.com/gopxl/beep v1.4.0

Again, I have a workaround, but If I'm seeing it, then other people are. Figured you would like to know. Sorry about being a douche last weekend.

@MarkKremer
Copy link
Contributor

MarkKremer commented Mar 10, 2024

So the speaker package doesn't really do anything until Init is called. So I'm wondering if the compilation process is just being a little slow (I've had that before). Could you try:

  • just waiting 10min and see if your code with the speaker produces output. If that works, is it faster the second time?
  • if that doesn't work, try building it to a binary first instead of running it directly and see if the building/compilation finishes.

Could you try this with the verbose build option to see what it hangs on if it does?

@atljoseph
Copy link

atljoseph commented Mar 16, 2024

cd examples/tone-player

Run.

go run -v .

No output.

Build.

go build -v

Build is completed immediately.

./tone-player

No output.

Result.

Gave each 10 minutes.
From main branch.
Nothing ever happened.

@MarkKremer
Copy link
Contributor

MarkKremer commented Mar 16, 2024

Could you run the following snippets with go run -v -a . and reply with the output of each including the build output?

package main

import (
	"fmt"

	"github.com/gopxl/beep"
	"github.com/gopxl/beep/speaker"
)

func init() {
	fmt.Println("init()")
}

func main() {
	fmt.Println("main() start")

	fmt.Println("speaker.Init()")
	err := speaker.Init(beep.SampleRate(41000), 4100)
	if err != nil {
		panic(err)
	}

	fmt.Println("main() end")
}
package main

import (
	"fmt"

	_ "github.com/gopxl/beep/speaker"
)

func init() {
	fmt.Println("init()")
}

func main() {
	fmt.Println("main()")
}
package main

import (
	"fmt"

	_ "github.com/ebitengine/oto/v3"
)

func init() {
	fmt.Println("init()")
}

func main() {
	fmt.Println("main()")
}
package main

import (
	"fmt"
	"runtime"
)

func main() {
	fmt.Printf(
		"Hello world from %s/%s\n",
		runtime.GOOS,
		runtime.GOARCH,
	)
}
package main

import (
	"fmt"

	_ "github.com/ebitengine/purego"
	_ "github.com/ebitengine/purego/objc"
)

func init() {
	fmt.Println("init()")
}

func main() {
	fmt.Println("main()")
}
package main

import (
	"fmt"

	_ "github.com/ebitengine/purego/objc"
)

func init() {
	fmt.Println("init()")
}

func main() {
	fmt.Println("main()")
}

@domingguss
Copy link

domingguss commented Apr 3, 2024

Since no-one answered and I have the same issue here are my results, running on mac OS Big Sur 11.7.10 on a Intel Macbook Pro Late 2014.

TL;DR:

Only scenario 4 exits normally, all other ones hang indefinitely and after 5 minutes I did a ctrl-c.

$ go run -v -a .
internal/coverage/rtcov
internal/unsafeheader
internal/goarch
internal/goos
internal/godebugs
internal/goexperiment
runtime/internal/atomic
internal/cpu
internal/itoa
math/bits
internal/chacha8rand
runtime/internal/math
internal/abi
runtime/internal/sys
unicode/utf8
internal/race
sync/atomic
unicode
cmp
internal/bytealg
slices
github.com/ebitengine/purego/internal/strings
math
runtime
internal/reflectlite
sync
internal/testlog
errors
sort
runtime/cgo
internal/oserror
internal/safefilepath
path
io
strconv
syscall
bytes
strings
reflect
regexp/syntax
internal/syscall/execenv
internal/syscall/unix
time
regexp
io/fs
internal/poll
internal/fmtsort
os
github.com/ebitengine/purego
fmt
github.com/ebitengine/oto/v3/internal/mux
github.com/ebitengine/purego/objc
github.com/pkg/errors
github.com/gopxl/beep
github.com/ebitengine/oto/v3
github.com/gopxl/beep/speaker
example/hello
^Csignal: interrupt

2 .

$  go run -v -a .
internal/goarch
internal/goos
internal/coverage/rtcov
internal/unsafeheader
internal/godebugs
internal/goexperiment
internal/cpu
runtime/internal/atomic
internal/chacha8rand
internal/abi
runtime/internal/math
internal/itoa
runtime/internal/sys
math/bits
unicode/utf8
internal/race
sync/atomic
cmp
unicode
github.com/ebitengine/purego/internal/strings
internal/bytealg
math
slices
runtime
internal/reflectlite
sync
internal/testlog
runtime/cgo
errors
sort
internal/oserror
path
io
internal/safefilepath
strconv
syscall
bytes
strings
reflect
regexp/syntax
internal/syscall/execenv
internal/syscall/unix
time
regexp
io/fs
internal/poll
internal/fmtsort
os
fmt
github.com/ebitengine/purego
github.com/ebitengine/oto/v3/internal/mux
github.com/ebitengine/purego/objc
github.com/pkg/errors
github.com/gopxl/beep
github.com/ebitengine/oto/v3
github.com/gopxl/beep/speaker
example/hello
^Csignal: interrupt

3 .

$  go run -v -a .
internal/coverage/rtcov
internal/goarch
internal/godebugs
internal/goexperiment
internal/unsafeheader
internal/cpu
internal/goos
runtime/internal/atomic
internal/itoa
internal/abi
internal/chacha8rand
runtime/internal/math
runtime/internal/sys
math/bits
unicode/utf8
internal/race
sync/atomic
unicode
cmp
internal/bytealg
github.com/ebitengine/purego/internal/strings
math
slices
runtime
internal/reflectlite
sync
internal/testlog
runtime/cgo
errors
sort
internal/oserror
internal/safefilepath
path
io
strconv
syscall
bytes
strings
reflect
regexp/syntax
internal/syscall/execenv
internal/syscall/unix
time
regexp
io/fs
internal/poll
internal/fmtsort
os
github.com/ebitengine/purego
fmt
github.com/ebitengine/oto/v3/internal/mux
github.com/ebitengine/purego/objc
github.com/ebitengine/oto/v3
example/hello
^Csignal: interrupt

4 .

$ go run -v -a .
internal/godebugs
internal/coverage/rtcov
internal/unsafeheader
internal/goos
internal/goexperiment
internal/goarch
internal/cpu
runtime/internal/atomic
internal/itoa
math/bits
unicode/utf8
internal/race
internal/abi
internal/chacha8rand
runtime/internal/math
runtime/internal/sys
sync/atomic
unicode
cmp
internal/bytealg
slices
math
runtime
internal/reflectlite
sync
internal/testlog
errors
sort
internal/oserror
internal/safefilepath
io
path
strconv
syscall
reflect
internal/syscall/execenv
internal/syscall/unix
time
io/fs
internal/poll
internal/fmtsort
os
fmt
example/hello
Hello world from darwin/amd64

5 .

$ go run -v -a .
internal/goarch
internal/unsafeheader
internal/coverage/rtcov
internal/godebugs
internal/goos
internal/goexperiment
internal/cpu
runtime/internal/atomic
internal/itoa
internal/abi
runtime/internal/math
internal/chacha8rand
math/bits
runtime/internal/sys
unicode/utf8
internal/race
sync/atomic
cmp
unicode
slices
github.com/ebitengine/purego/internal/strings
internal/bytealg
math
runtime
internal/reflectlite
sync
internal/testlog
errors
sort
runtime/cgo
internal/safefilepath
internal/oserror
path
io
strconv
syscall
bytes
strings
reflect
regexp/syntax
internal/syscall/unix
internal/syscall/execenv
time
regexp
io/fs
internal/poll
internal/fmtsort
os
github.com/ebitengine/purego
fmt
github.com/ebitengine/purego/objc
example/hello
^Csignal: interrupt

6 .

  go run -v -a .
internal/unsafeheader
internal/godebugs
internal/goarch
internal/goos
internal/goexperiment
internal/coverage/rtcov
internal/cpu
runtime/internal/atomic
internal/itoa
math/bits
internal/abi
runtime/internal/math
internal/chacha8rand
runtime/internal/sys
unicode/utf8
internal/race
sync/atomic
unicode
cmp
internal/bytealg
slices
math
github.com/ebitengine/purego/internal/strings
runtime
internal/reflectlite
sync
internal/testlog
runtime/cgo
errors
sort
internal/oserror
internal/safefilepath
path
io
strconv
syscall
bytes
strings
reflect
regexp/syntax
internal/syscall/execenv
internal/syscall/unix
time
regexp
io/fs
internal/poll
os
internal/fmtsort
fmt
github.com/ebitengine/purego
github.com/ebitengine/purego/objc
example/hello
^Csignal: interrupt

@domingguss
Copy link

domingguss commented Apr 3, 2024

Interesting: when I downgrade all the way to v1.1.0, only scenarios 3, 5 and 6 keep getting stuck after it logs example/hello as shown above.

Scenarios 1,2 and 4 do finish, and the first tutorial also works...

from v1.2.0 it keeps hanging again in all scenarios including the tutorial, except for scenario 4 (obviously).

@MarkKremer
Copy link
Contributor

Thanks for your help!!

In Beep v1.2 we've upgraded from Oto <1 to 3. From the output above I think it's save to say that we've narrowed down to be somewhere in github.com/ebitengine/purego or github.com/ebitengine/purego/objc.

I have created an issue in the purego repo (ebitengine/purego#224). It would be great if anyone experiencing this issue could help out there if they have questions. :)

@domingguss
Copy link

Found a workaround!

TL;DR - manually set purego version to v0.7.0 after go get github.com/gopxl/beep/speaker

  1. First, I cleared my go.mod dependencies file.

  2. run code below

package main

import (
	"fmt"

	_ "github.com/gopxl/beep/speaker"
)

func init() {
	fmt.Println("init()")
}

func main() {
	fmt.Println("main()")
}
  1. The following happenend in the terminal:
$  go run -v -a .
main.go:6:2: no required module provides package github.com/gopxl/beep/speaker; to add it:
        go get github.com/gopxl/beep/speaker
$ go get github.com/gopxl/beep/speaker
go: added github.com/ebitengine/oto/v3 v3.1.0
go: added github.com/ebitengine/purego v0.5.0
go: added github.com/gopxl/beep v1.4.0
go: added github.com/pkg/errors v0.9.1
go: added golang.org/x/sys v0.12.0
dominggus@dombp15 .../projects/doWork/go-playground  go run -v -a .                      
internal/unsafeheader
internal/goos
internal/godebugs
internal/coverage/rtcov
internal/goexperiment
internal/goarch
runtime/internal/atomic
internal/cpu
internal/itoa
internal/chacha8rand
runtime/internal/math
internal/abi
runtime/internal/sys
math/bits
unicode/utf8
internal/race
sync/atomic
cmp
unicode
github.com/ebitengine/purego/internal/strings
internal/bytealg
slices
math
runtime
internal/reflectlite
sync
internal/testlog
runtime/cgo
errors
sort
path
internal/oserror
io
internal/safefilepath
strconv
syscall
bytes
strings
reflect
regexp/syntax
internal/syscall/execenv
internal/syscall/unix
time
regexp
io/fs
internal/poll
internal/fmtsort
os
github.com/ebitengine/purego
fmt
github.com/ebitengine/oto/v3/internal/mux
github.com/ebitengine/purego/objc
github.com/pkg/errors
github.com/gopxl/beep
github.com/ebitengine/oto/v3
github.com/gopxl/beep/speaker
example.com/mod
^Csignal: interrupt
  1. Then it hangs as expected. Then I open the go.mod file again:
module example.com/mod

go 1.22.1

require (
	github.com/ebitengine/oto/v3 v3.1.0 // indirect
	github.com/ebitengine/purego v0.5.0 // indirect
	github.com/gopxl/beep v1.4.0 // indirect
	github.com/pkg/errors v0.9.1 // indirect
	golang.org/x/sys v0.12.0 // indirect
)
  1. Then, I change purego's version to v0.7.0

  2. Voila, it works!

go run -v -a .
internal/goarch
internal/goexperiment
internal/coverage/rtcov
internal/unsafeheader
internal/godebugs
internal/goos
internal/cpu
internal/abi
runtime/internal/atomic
runtime/internal/math
internal/itoa
internal/chacha8rand
runtime/internal/sys
math/bits
unicode/utf8
internal/race
sync/atomic
unicode
cmp
github.com/ebitengine/purego/internal/cgo
github.com/ebitengine/purego/internal/strings
internal/bytealg
slices
math
runtime
internal/reflectlite
sync
internal/testlog
runtime/cgo
errors
sort
internal/oserror
internal/safefilepath
path
io
strconv
syscall
bytes
strings
reflect
regexp/syntax
internal/syscall/execenv
time
internal/syscall/unix
regexp
io/fs
internal/poll
internal/fmtsort
os
fmt
github.com/ebitengine/oto/v3/internal/mux
github.com/pkg/errors
github.com/gopxl/beep
github.com/ebitengine/purego
github.com/ebitengine/purego/objc
github.com/ebitengine/oto/v3
github.com/gopxl/beep/speaker
example.com/mod
init()
main()

@domingguss
Copy link

Would upping purego's version here fix it?

This is actually my first time trying to create an application with Golang, pls forgive me my noobness :)

@TotallyGamerJet
Copy link
Contributor

TotallyGamerJet commented Apr 8, 2024

You can update a dependency like so go get github.com/ebitengine/purego@latest

EDIT: I was actually able to reproduce the issue with the current beep version #151 does fix it for me.

@MarkKremer
Copy link
Contributor

Merged 👍 I assume this is fixed now but if anyone still has troubles after updating, don't hesitate to re-open or comment.

@MarkKremer
Copy link
Contributor

@domingguss maybe I'm a bit too hasty here. Can you confirm that it works now?

@domingguss
Copy link

@domingguss maybe I'm a bit too hasty here. Can you confirm that it works now?

Yes it works with 1.4.1, thank you all!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
documentation Improvements or additions to documentation
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants