faiface / beep

A little package that brings sound to any Go application. Suitable for playback and audio-processing.
MIT License
2.03k stars 150 forks source link

Oto v2.0 has been release :) #128

Open mewmew opened 2 years ago

mewmew commented 2 years ago

Oto v2.0 was just released :) https://github.com/hajimehoshi/oto/releases/tag/v2.0.0

  • New APIs
    • Accepting io.Reader instead of io.Writer to create a player
    • Richer Player interface
  • New implementations
    • Much more buffers to avoid clicking noises

This issue tracks the work to update beep to use the latest version of Oto, bring with it performance increases.

MarkKremer commented 2 years ago

Some notes:

I may be wrong on some things here. There are a lot of small details to oversee.

I would like to hear other people's thoughts/wishes on this as well.

I may try to implement Oto 2 with Beep. If it takes too long, feel free to work on this yourself. I can't spend loads of time on the computer right now.

mewmew commented 2 years ago

Wow, really thorough review of the Oto release. Thanks @MarkKremer!

I'm surprised to see there are additional delays with the new API, seeing as @hajimehoshi is also the author of Ebiten and use Oto for game development themselves.

@hajimehoshi would you be able to help us clarify the performance improvements you've seen with the new release with regards to games? Also, have you seen any issues with delays as mentioned above?

Thanks for working on this! Both Oto and Beep are really great for game development in Go :)

Cheers, Robin

MarkKremer commented 2 years ago

I want to clarify a bit. The problem is with how Beep and Oto work(ed) together. Oto basically has its own mixer that adds samples of each player together. Each player has a big buffer (which is good because you don't want to run out of samples). It's just that if we add our own mixer in front of it that that we have to wait for all samples currently in the buffer to be played before any new samples are played if we add a new streamer.

I think this could actually work out quite nicely, but we have to make some changes on our end. :)

Great work @hajimehoshi and contributors! I haven't tested it yet but having each player buffer individually and then combining the buffers once the platform-specific code requests it seems promising.

hajimehoshi commented 2 years ago

Hi,

This is fine if you want to play a song but for game sounds this is an unacceptable delay.

I don't think so. It depends on environments, but the audio library's buffer size should be very much smaller. The delay is determined by the audio library's buffer size, not by Oto players' buffer sizes.

For example, on macOS, OS's buffer size is 2048 [bytes] (= 0.005 [s] in 48000 [Hz] stereo)

https://github.com/hajimehoshi/oto/blob/main/driver_macos.go

would you be able to help us clarify the performance improvements you've seen with the new release with regards to games?

EDIT: From this, you can no longer update your data at io.Reader in real time, as the data change is reflected 0.5[s] after its change. I think this might require to change the current Beep's implementation.

Also, have you seen any issues with delays as mentioned above?

I've not realized any additional delays. Rather, v2 should improve latencies especially on Android. Please inform me if you find actual delays. I appreciate all the contributions.

Thanks,

hajimehoshi commented 2 years ago

It's just that if we add our own mixer in front of it that that we have to wait for all samples currently in the buffer to be played before any new samples are played if we add a new streamer.

Ah right, if you do mixing on your side, the buffer sizes of Oto's players would matter.

MarkKremer commented 2 years ago

I've made a first draft. Some notes:

Besides that, I'm still working on updating the examples to use the new speaker and make use of the player where useful.

mewmew commented 2 years ago

Besides that, I'm still working on updating the examples to use the new speaker and make use of the player where useful.

Incredible work @MarkKremer! Excited to take it for a spin, will be great to see if this gives performance improvements in a game I'm playing with. Had some issues with delays a while back.

faiface commented 2 years ago

Hey, sorry for arriving to this issue so late, thanks @MarkKremer for working on this, it would be great to update to the new Oto. However, I have to stress that the philosophy of Beep has to be kept in tact. To spell it out concretely, I think this is one of the fundamental pillars of Beep's philosophy:

Why is this important? Several reasons:

Now, as @hajimehoshi said, if we do our own mixing (and we do!), then Oto's buffer size starts to matter because of latency. If this is still true, then I'm not sure we can upgrade because low latency is important in games and is actually one of the great features of Beep. This needs to be resolved before updating.

Anyway, thanks for the great work, I just wanted to clarify this.

faiface commented 2 years ago

You could argue that we can of course still do our own mixing in software, but if we want latency-free playback, then we have to fall back on Oto's capabilities. This is also not good. If we have two methods of mixing and one of them is latency-free but not composable, and the other one introduces latency but composes well, then we simply have two methods which are both bad.

hajimehoshi commented 2 years ago

For example, what about letting an Oto's player have a callback function that is called just before pushing bytes/floats to the drivers? It's just like Audio Worklet or ScriptProcessorNode and you would be able to modify bytes/floats in real time.

faiface commented 2 years ago

@hajimehoshi Yes, that would be great! Btw, I think with this functionality, it would be possible to upgrade to Oto 2 without breaking any backwards compatibility, which would be ideal.

faiface commented 2 years ago

Actually, without changing any of Beep's API.

hajimehoshi commented 2 years ago

OK let me think. The implementation should not be difficult. Of course, I welcome your designs and/or PRs!

faiface commented 2 years ago

Although now that I think about it, I'm not sure this would be sufficient. We would be able to modify the samples right before pushing, but you would still push 1/2s or 1/4s of samples at once, meaning the next batch of samples could only be added/modifies after this time has passed. This would still keep the latency there.

hajimehoshi commented 2 years ago

This might be extreme, but would using 'zero' io.Reader that emits zeros and mixing everything by yourself at the callback work for Beep?

faiface commented 2 years ago

That would be the idea, but it would only work if the callback was called many times per second. In fact, the latency would be precisely proportional to that number (called N times per second implies latency of 1/N seconds). Would that be possible?

hajimehoshi commented 2 years ago

Yeah for example calling the callback for each 100 samples = 480 times per second for 48000 Hz would be feasible.

faiface commented 2 years ago

Yeah, 480 is way more than enough :D Even 16 is probably enough for games. But just to clarify, this would actually make it possible to change the contents of the buffer in such a way that if the speaker is currently playing some sample and I modify a sample that's 1/480 of a second before in the buffer, the speaker would actually end up playing the modified samples when it gets to that point?

hajimehoshi commented 2 years ago

There is still a small delay due to the low level drivers, OSes, and so on. I set these buffer sizes as small as possible on Oto v2, but still there are.

hajimehoshi commented 2 years ago

I'll be afk soon. See you later :-)

faiface commented 2 years ago

See ya! Hope we can resolve this eventually!

MarkKremer commented 2 years ago

@hajimehoshi so without the buffer between Beep and the driver code, any guesses on how fast the callback has to respond before it glitches?

I had the idea of creating a buffer streamer. Not like the one currently in Beep but more like how Oto buffers the audio: keep 0.5-1sec of audio buffered so it can provide samples quickly and when the buffer gets drained, fill it up with more samples. Having the buffer as a streamer makes it composable again:

[heavy tasks like decoding mp3, resampling etc.] -> [buffer] -> [cheap tasks like volume adjustments, pause/stop etc.] -> [speaker]

I have some thoughts about this but I would like to hear what @faiface thinks about this first.


If people have more/different ideas, I'd love to hear them.

hajimehoshi commented 2 years ago

so without the buffer between Beep and the driver code, any guesses on how fast the callback has to respond before it glitches?

I think you meant how much internal buffers Oto's drivers have. This depends on environments. In the current implementations:

Android: ? (this depends on the returning value of oboe::AudioStream::getBufferSizeInFrames. This should be very small (0.01 [sec] maybe?). macOS: 2048 [bytes] = 256 [samples] in stereo = 0.005 [sec] in 48000 [Hz] stereo iOS: 12288 [bytes] = 0.032 [sec] in 48000 [Hz] stereo Linux/Unix: 2048 [frames] = 1024 [samples] in stereo = 0.021 [sec] in 48000 [Hz] stereo Windows: 4096 [bytes] = 512 [samples] in stereo = 0.011 [sec] in 48000 [Hz] stereo Wasm: This is special since mixing happens on browser side, not Go side. We can process streams in realtime by Audio Worklet.

Note: Samples are represented in float32 in most cases.

tinne26 commented 2 years ago

Quick heads up: https://github.com/hajimehoshi/oto/pull/160 has finally derived into hajimehoshi re-adding configurable buffer sizes in Oto, in case you want to start experimenting with it. The performance and latency is extremely similar to what could already be achieved with UnplayedBufferSize, though (16ms for most desktop environments, and more like 50ms on browsers), but far more convenient and simpler to manage.

hajimehoshi commented 1 year ago

Any updates?

hajimehoshi commented 1 year ago

If Oto v2 would not be used in Beep, it would be worthless to keep backward compatibility of Oto's public APIs. I'd plan to freeze the project of Oto (v2), and move Oto as an internal package in Ebitengine.

mewmew commented 1 year ago

If Oto v2 would not be used in Beep, it would be worthless to keep backward compatibility of Oto's public APIs. I'd plan to freeze the project of Oto (v2), and move Oto as an internal package in Ebitengine.

Oto is tremendously useful as it's the main Go package to give cross-platform audio playback.

@hajimehoshi, please keep Oto as an external package. It is used also outside of Beep and it's a really useful package.

screenshot_2022-10-04_14:40:55

With kindness, Robin

mewmew commented 1 year ago

re: https://github.com/faiface/beep/issues/128#issuecomment-910340152

I've made a first draft.

@MarkKremer I know you've been working on this. Do you still have your draft work for using Oto v2.0 in Beep?

Cheerful regards, Robin

MarkKremer commented 1 year ago

I just pushed whatever I had locally: https://github.com/faiface/beep/compare/master...MarkKremer:beep:master

Something something long time ago disclaimer :smile:

hajimehoshi commented 1 year ago

@hajimehoshi, please keep Oto as an external package. It is used also outside of Beep and it's a really useful package.

Beep is much more widely used than Oto v2.

https://pkg.go.dev/github.com/faiface/beep?tab=importedby

https://github.com/search?l=Go&q=%22github.com%2Fhajimehoshi%2Foto%2Fv2%22&type=Code (66 files Oto v2) vs https://github.com/search?l=Go&q=%22github.com%2Ffaiface%2Fbeep%22&type=Code (1116 files for Beep)

So I thought the impact by stopping maintaining Oto v2 would be limited. That's one of the reasons why I'd stop maitaining Oto v2 as long as Beep didn't use Oto v2. What do you think?

mewmew commented 1 year ago

So I thought the impact by stopping maintaining Oto v2 would be limited. That's one of the reasons why I'd stop maitaining Oto v2 as long as Beep didn't use Oto v2. What do you think?

Yeah, that makes sense. Maintain the version of Oto that is supported by Beep. So when Beep does get support for Oto v2, then switch to supporting v2 instead.

hajimehoshi commented 1 year ago

Maintain the version of Oto that is supported by Beep.

Note that Oto v1 and older is no longer maintained.

mewmew commented 1 year ago

Note that Oto v1 and older is no longer maintained.

Ah, ok. Good to know. I would love to see Oto v2 support added to Beep, as it's the main audio playback for Go. I don't know how far away #130 is from being ready for merge. Anyone care to take a look who knows more about Beep and Oto internals? : )

Cheers, Robin

MarkKremer commented 1 year ago

Last year I had trouble getting the example in my PR to run stably. I think I just found a bug in Oto which may have caused some (but not all?) of the problems. As you can see I've made an issue there.

My PR contains some other stuff which isn't in line with Beep's philosophy of having composable elements (see faiface's comment). Some of which should be removed/changed. Then figure out if the example can be made working again & update docs and other examples.

mewmew commented 1 year ago

Last year I had trouble getting the example in my PR to run stably. I think I just found a bug in Oto which may have caused some (but not all?) of the problems. As you can see I've made an issue there.

Really happy to see you've found an underlying issue! Great job : )

My PR contains some other stuff which isn't in line with Beep's philosophy of having composable elements (see faiface's comment). Some of which should be removed/changed. Then figure out if the example can be made working again & update docs and other examples.

Thanks for providing more background on the current state of the PR. This also enables others to help out, e.g. to test the example code and such.

Excited to see cross platform audio playback in Go receive love from many different people!

Cheers, Robin

MarkKremer commented 1 year ago

I updated my PR with a more minimum viable product version of the speaker so we can get to Oto v2 sooner. I kept the mixer on our end and removed my other additions which aren't strictly necessary. It is backwards compatible I think. If anyone is curious, I moved my original version to here.

The speedy player example seems to work great except that it doesn't like to share audio playback with other programs on my laptop. But that could be because it uses the hardware driver or something which is documented somewhere.

Next steps in no particular order:

mewmew commented 1 year ago

Thanks for doing the work @MarkKremer and updating your PR!

I'll be excited to test this out on our little game project as soon as I'm through the exam period at Uni : ) Should be in about one week.

Cheerful regards, Robin

Edit: I couldn't wait, so I tested your PR (#130) and it works like a charm!

MarkKremer commented 1 year ago

PR is ready for review. I did add some comments.

mewmew commented 1 year ago

PR is ready for review. I did add some comments.

That's great! I don't know the ins and outs of the beep nor oto implementations, so I I can't address some of the comments (e.g. ignore errors, close of context, etc).

The parts I do know in beep are related to FLAC decoding : )

However, as mentioned in https://github.com/faiface/beep/issues/128#issuecomment-1278127076, using #130 worked great on my end (using Linux). So at least, that's a :+1: from a perspective user of beep with the Oto v2 branch merged : )

Cheers, Robin

Oh, and thanks a lot for working on this! Both @MarkKremer, @hajimehoshi and everyone else involed :heart:

hajimehoshi commented 1 year ago

I think I'll release Oto v3 this year in order to clean up the API.

arthurspa commented 9 months ago

Hi, @hajimehoshi , I loved beep project and started using it. Thanks!!! It currently does not work when I tried to run on iOS. I have some hope that with oto v3 it will work. Do you still plan to support Oto v3 for beep this year?

hajimehoshi commented 9 months ago

Hi, I'm not the author of beep. Please ask the author :-)

arthurspa commented 9 months ago

Right, I misunderstood based on your previous comment :)

mewmew commented 9 months ago

Mirroring @hajimehoshi comment in this issue, so it's not missed (ref: https://github.com/faiface/beep/pull/130#issuecomment-1304760337)

Who are the maintainers of this project?

I know @faiface stepped down as maintainer of the pixel and beep projects. Who took his place I do not know.

Anyone with more information, please let us know : )

And of course, it would be great to see oto v3 in beep.

But as a prerequisite, there should be some kind of maintenance plan for beep. Hope we can keep this amazing project alive as it has together with oto simplified cross-platform audio playback a lot.

Cheerful regards, Robin

MarkKremer commented 9 months ago

I've kindly spammed @faiface through the number of channels I could find (please forgive me Michal).

If you happen to read this, please contact me. I would like to help you out with coming up with a maintenance plan for Beep. :pray:

MarkKremer commented 9 months ago

I haven't been able to contact him but the Pixel people are working on forks for all his projects including Beep. I assume they will add a notice to this repo when it's time. For now the Pixel2 Discord is probably a good channel if you want the newest information.