{
 "metadata": {
  "name": "",
  "signature": "sha256:706819cbfd628467abd31053a3a79b207af8b6252602c25509eeb930fe9f9063"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "heading",
     "level": 1,
     "metadata": {},
     "source": [
      "Tonal Descriptors: Pitch and Chroma"
     ]
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Load *Zigeunerweisen* by Pablo de Sarasate."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from urllib import urlretrieve\n",
      "urlretrieve('https://ccrma.stanford.edu/workshops/mir2014/audio/prelude_cmaj_10s.wav', filename='prelude_cmaj_10s.wav')\n",
      "urlretrieve('https://ccrma.stanford.edu/workshops/mir2014/audio/T08-violin-8k.wav', filename='violin.wav')\n",
      "\n",
      "from essentia.standard import MonoLoader\n",
      "audio = MonoLoader(filename='violin.wav')()\n",
      "\n",
      "from IPython.display import Audio\n",
      "fs = 44100.0\n",
      "Audio(audio, rate=fs)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "html": [
        "\n",
        "                <audio controls=\"controls\" >\n",
        "                    <source src=\"data:audio/wav;base64,[encoded data, 2121460 characters]\" type=\"audio/wav\" />\n",
        "                    Your browser does not support the audio element.\n",
        "                </audio>\n",
        "              "
       ],
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 67,
       "text": [
        "<IPython.lib.display.Audio at 0x3bdc110>"
       ]
      }
     ],
     "prompt_number": 67
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Compute onsets, play audio signal with onsets superimposed."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from essentia.standard import PitchSalience, PredominantMelody, \\\n",
      "        PitchYinFFT, FrameGenerator, OnsetRate, AudioOnsetsMarker, \\\n",
      "        HPCP, TuningFrequency, Key, ChordsDetection, ChordsDescriptors\n",
      "\n",
      "onset_gen = OnsetRate()\n",
      "onset_times, onset_rate = onset_gen(audio)\n",
      "onset_samples = (onset_times*fs).astype(int)\n",
      "#print onset_times\n",
      "#print onset_rate\n",
      "aom = AudioOnsetsMarker(onsets=onset_times)\n",
      "audio_with_onsets = aom(audio)\n",
      "\n",
      "Audio(audio_with_onsets, rate=fs)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "html": [
        "\n",
        "                <audio controls=\"controls\" >\n",
        "                    <source src=\"data:audio/wav;base64,[encoded data, 2121460 characters]\" type=\"audio/wav\" />\n",
        "                    Your browser does not support the audio element.\n",
        "                </audio>\n",
        "              "
       ],
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 68,
       "text": [
        "<IPython.lib.display.Audio at 0x3bdc2d0>"
       ]
      }
     ],
     "prompt_number": 68
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Compute a pitch for each onset-bounded segment."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "from essentia.standard import Spectrum\n",
      "spectrum = Spectrum()\n",
      "\n",
      "bounds = append(onset_times, (len(audio)/fs))\n",
      "print bounds.shape\n",
      "print type(bounds)\n",
      "bounds_samples = (bounds*fs).astype(int)\n",
      "\n",
      "pitches = []\n",
      "\n",
      "def hz2midi(hz):\n",
      "    return 69 + 12*log2(hz/440.0)\n",
      "\n",
      "for i in range(len(bounds)-1):\n",
      "    seg_start = bounds_samples[i]\n",
      "    seg_end = bounds_samples[i+1]\n",
      "    seg = audio[seg_start:seg_end]\n",
      "    frame_sz = len(seg)\n",
      "    \n",
      "    if frame_sz % 2 == 1:\n",
      "        seg = seg[:-1]\n",
      "        frame_sz = len(seg)\n",
      "    \n",
      "    yin = PitchYinFFT(frameSize = frame_sz)\n",
      "    pitch, pitch_conf = yin(spectrum(seg))\n",
      "    pitches.append([pitch, frame_sz])\n",
      "\n",
      "midi_pitches = [[hz2midi(f[0]), f[1]/fs] for f in pitches]\n",
      "#print midi_pitches"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "(33,)\n",
        "<type 'numpy.ndarray'>\n"
       ]
      }
     ],
     "prompt_number": 69
    },
    {
     "cell_type": "markdown",
     "metadata": {},
     "source": [
      "Synthesize a new signal comprised of pure sinusoids using the extracted midi pitch values and note durations."
     ]
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def midi2hz(midi):\n",
      "    return 440*2**((midi-69)/12.0)\n",
      "\n",
      "def synth(midi, T, fs):\n",
      "    \n",
      "    f0 = midi2hz(midi)\n",
      "    #print midi, f0\n",
      "    N = int(T*fs)\n",
      "    n = arange(N)\n",
      "    t = n/float(fs)\n",
      "    return t, sin(2*pi*f0*t)\n",
      "\n",
      "t, y = synth(60, 0.01, fs)\n",
      "plot(t, y)\n",
      "\n",
      "z = concatenate([synth(int(p[0]), p[1], fs)[1] for p in midi_pitches])\n",
      "\n",
      "audio_trim = audio[len(audio)-len(z):]\n",
      "z_stereo = array([z, audio_trim])\n",
      "#print z.shape, type(z)\n",
      "#print audio.shape\n",
      "#print audio_trim.shape, type(audio_trim)\n",
      "#print z_stereo.shape\n",
      "Audio(z_stereo.sum(axis=0), rate=fs)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "html": [
        "\n",
        "                <audio controls=\"controls\" >\n",
        "                    <source src=\"data:audio/wav;base64,[encoded data, 2120048 characters]\" type=\"audio/wav\" />\n",
        "                    Your browser does not support the audio element.\n",
        "                </audio>\n",
        "              "
       ],
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 70,
       "text": [
        "<IPython.lib.display.Audio at 0x3c054d0>"
       ]
      },
      {
       "metadata": {},
       "output_type": "display_data",
       "png": "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\nH4l4LBJCagwUAAAAAElFTkSuQmCC\n",
       "text": [
        "<matplotlib.figure.Figure at 0x3b3f310>"
       ]
      }
     ],
     "prompt_number": 70
    }
   ],
   "metadata": {}
  }
 ]
}