This is one of the 100 recipes of the IPython Cookbook, the definitive guide to high-performance scientific computing and data science in Python.

11.7. Creating a sound synthesizer in the notebook

  1. We import NumPy, matplotlib, and various IPython packages and objects.
In [ ]:
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import Audio, display, clear_output
from IPython.html import widgets
from functools import partial
import matplotlib as mpl
%matplotlib inline
  1. We define the sampling rate and the duration of the notes.
In [ ]:
rate = 16000.
duration = .5
t = np.linspace(0., duration, rate * duration)
  1. We create a function that generates and plays the sound of a note (sine function) at a given frequency, using NumPy and IPython's Audio class.
In [ ]:
def synth(f):
    x = np.sin(f * 2. * np.pi * t)
    display(Audio(x, rate=rate, autoplay=True))
  1. Here is the fundamental 440 Hz note.
In [ ]:
synth(440)
  1. Now, we generate the note frequencies of our piano. The chromatic scale is obtained by a geometric progression with common ratio $2^{1/12}$.
In [ ]:
keys = 'C,C#,D,D#,E,F,F#,G,G#,A,A#,B,C'.split(',')
notes = zip(keys, 440. * 2 ** (np.arange(3, 3 + len(keys)) / 12.))
  1. Finally, we create the piano with the notebook widgets. Each note is a button, and all buttons are contained in an horizontal box container. Clicking on one note plays a sound at the corresponding frequency.
In [ ]:
container = widgets.ContainerWidget()
buttons = []
for note, f in notes:
    button = widgets.ButtonWidget(description=note)
    def on_button_clicked(f, b):
        clear_output()
        synth(f)
    button.on_click(partial(on_button_clicked, f))
    button.set_css({'width': '30px', 
                    'height': '60px',
                    'padding': '0',
                    'color': ('black', 'white')['#' in note],
                    'background': ('white', 'black')['#' in note],
                    'border': '1px solid black',
                    'float': 'left'})
    buttons.append(button)
container.children = buttons
display(container)
container.remove_class('vbox')
container.add_class('hbox')

You'll find all the explanations, figures, references, and much more in the book (to be released later this summer).

IPython Cookbook, by Cyrille Rossant, Packt Publishing, 2014 (500 pages).