在IPython笔记本中自动播放声音

67

我经常在IPython笔记本中运行长时间的单元格。 我希望当单元格执行完毕时,笔记本自动发出哔哔声或播放声音。 在iPython笔记本中有没有这样做的方法,或者可以在单元格末尾放置某个命令来自动播放声音?

如果需要区分,我使用的是Chrome浏览器。


可能是使用Python播放声音的重复问题。 - agconti
请查看 Waylon Finn 的回答,了解最新的 iPython 笔记本版本中的内置方法。 - Seanny123
请参考以下链接 https://dev59.com/3mQm5IYBdhLWcg3w0Bm5#50569680,了解如何自动发出警报声(如果任何单元格的执行时间超过指定时间),而不需要在单元格末尾添加任何代码。 - krassowski
@mic,我认为你想链接到这个页面:当执行/命令完成时通知,而不小心链接回了这个问题。 - NichtJens
9个回答

73

简要概述

在你的笔记本顶部

from IPython.display import Audio
sound_file = './sound/beep.wav'
sound_file 应该指向您计算机上的文件,或者可从互联网访问。
然后,在长时间运行的单元格结束时。
<code that takes a long time>

Audio(sound_file, autoplay=True)

这种方法使用内置于新版本iPython/Jupyter中的Audio标签。

旧版本注意事项

没有Audio标签的旧版本可以使用以下方法:

将以下代码放入单元格并在播放声音之前运行它:

from IPython.display import HTML
from base64 import b64encode

path_to_audio = "/path/to/snd/my-sound.mp3"
audio_type = "mp3"

sound = open(path_to_audio, "rb").read()
sound_encoded = b64encode(sound)
sound_tag = """
    <audio id="beep" controls src="data:audio/{1};base64,{0}">
    </audio>""".format(sound_encoded, audio_type)

play_beep = """
<script type="text/javascript">
    var audio = document.getElementById("beep");
    audio.play();
</script>
"""

HTML(sound_tag)

如果您想在单元格完成时发出声音,请将以下代码放在末尾:

Sub BeepOnCompletion()
    Beep
End Sub
HTML(play_beep)

它的工作原理:

使用iPython内置的openread方法从文件系统读取文件。然后将其编码为base64格式。接着创建一个ID为beep的音频标签,并将base64数据注入其中。最后创建一个小的脚本标签,用于播放声音。

这种方法应该适用于支持HTML5音频标签的任何浏览器。

注意:如果您不想在笔记本中显示音频控件,只需从名为sound_tag的变量中删除controls属性即可。


22
除了查找声音文件外,您还可以指定一个numpy数组:wave = np.sin(2*np.pi*400*np.arange(10000*2)/10000),然后使用 Audio(wave, rate=10000, autoplay=True) 播放一个采样率为10000的400Hz正弦波,持续时间为2秒。 - S.A.
2
类似于这样,您可以让Jupyter笔记本发声并说“完成”。请参阅Peter Parente的帖子此处 - Wayne
1
我只需将 notify=Audio(sound_file, autoplay=True) 赋值,然后在每个长时间运行的单元格末尾加上 notify 以播放音乐。 - Vijayabhaskar J
在Jupyterlab 3.0.3中,我必须将sound_file作为关键字参数传递:Audio(filename=sound_file, autoplay=True)。 - sgillen
这能作为单元格魔法吗? - alancalvitti

27

我最喜欢的解决方案(无需外部模块):

import os
os.system("printf '\a'") # or '\7'

可在OS X上使用。

然而,DaveP的评论仍然适用:播放声音的不是浏览器,而是服务器。


3
如果您已经[禁用了系统蜂鸣声],@Seanny123将无法工作。 - jadelord
这太棒了!有没有办法改变声音? - RHaguiuda
1
@RHaguiuda \a 被称为 响铃字符。在 OS X 中,它会播放系统警告声音,您可以在“系统偏好设置”中更改。我不知道其他平台的情况。 - Arthur

15

以下是另一个版本(主要是Python端),可与JupyterLab良好配合使用:

from time import time
from IPython import get_ipython
from IPython.display import Audio, display


class Beeper:

    def __init__(self, threshold, **audio_kwargs):
        self.threshold = threshold
        self.start_time = None    # time in sec, or None
        self.audio = audio_kwargs

    def pre_execute(self):
        if not self.start_time:
            self.start_time = time()

    def post_execute(self):
        end_time = time()
        if self.start_time and end_time - self.start_time > self.threshold:
            audio = Audio(**self.audio, autoplay=True)
            display(audio)
        self.start_time = None


beeper = Beeper(5, url='http://www.soundjay.com/button/beep-07.wav')

ipython = get_ipython()
ipython.events.register('pre_execute', beeper.pre_execute)
ipython.events.register('post_execute', beeper.post_execute)

每次代码执行时间超过5秒钟时,会自动发出蜂鸣声,但连续的执行不会被计算在一起。

例如:

# cell 0:
from time import sleep
# cell 1:
sleep(6)    # will ring

如果您添加了另一个单元格。
# cell 3:
sleep(3)    # it won't ring

已测试可与JupyterLab 0.32.1和Jupyter笔记本5.5.0兼容。

编辑:为了减少显示的音频播放器的混乱,我使用以下代码片段(对于版本低于3.6的Python,您需要使用.format()而不是f-strings):

from IPython.display import Audio, display


class InvisibleAudio(Audio):
    def _repr_html_(self):
        audio = super()._repr_html_()
        audio = audio.replace('<audio', f'<audio onended="this.parentNode.removeChild(this)"')
        return f'<div style="display:none">{audio}</div>'

然后在post_execute中使用InvisibleAudio代替Audio


你在JupyterLab中找到了一种播放音频而不显示音频控件的方法吗?编辑:来自这里的解决方案有效:display(HTML("<style>audio{display:none}</style>"))。但是,它确实会留下比没有输出的单元格更大的空白输出区域。 - Nathan
1
@Nathan - 当然,我将我的方法添加到答案中。这种方式更好,因为它不会隐藏笔记本中的每个音频播放器,而只隐藏那些是蜂鸣器的播放器。 - krassowski
这非常有用,应该默认在jupyter notebook环境中出现!谢谢 - sandeepsign

8

如果代码执行时间超过给定的时间,那么只需输入一次代码并在每个单元格执行后使其运行即可怎么办?

只需创建并执行一个带有以下JavaScript的单元格(调整超时和声音)即可。

%%javascript
(function(){
    var startTime;
    $([Jupyter.events]).on('execute.CodeCell', function(event, target)
    {
        startTime = performance.now();
    });
    $([Jupyter.events]).on('finished_iopub.Kernel', function(event, target)
    {
        var endTime = performance.now();

        if(endTime - startTime > 5 * 1000)
        {
            var audio = new Audio('http://www.soundjay.com/button/beep-07.wav');
            audio.play();    
        }
    });
})()

之后,您应该在执行每个需要超过5秒的代码后听到“滴哒”声。例如:

# cell 0:
from time import sleep
# cell 1:
sleep(6)    # will ring

如果您添加了另一个单元格,则需要调整所有其他单元格的大小以适应新单元格。
# cell 3:
sleep(3)    # it won't ring

除非您一次执行多个单元格:
# cell 4:
sleep(3)
# cell 5:
sleep(3)    # will ring if queued for execution after cell 4

本代码已在Jupyter notebook 5.5.0测试通过。

该代码可能需要进一步改进(欢迎编辑)。要在Google Colab上运行它,需要自己加载jQuery。似乎还不能在JupyterLab上使用。

要关闭,请使用:

%%javascript
// a slightly better version would unbind only the handlers defined above 
$([Jupyter.events]).unbind('execute.CodeCell')
$([Jupyter.events]).unbind('finished_iopub.Kernel')

您也可以使用base64编码的蜂鸣声(请参见此答案此代码片段):

var audio = new Audio('data:audio/wav;base64,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qJrx4KOQjahZxWbcZgztj2c49nKmkId44S71j0c8eV9yDK6uPRzx5X18eDvjvQ6yKo9ZSS6l//8elePK/Lf//IInrOF/FvDoADYAGBMGb7FtErm5MXMlmPAJQVgWta7Zx2go+8xJ0UiCb8LHHdftWyLJE0QIAIsI+UbXu67dZMjmgDGCGl1H+vpF4NSDckSIkk7Vd+sxEhBQMRU8j/12UIRhzSaUdQ+rQU5kGeFxm+hb1oh6pWWmv3uvmReDl0UnvtapVaIzo1jZbf/pD6ElLqSX+rUmOQNpJFa/r+sa4e/pBlAABoAAAAA3CUgShLdGIxsY7AUABPRrgCABdDuQ5GC7DqPQCgbbJUAoRSUj+NIEig0YfyWUho1VBBBA//uQZB4ABZx5zfMakeAAAAmwAAAAF5F3P0w9GtAAACfAAAAAwLhMDmAYWMgVEG1U0FIGCBgXBXAtfMH10000EEEEEECUBYln03TTTdNBDZopopYvrTTdNa325mImNg3TTPV9q3pmY0xoO6bv3r00y+IDGid/9aaaZTGMuj9mpu9Mpio1dXrr5HERTZSmqU36A3CumzN/9Robv/Xx4v9ijkSRSNLQhAWumap82WRSBUqXStV/YcS+XVLnSS+WLDroqArFkMEsAS+eWmrUzrO0oEmE40RlMZ5+ODIkAyKAGUwZ3mVKmcamcJnMW26MRPgUw6j+LkhyHGVGYjSUUKNpuJUQoOIAyDvEyG8S5yfK6dhZc0Tx1KI/gviKL6qvvFs1+bWtaz58uUNnryq6kt5RzOCkPWlVqVX2a/EEBUdU1KrXLf40GoiiFXK///qpoiDXrOgqDR38JB0bw7SoL+ZB9o1RCkQjQ2CBYZKd/+VJxZRRZlqSkKiws0WFxUyCwsKiMy7hUVFhIaCrNQsKkTIsLivwKKigsj8XYlwt/WKi2N4d//uQRCSAAjURNIHpMZBGYiaQPSYyAAABLAAAAAAAACWAAAAApUF/Mg+0aohSIRobBAsMlO//Kk4soosy1JSFRYWaLC4qZBYWFRGZdwqKiwkNBVmoWFSJkWFxX4FFRQWR+LsS4W/rFRb/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////VEFHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU291bmRib3kuZGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjAwNGh0dHA6Ly93d3cuc291bmRib3kuZGUAAAAAAAAAACU=');

7
你可以使用 Python 的外部模块。尝试在单元格末尾添加来自 Snack 音频工具包的 s.play() 调用即可。Snack 音频工具包 可以播放 wav、au 和 mp3 文件。
s = Sound() 
s.read('sound.wav') 
s.play()

这个问题基本上是一个重复问题: 使用Python播放声音
上面的代码片段来自那个问题中的@csexton。

7
这是一个不错的回答,但它的问题在于它会在运行笔记本服务器的机器上播放声音,这可能与显示笔记本的机器不同。肯定有办法让浏览器播放声音。 - DaveP

4
如果您不想依赖任何“外部模块”,您可以只使用此 Python 笔记本中的代码片段。您可以在第一个单元格之后连续运行此单元格,在当前运行单元格执行完成后发出“嘟嘟声”。
from IPython.display import Audio
import numpy as np

beep = np.sin(2*np.pi*400*np.arange(30000*2)/10000)
Audio(beep, rate=10000, autoplay=True)

2

荣誉提及。

我曾多次寻找这个特定的答案,但在这里找不到。

winsound.Beep(freq, time_in_millisec)

I use:

winsound.Beep(300, 200)
winsound.Beep(300, 200)
winsound.Beep(300, 700)

先导入winsound:from winsound import Beep,然后使用Beep(1000,1000)。这里有一个链接可以播放用蜂鸣声制作的超级马里奥音乐 - kotchwane

2

参考@krassowski的回答,这是我的解决方案。主要区别在于@krassowski的解决方案在每个“长”单元格执行(您定义了什么是“长”)之后运行;我更喜欢明确地说明我想要播放声音的时间,因此我将其包装成了一种行/单元格魔法(位于GitHub上并复制如下):

"""
Adds a magic to IPython which will play a given sound when a cell finishes running.
Requires Python 3.6+.
Put this file in, e.g., ~/.ipython/profile_default/startup to load this magic on startup.

Usage:
``
%notify [-u/--url URL] [command]
``

Examples
``
%notify # no command needed
%notify run_long_command()
%notify -u https://www.example.com/sound.wav run_long_command()
``

There's also a cell magic version (don't put commands on the first line if using this).
``
%%notify [-u/--url URL]
command1()
command2()
...
``

To always play your preferred audio file, just change the default below.
"""

from typing import Optional
from IPython import get_ipython
from IPython.display import Audio, display
from IPython.core.magic import line_cell_magic, Magics, magics_class
from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring


class _InvisibleAudio(Audio):
    """
    An invisible (`display: none`) `Audio` element which removes itself when finished playing.
    Taken from https://dev59.com/3mQm5IYBdhLWcg3w0Bm5#50648266.
    """

    def _repr_html_(self) -> str:
        audio = super()._repr_html_()
        audio = audio.replace(
            "<audio", '<audio onended="this.parentNode.removeChild(this)"'
        )
        return f'<div style="display:none">{audio}</div>'


@magics_class
class NotificationMagics(Magics):
    """
    Inspired by https://dev59.com/3mQm5IYBdhLWcg3w0Bm5#50648266.
    """

    @magic_arguments()
    @argument(
        "-u",
        "--url",
        default="https://freewavesamples.com/files/E-Mu-Proteus-FX-CosmoBel-C3.wav",
        help="URL of audio file to play.",
    )
    @argument(
        "line_code",
        nargs="*",
        help="Other code on the line will be executed, unless this is called as a cell magic.",
    )
    @line_cell_magic
    def notify(self, line: str, cell: Optional[str] = None):
        args = parse_argstring(self.notify, line)

        code = cell if cell else " ".join(args.line_code)
        try:
            ret = self.shell.ex(code)
        finally:
            audio = _InvisibleAudio(url=args.url, autoplay=True)
            display(audio)

        return ret


get_ipython().register_magics(NotificationMagics)

1
有一些不同的方法,基于krassowski's solution:只有在没有更多的单元格等待执行时才播放声音。 将此代码复制到一个单元格中,并运行一次即可:
%%javascript
(function(){ // ding after some cell(s) was running for more than 5 s
    var startTime = performance.now();
    var running = 0;
    $([Jupyter.events]).on('execute.CodeCell', function(event, target)
    {
        startTime = performance.now();
    });
    
    $([Jupyter.events]).on('finished_execute.CodeCell', function(event, target)
    {
        var endTime = performance.now();   
        //console.log(`elapsed time from last run command [ms] ${endTime - startTime}` );
        if(endTime - startTime > 5 * 1000)
         {
             // check how many running cells there are based on their css class
             // changing this class is asynchronous and may take a while
             // --> introduce 200 ms delay to get the correct reading
             // (if last cell(s) take less than 200 ms the sound will be played multiple times)
             setTimeout(() => {  
                 var running = document.querySelectorAll('.running');
                 //console.log(`remaining running cells: ${running.length}`);             
                 if(running.length == 0){
                     var audio = new Audio("data:audio/mpeg;base64,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");
                     audio.play(); 
                 };
              }, 200);   
         } 
    }); 
})()

区别在于它根据单元格的 CSS 类检查剩余排队单元格的数量,并仅在没有更多要运行的单元格时播放声音。
# cell 0:
from time import sleep
sleep(6)
# cell 1:
sleep(6)    # will ring only once if queued for execution

请注意,脚本使用最后一个执行请求启动计时器,因此如果您在前一个单元格完成之前排队了一个单元格,则不会响铃。
# cell 2:
sleep(6)
# cell 3: 
sleep(2)  # queued right after cell 2
# cell 4:
sleep(2)  # will NOT ring if queued during execution of cell 3 (after cell 2 is finished)   

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接