This is a working prototype of a cell magic that plays a “beep” sound after cell execution.
%%finish_with_beep
for i in range(0,10000000):
x = i+1
print("Hello World")
from IPython import get_ipython
from IPython.core.magic import Magics, cell_magic, magics_class
from IPython.display import Audio
@magics_class
class MyMagic(Magics):
@cell_magic
def finish_with_beep(self, line, cell):
self.shell.run_cell(cell)
print("beep")
sound_file = 'beep.wav'
display(Audio(sound_file, autoplay=True))
ipy = get_ipython()
ipy.register_magics(MyMagic)
I think that %%finish_with_beep
can be useful for people who want to be notified when a long-running cell execution is finished.
3 Likes
By the way different, versions of notebook add the cells with different delay (or in batches) so you can get different music on re-opening of a notebook depending on the environment
(if not using one of the workarounds that delete the audio after playing).
2 Likes
get different music on re-opening of a notebook depending on the environment 
This can be advertised as a jupy-synth feature 
Thanks for pointing me to your code, I am now using the InvisibleAudio class into the cell magic definition, and the Audio player is now indeed hidden.
But re-opening the notebook will still play all sounds.
I really don’t mind that small bug, so for my personal use I won’t implement a fix for that.
But if someone is interested in tweaking this finish_with_beep
magic, feel free to go ahead 
from IPython import get_ipython
from IPython.core.magic import Magics, cell_magic, magics_class
from IPython.display import display, Audio
OUTPUT_AREA_CLASS = 'jp-OutputArea-child'
OUT_CLASS = 'jp-transient-html'
def hide_closest(css_class):
return (
f"var widget_our = this.closest('.{OUT_CLASS}');"
f"var that = widget_our ? widget_our : this;"
f"that.closest('.{css_class}').style.display = 'none';"
)
class InvisibleAudio(Audio): # by @krassowski
def _repr_html_(self):
audio = super()._repr_html_()
audio = audio.replace(
'<audio',
(
'<audio onended="'
+ hide_closest(css_class=OUTPUT_AREA_CLASS)
+ '" onloadstart="' + hide_closest(css_class=OUTPUT_AREA_CLASS) + '"'
)
)
return f'<div style="display:none">{audio}</div>'
@magics_class
class MyMagic(Magics):
@cell_magic
def finish_with_beep(self, line, cell):
self.shell.run_cell(cell)
#print("beep")
sound_file = 'beep.wav'
display(InvisibleAudio(filename='beep.wav', autoplay=True))
ipy = get_ipython()
ipy.register_magics(MyMagic)
That’s what transient_html
trick is for if I recall correctly.
from IPython import get_ipython
from IPython.core.magic import Magics, cell_magic, magics_class
from IPython.display import display, Audio
from threading import Thread
from time import sleep
OUTPUT_AREA_CLASS = 'jp-OutputArea-child'
OUT_CLASS = 'jp-transient-html'
def delayed_close(out, element, delay):
sleep(delay)
element.close()
out.clear_output()
out.close()
def hide_closest(css_class):
return (
f"var widget_our = this.closest('.{OUT_CLASS}');"
f"var that = widget_our ? widget_our : this;"
f"that.closest('.{css_class}').style.display = 'none';"
)
class InvisibleAudio(Audio):
def _repr_html_(self):
audio = super()._repr_html_()
audio = audio.replace(
'<audio',
(
'<audio onended="'
+ hide_closest(css_class=OUTPUT_AREA_CLASS)
+ '" onloadstart="' + hide_closest(css_class=OUTPUT_AREA_CLASS) + '"'
)
)
return f'<div style="display:none">{audio}</div>'
def transient_html(code: str, lifetime: float = 3):
try:
from ipywidgets import HTML
from ipywidgets.widgets import Output
element = HTML(code)
out = Output()
out.add_class(OUT_CLASS)
thread = Thread(target=delayed_close, args=(out, element, lifetime))
with out:
display(element)
display(out)
thread.start()
except ImportError:
from IPython.display import HTML
element = HTML(code)
display(element)
@magics_class
class MyMagic(Magics):
@cell_magic
def finish_with_beep(self, line, cell):
self.shell.run_cell(cell)
sound_file = 'beep.wav'
audio = InvisibleAudio(filename='beep.wav', autoplay=True)
display(audio)
transient_html(audio._repr_html_())
ipy = get_ipython()
ipy.register_magics(MyMagic)
I’ve tried that, but sound is still coming when re-opening the notebook.
Maybe display(audio)
is the problem?
Yes, it’s either display
or transient_html
.
with only transient_html
there is no sound when running the cell, only this output:
Sorry, have not seen this. Do you have ipywidgets installed?
nope, I did not install them before, but now I have that.
The cells with cellmagic show now the message Loading widget...
for 3 seconds, and then the message disappears. But no sound still.
Lab or Notebook? Did you restart (fully) after installing ipywidgets?
Lab. And yes, full restart.