3

I would like to play a sound in a jupyter notebook each time a specific condition is met. After browsing through similar questions on stackoverflow, I managed to almost achieve this, especially thanks to this thread: Playing audio in jupyter, in a for loop. The notebook would look something like this:

import IPython.display as ipd
import ipywidgets as widgets
import numpy as np

output = widgets.Output()
display(output)

# Define sinewave to produce sound
sr = 44100
T = 2 # seconds
t = np.linspace(0, T, int(T*sr), endpoint=False) # sample sine wave
freqs = [329.63,440.0,466.16,554.37,587.33]
for i in range(0,len(freqs)):
    if (i<2):
        x = 0.5*np.sin(2*np.pi*freqs[i]*t)
        with output:        
            ipd.display(ipd.Audio(x, rate=sr,autoplay=True))

However a major problem remains: each time the condition is met, a new widget appears in the cell where the output is displayed; Given that a sound could potentially be played hundreds of times, this leads to a massive slowdown after some time. In addition, I don't need any widget to be displayed at all in the first place, since I simply want the sound to be played automatically. I have tried using "output.clear_output()", but doing so too early will interrupt any sound currently playing, and anyway I guess it takes ressources to clear and reload widgets constantly, so it's not a solution if used that way. Is there a way to just update the widget so that only one is displayed? Is it possible to make this work without widgets?

P.S: in the end I'd like to provide an online version of the notebook through MyBinder, so it should work there as well.

Edit: the use of "clear_output(wait=True)" after displaying the display kind of works for short sounds. Still, this is not optimal, and more importantly does not work if I want several sounds to be played simultaneously.

Leinahtan
  • 57
  • 1
  • 5
  • I also discovered the following notebook: https://github.com/ipython-books/cookbook-2nd-code/blob/master/chapter11_image/07_synth.ipynb It is a virtual synthetizer, and would basically do what I want. However, while it seems to have worked at some point in the past, now it is not, so I guess something changed in the versions of jupyter. Any idea anyone? – Leinahtan Nov 16 '19 at 00:03
  • For that virtual synthesizer you say is presently not working, delete the line `with widgets.Output():` and move `synth(f)` up where it was so indentation is correct. I imagine the specifics on the output widget working inside Jupyter with context management protocol has subtly changed since that notebook was written or maybe simplified given [the documentation](https://github.com/jupyter-widgets/ipywidgets/blob/46aa56b6ca304233f31d0c5a27def6004a0fb5e2/ipywidgets/widgets/widget_output.py). – Wayne Dec 16 '19 at 22:18
  • By doing what you suggest with the synthetizer, it indeed works, but again, it displays a new output each time a button is pressed, so it doesn't solve my initial problem. I think things would work out if I had a way to remove an output widget as soon is the sound has finished playing, while keeping the other instances running (hopefully I'm clear enough). I really don't know much (read: "anything" :D) about protocols and so on, so I have a hard time figuring out what is happening with widgets. – Leinahtan Dec 17 '19 at 10:20
  • It seems like you'd need to capture each first so you can then reference each for clearing using the `with` context to target clearing a particular output like [here](https://github.com/jupyter-widgets/ipywidgets/issues/1744#issuecomment-335179855). – Wayne Dec 17 '19 at 17:35

1 Answers1

-1

just happened to read this

a cleaner solution exists in

  1. define an output widget to where you redirect all audio output

output = widgets.Output()

  1. clear that widget every time
   with output:
       clear_output()
       synth(f)
  1. add the output widget to the layout

widgets.VBox([widgets.Box(buttons),output])

DVC
  • 1
  • This may be what I am looking for. However it is hard to understand. I need to understand the non-working code in the question before I can understand this. No even then it makes zero sence. – ctrl-alt-delor Apr 12 '21 at 23:31