ipywidgets icon indicating copy to clipboard operation
ipywidgets copied to clipboard

Playing an Audio widget programmatically?

Open deeplook opened this issue 4 years ago • 18 comments
trafficstars

I tried to play an Audio widget programmatically, but I don't see a play()-like method to do that, like:

from ipywidgets import Audio
w = Audio.from_file("audio/a.mp3", autoplay=False, loop=False)
w.play()
# AttributeError: 'Audio' object has no attribute 'play'

Is it possible?

deeplook avatar Jan 14 '21 19:01 deeplook

It's not currently possible. But I think this is a reasonable feature request. The steps to accomplish this are:

  1. Add a playing Bool attribute to the python side https://github.com/jupyter-widgets/ipywidgets/blob/bd8ec4509cdfee0a3609b30a4bc9ea5e398b856b/ipywidgets/widgets/widget_media.py#L214-L217

  2. On the javascript side add a this.model.on("change:playing", <some fxn>) callback to update call .play() or .pause() This should probably go here: https://github.com/jupyter-widgets/ipywidgets/blob/bd8ec4509cdfee0a3609b30a4bc9ea5e398b856b/packages/controls/src/widget_audio.ts#L39

https://www.w3schools.com/Jsref/met_audio_pause.asp

See how the play button widget works for inspiration: https://github.com/jupyter-widgets/ipywidgets/blob/51322341d4f6d88449f9dbf6d538c60de6d23543/packages/controls/src/widget_int.ts#L922

ianhi avatar Feb 07 '21 19:02 ianhi

@deeplook I think the best tool for this is ipywebrtc, not the media widgets of ipywidgets.

SylvainCorlay avatar Feb 07 '21 20:02 SylvainCorlay

Let's close this issue as @SylvainCorlay's suggestion makes good sense and requires no additional development here. @deeplook and ianhi please close this issue if you agree. Thanks!

willingc avatar Feb 08 '21 05:02 willingc

I'll surely try ipywebrtc, but it does have a slight flavor of having to use an overkill solution for a little missing feature in the existing Audio widget that would simply make it a bit more of a fully implemented thingy.

deeplook avatar Feb 09 '21 17:02 deeplook

I agree with @deeplook.

hai-schrodinger avatar Feb 09 '21 17:02 hai-schrodinger

My sense is that the ability to start and stop playing is essential functionality for an audio widget. So if ipywidgets is going to provide an audio widget it is incomplete without that. If ipywebrtc is the superior solution then perhaps the audio widget should be deprecated (although I'm pro keeping the audio widget with a playing trait).

ianhi avatar Feb 09 '21 18:02 ianhi

The other issue with ipywebrtc is that it seems to currently only support jlab-1 https://github.com/maartenbreddels/ipywebrtc/pull/95

ianhi avatar Feb 09 '21 18:02 ianhi

Another useful case for nglview to programmatically play the trajectory (using Play from ipywidgets).

hai-schrodinger avatar Feb 09 '21 18:02 hai-schrodinger

tl;dr: I support adding a playing attribute to the audio/video widgets, and would support adding a volume attribute as well.

Currently the audio and video widgets have the following attributes exposed from the HTML media element:

  • autoplay - start playing immediately on display
  • loop - loop the audio
  • controls - boolean saying whether the browser should display controls.

I think it makes sense to expose others that help in managing the media element. From https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement, for example, we could expose:

  • volume (there is an event for volumechange we can use to notify the python side)
  • and also, as suggested here, a playing attribute that uses the .play() and .pause() methods to control the playback, and there are play/pause events we can use to notify the python side

There are some other attributes we could expose like muted and playbackRate, but it's not clear (a) how useful it would be and (b) what events could be used to send notification back to python if they changed from user interaction.

jasongrout avatar Feb 09 '21 19:02 jasongrout

I agree that having a .play(), .pause() method and a volume control would be super nice. You can assign this to me @jasongrout if no-one is working on it.

I remember looking into syncing the play progress between views of a media widget, it was very compllicated to have a robust solution for this. So I guess we'll need to live without a progress attribute for now.

martinRenou avatar Feb 11 '21 08:02 martinRenou

If ipywebrtc is the superior solution then perhaps the audio widget should be deprecated (although I'm pro keeping the audio widget with a playing trait).

ipywebrtc actually relies on ipywidgets.Audio and ipywidgets.Video :)

martinRenou avatar Feb 11 '21 08:02 martinRenou

I may be missing an aspect of what people are asking for, but in some use-cases, wouldn't the following work:

audio = Audio(filename='some_audio_file.wav', autoplay=True)
display(audio)

By making audio be autoplay then each time you include display(Audio) it will just play automatically.

I guess there are reasonable extensions that the above does not deal with, and one of those is what brought me here (I'm looking for a way to asynchronously play audio via the frontend as the above display method makes it wait for the audio to complete before proceeding) but this might be a start for some use-cases.

nmstoker avatar Feb 26 '21 16:02 nmstoker

In my use-case it's not about auto-playing one audio or not, but about selecting which audio to play from multiple ones shown on the same page.

deeplook avatar Mar 01 '21 09:03 deeplook

Okay. I see you would benefit from a cleaner way to work with the files, but you could do what you mention above with this method.

Maybe it's the side effect of it redrawing an audio player each time that you're not keen on, but you could play any one of multiple audio files this way: you prepare all your audio files in advance (1 to N, each prepared as an autoplay, but note, that won't autoplay it yet) and then when you want to play one programmatically, you call the display(audio_N_) for that one and it starts playing .

It's kind of a hack but seems like it gives you what you asked for. I suppose it might be possible to clean up the added audio player afterwards (so your notebook isn't littered with them afterwards)

nmstoker avatar Mar 01 '21 10:03 nmstoker

I guess, this hasn't been fixed yet? Is there any other way of playing audio in a jupyter notebook on the client side, that enables me to start / stop playback programmatically, and ideally, also programmatically change the audio data? With a library like sounddevice I can code something that works for me, but it plays audio only on the server side.

In theory, the web audio API should provide anything needed, but, what's missing seems to be the corresponing widget code to enable using these functions, right?

herrzinter avatar Sep 14 '21 13:09 herrzinter

My autoplay method is clunky and won't give the kind of control that lets you stop playback, but it would work to trigger playback programmatically if you didn't mind the side effects.

Generally speaking though a better solution (eg with widget code /use of web audio API as you mention) seems the smarter way to go, but I don't know if there's any progress there

nmstoker avatar Sep 14 '21 13:09 nmstoker

This code worked for me: from IPython.display import Audio Audio('https://ccrma.stanford.edu/~jos/mp3/pno-cs.mp3', autoplay=True) But don't know how these mp3 are created.

nasrin1748 avatar Oct 15 '23 22:10 nasrin1748