{ "cells": [ { "cell_type": "markdown", "metadata": { "internals": { "slide_type": "subslide" }, "slideshow": { "slide_type": "slide" } }, "source": [ "The basic shape of ADSR is explained here: [http://dsp.stackexchange.com/questions/2555/help-with-equations-for-exponential-adsr-envelope](http://dsp.stackexchange.com/questions/2555/help-with-equations-for-exponential-adsr-envelope).\n", "\n", "In this post, we will implement two different types of ADSR: a linear one and an exponential one." ] }, { "cell_type": "markdown", "metadata": { "internals": {}, "slideshow": { "slide_type": "-" } }, "source": [ "How will we model our ADSR? We will only consider sound lengths between 0 and 1. Therefore, the periods of ADSR have to sum to 1. Our ADSR will therefore be coded by three points which will be computed by the parameters." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false, "internals": {}, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": 28, "metadata": { "collapsed": false, "internals": {}, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "class linear_ADSR:\n", " def __init__(self, attack_time, decay_time, sustain_time, release_time,\n", " attack_gain, sustain_gain):\n", " \"\"\"\n", " instantiates class for linear ADSR\n", " \"\"\"\n", " self.attack_time = attack_time\n", " self.decay_time = decay_time\n", " self.sustain_time = sustain_time\n", " self.release_time = release_time\n", " self.attack_gain = attack_gain\n", " self.sustain_gain = sustain_gain\n", " \n", " self.computed = False\n", " \n", " def compute_waveform(self):\n", " \"\"\"\n", " computes the waveform shape\n", " \"\"\"\n", " t = np.array([self.attack_time, self.decay_time, self.sustain_time, self.release_time])\n", " t = np.cumsum(t.astype(np.float))\n", " t /= t[-1]\n", " t = np.insert(t, 0, 0.)\n", " \n", " self.waveform = np.vstack((t,\n", " np.array([0., self.attack_gain, self.sustain_gain, self.sustain_gain, 0.])))\n", " \n", " def evaluate_waveform(self, t):\n", " \"\"\"\n", " allows one to evaluate the ADSR time filter at times t\n", " it is assumed that the time window goes from 0 to 1\n", " \"\"\"\n", " if not self.computed:\n", " self.compute_waveform()\n", " \n", " normalized_t = (t - t[0]) / (t[-1] - t[0])\n", " \n", " from scipy import interpolate\n", " interpolator = interpolate.interp1d(self.waveform[0, :], self.waveform[1, :],\n", " bounds_error=False,\n", " fill_value=0.,\n", " assume_sorted=True)\n", " return interpolator(normalized_t)\n", " \n", " def plot(self, ax, t):\n", " \"\"\"\n", " plots the waveform to the axis supplied to the method\n", " \"\"\"\n", " if not self.computed:\n", " self.compute_waveform()\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now test this class:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false, "internals": { "slide_helper": "subslide_end" }, "slide_helper": "slide_end", "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "lin_adsr = linear_ADSR(0.5, 1, 3, 1, 2, 1)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "collapsed": false }, "outputs": [], "source": [ "lin_adsr.compute_waveform()" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "array([[ 0. , 0.09090909, 0.27272727, 0.81818182, 1. ],\n", " [ 0. , 2. , 1. , 1. , 0. ]])" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin_adsr.waveform" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": true }, "outputs": [], "source": [ "t = np.linspace(0, 1, 300)" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false }, "outputs": [], "source": [ "wf = lin_adsr.evaluate_waveform(t)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 53, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\nSUVORK5CYII=\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "plt.plot(t, wf)" ] }, { "cell_type": "code", "execution_count": 68, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 68, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n/x+KKZ2duqMETgAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "t = np.linspace(1, 3, 200)\n", "wf = lin_adsr.evaluate_waveform(t)\n", "plt.plot(t, wf)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can convolve this shape with any pulse shape. Let's start with a sample sinusoid sound." ] }, { "cell_type": "code", "execution_count": 63, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f = 100\n", "sample_freq = 5000\n", "t = np.arange(0, 1, 1./sample_freq)\n", "snd = np.sin(2 * np.pi * f * t) * lin_adsr.evaluate_waveform(t)" ] }, { "cell_type": "code", "execution_count": 64, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 64, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.display import Audio\n", "Audio(snd, rate=sample_freq)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same thing can be done with a square wave." ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from scipy.signal import square" ] }, { "cell_type": "code", "execution_count": 66, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 66, "metadata": {}, "output_type": "execute_result" } ], "source": [ "snd = square(2 * np.pi * f * t) * lin_adsr.evaluate_waveform(t)\n", "Audio(snd, rate=sample_freq)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can build an interesting waveform using this:" ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lin_adsr = linear_ADSR(0.5, 2, 5, 0.5, 6, 1)\n", "f = 243\n", "sample_freq = 5000\n", "t = np.arange(0, 0.5, 1./sample_freq) \n", "wf1 = square(2 * np.pi * f * t) * lin_adsr.evaluate_waveform(t)\n", "wf2 = square(2 * np.pi * 0.8 * f * t) * lin_adsr.evaluate_waveform(t)\n", "snd = np.concatenate((wf1, wf1, wf1, wf2))\n", "Audio(snd, rate=sample_freq)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Building upon the previous code, we can program a nice sounding exponential ADSR. The trick is to change the way of evaluating the waveform and to plugin an exponential waveform. A general formula for the **increasing** exponential waveform is as follows:\n", "\n", "$$\n", "s(t) = A \\left( 1 - \\exp(-\\frac{t}{\\tau}) \\right)\n", "$$\n", "\n", "in this expression $A$ is the target amplitude and $\\tau$ is the time constant chosen so that $5 \\tau$ is equal to the time interval of the given phase (attack, delay, sustain, release).\n", "\n", "A general formula for the **decreasing** exponential waveform is as follows:\n", "\n", "$$\n", "s(t) = A \\exp(-\\frac{t}{\\tau})\n", "$$\n" ] }, { "cell_type": "code", "execution_count": 105, "metadata": { "collapsed": false }, "outputs": [], "source": [ "class exponential_ADSR(linear_ADSR):\n", " def evaluate_waveform(self, t):\n", " \"\"\"\n", " allows one to evaluate the ADSR time filter at times t\n", " it is assumed that the time window goes from 0 to 1\n", " \"\"\"\n", " if not self.computed:\n", " self.compute_waveform()\n", " \n", " t = (t - t[0]) / (t[-1] - t[0])\n", " \n", " a = t < self.waveform[0, 1]\n", " d = (t > self.waveform[0, 1]) & (t < self.waveform[0, 2])\n", " s = (t > self.waveform[0, 2]) & (t < self.waveform[0, 3])\n", " r = t > self.waveform[0, 3]\n", " \n", " delta_t = self.waveform[0, 1:] - self.waveform[0, 0:-1]\n", " amps = self.waveform[1, 1:4]\n", " \n", " return np.ones_like(t) * (a * amps[0] * (1 - np.exp(-t / delta_t[0] * 5.)) + \\\n", " d * ((amps[0] - amps[1]) * np.exp(-(t - t[d][0]) / delta_t[1] * 5.) + amps[1]) + \\\n", " s *(amps[1]) + \\\n", " r * (amps[2] * np.exp(-(t - t[r][0]) / delta_t[2] * 5.)))" ] }, { "cell_type": "code", "execution_count": 125, "metadata": { "collapsed": false }, "outputs": [], "source": [ "expo_adsr = exponential_ADSR(1, 1, 2, 2, 3, 1)" ] }, { "cell_type": "code", "execution_count": 126, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[]" ] }, "execution_count": 126, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\nQQAAAABJRU5ErkJggg==\n", "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "t = np.linspace(0, 1, 200)\n", "wf = expo_adsr.evaluate_waveform(t)\n", "plt.plot(t, wf)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Again, let's test the different signals:" ] }, { "cell_type": "code", "execution_count": 127, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 127, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = 100\n", "sample_freq = 5000\n", "t = np.arange(0, 1, 1./sample_freq)\n", "snd = np.sin(2 * np.pi * f * t) * expo_adsr.evaluate_waveform(t)\n", "Audio(snd, rate=sample_freq)" ] }, { "cell_type": "code", "execution_count": 128, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 128, "metadata": {}, "output_type": "execute_result" } ], "source": [ "snd = square(2 * np.pi * f * t) * expo_adsr.evaluate_waveform(t)\n", "Audio(snd, rate=sample_freq)" ] }, { "cell_type": "code", "execution_count": 129, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 129, "metadata": {}, "output_type": "execute_result" } ], "source": [ "expo_adsr = exponential_ADSR(0.5, 5, 5, 0.5, 4, 1)\n", "f = 243\n", "sample_freq = 5000\n", "t = np.arange(0, 0.5, 1./sample_freq) \n", "wf1 = square(2 * np.pi * f * t) * expo_adsr.evaluate_waveform(t)\n", "wf2 = square(2 * np.pi * 0.8 * f * t) * expo_adsr.evaluate_waveform(t)\n", "snd = np.concatenate((wf1, wf1, wf1, wf2))\n", "Audio(snd, rate=sample_freq)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's apply the knowledge of waveforms we gained to playing nice little melodies:" ] }, { "cell_type": "code", "execution_count": 139, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import re\n", "from IPython.display import Audio, display\n", "\n", "def play_melody(melody, adsr, sample_freq=10.e3, bpm=50):\n", " duration = re.compile(\"^[0-9]+\")\n", " pitch = re.compile(\"[\\D]+[\\d]*\") \n", " measure_duration = 4 * 60. / bpm #usually it's 4/4 measures\n", " output = np.zeros((0,))\n", " for note in melody.split(','):\n", " # regexp matching\n", " duration_match = duration.findall(note)\n", " pitch_match = pitch.findall(note)\n", " \n", " # duration \n", " if len(duration_match) == 0:\n", " t_max = 1/4.\n", " else:\n", " t_max = 1/float(duration_match[0])\n", " if \".\" in pitch_match[0]:\n", " t_max *= 1.5\n", " pitch_match[0] = \"\".join(pitch_match[0].split(\".\"))\n", " t_max = t_max * measure_duration\n", " \n", " # pitch\n", " if pitch_match[0] == 'p':\n", " freq = 0\n", " else:\n", " if pitch_match[0][-1] in [\"4\", \"5\", \"6\", \"7\"]: # octave is known\n", " octave = [\"4\", \"5\", \"6\", \"7\"].index(pitch_match[0][-1]) + 4 \n", " height = pitch_match[0][:-1]\n", " else: # octave is not known\n", " octave = 5\n", " height = pitch_match[0]\n", " freq = 261.626 * 2 ** (([\"c\", \"c#\", \"d\", \"d#\", \"e\", \"f\", \"f#\", \"g\", \"g#\", \"a\", \"a#\", \"b\"].index(height) / 12. + octave - 4)) \n", " \n", " # generate sound\n", " t = np.arange(0, t_max, 1/sample_freq)\n", " wave = square(2 *np. pi * freq * t) * adsr.evaluate_waveform(t)\n", " \n", " # append to output\n", " output = np.hstack((output, wave))\n", " \n", " display(Audio(output, rate=sample_freq)) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have modified the function [from this post](http://flothesof.github.io/gameboy-sounds-in-python.html) to allow for a changing envelope function." ] }, { "cell_type": "code", "execution_count": 140, "metadata": { "collapsed": true }, "outputs": [], "source": [ "tetris = \"e6,8b,8c6,8d6,16e6,16d6,8c6,8b,a,8a,8c6,e6,8d6,8c6,b,8b,8c6,d6,e6,c6,a,2a,8p,d6,8f6,a6,8g6,8f6,e6,8e6,8c6,e6,8d6,8c6,b,8b,8c6,d6,e6,c6,a,a\"" ] }, { "cell_type": "code", "execution_count": 141, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "play_melody(tetris, lin_adsr, bpm=140)" ] }, { "cell_type": "code", "execution_count": 142, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "play_melody(tetris, expo_adsr, bpm=140)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.8" } }, "nbformat": 4, "nbformat_minor": 0 }