{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<h1><center>BirdCLEF-Birdcall Identification</center></h1>\n\n# 1. Introduction\n\n### Libraries 📚⬇","metadata":{}},{"cell_type":"code","source":"import os\nimport re\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n%matplotlib inline\nimport matplotlib.image as mpimg\nfrom matplotlib.offsetbox import AnnotationBbox, OffsetImage\n\n# Map 1 library\nimport plotly.express as px\n\n# Map 2 libraries\nimport descartes\nimport geopandas as gpd\nfrom shapely.geometry import Point, Polygon\n\n# Librosa Libraries\nimport librosa\nimport librosa.display\nimport IPython.display as ipd\n\nimport sklearn\n\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. The .csv files 📁\n\n> 📌**Note**:\n* `train.csv` contains information about the audio files available in `train_audio`. It contains 62,874 datapoints in 14 unique columns.\n* `test.csv` contains only 3 observations (the rest are available in the *hidden test set*).","metadata":{}},{"cell_type":"code","source":"# Import data\ntrain_csv = pd.read_csv(\"../input/birdclef-2021/train_metadata.csv\")\ntrain_labels = pd.read_csv(\"../input/birdclef-2021/train_soundscape_labels.csv\")\n\nprint(\"There are {:,} unique bird species in the dataset.\".format(len(train_csv['common_name'].unique())))","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_csv.shape","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### TEST.csv - let's take a look here as well before going further\n\n> 📌**Note**:\n* only 3 rows available (rest are in the hidden set)\n* `site`: there are 3 sites in total, with first 2 having labeles every 5 seconds, while site_3 has labels at file level.\n* `row_id`: this is the unique ID that will be used for the submission\n* `seconds`: how long the clip is\n* `audio_id`: `row_id` without site\n\n*PS: \"nocall\" can be also one of the labels (hearing no bird).*","metadata":{}},{"cell_type":"code","source":"# Inspect text_csv before checking train data\ntest_csv = pd.read_csv('../input/birdclef-2021/test.csv')\ntest_csv.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.1 Time of the Recording ⏰\n\n> 📌**Note**: \n* `0000` is for the dates 0000-00-00, which are unknown\n* `0202`, `0201`, `0199`, `2104` looks like an anomalous value","metadata":{}},{"cell_type":"code","source":"train_csv['year'] = train_csv['date'].apply(lambda x: x.split(\"-\")[0])\ntrain_csv['month'] = train_csv['date'].apply(lambda x: x.split(\"-\")[1])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(16, 6))\nax = sns.countplot(train_csv['year'].sort_values(ascending=False), palette=\"hls\")\n\nplt.title(\"Audio Files Registration per Year Made\", fontsize=16)\nplt.xticks(rotation=90, fontsize=13)\nplt.yticks(fontsize=13)\nplt.ylabel(\"Frequency\", fontsize=14)\nplt.xlabel(\"\");","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(16, 6))\nax = sns.countplot(train_csv['month'].sort_values(ascending=False), palette=\"hls\")\n\nplt.title(\"Audio Files Registration per Month Made\", fontsize=16)\nplt.xticks(fontsize=13)\nplt.yticks(fontsize=13)\nplt.ylabel(\"Frequency\", fontsize=14)\nplt.xlabel(\"\");","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2.2 The Songs\n\n**Type Column**:\n\n> 📌**Note**: This column is a bit messy, as the same description can be found under multiple names. Also, there can be multiple descriptions for multiple sounds (one bird song can mean a different thing from another one in the same recording). Some examples are:\n* **begging call** is: `begging call`, `call`, `juvenile` \n* **male call** is: `chimp call`, `male`, `song` etc.","metadata":{}},{"cell_type":"code","source":"# Create a new variable type by exploding all the values\nadjusted_type = train_csv['type'].apply(lambda x: x.split(',')).reset_index().explode(\"type\")\n\n# Strip of white spaces and convert to lower chars\nadjusted_type = adjusted_type['type'].apply(lambda x: x.strip().lower()).reset_index()\nadjusted_type['type'] = adjusted_type['type'].replace({'calls':'call'})\nadjusted_type['type'] = adjusted_type['type'].str.replace(r\"\\W\", \"\", regex=True)\n\n# Create Top 10 list with song types\ntop_10 = list(adjusted_type['type'].value_counts().head(10).reset_index()['index'])\ndata = adjusted_type[adjusted_type['type'].isin(top_10)]\n\nplt.figure(figsize=(16, 6))\nax = sns.countplot(data['type'], palette=\"hls\", order = data['type'].value_counts().index)\n\nplt.title(\"Top 10 Song Types\", fontsize=16)\nplt.ylabel(\"Frequency\", fontsize=14)\nplt.yticks(fontsize=13)\nplt.xticks(rotation=45, fontsize=13)\nplt.xlabel(\"\");","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. The Audio Files","metadata":{}},{"cell_type":"markdown","source":"## 3.1 Listening to some Recordings","metadata":{}},{"cell_type":"code","source":"# Create Full Path so we can access data more easily\nbase_dir = '../input/birdclef-2021/train_short_audio'\ntrain_csv['full_path'] = base_dir +  \"/\" + train_csv['primary_label'] + '/' + train_csv['filename']\n\n# Now let's sample a fiew audio files\namered = train_csv[train_csv['primary_label'] == \"btywar\"].sample(1, random_state = 33)['full_path'].values[0]\ncangoo = train_csv[train_csv['primary_label'] == \"solsan\"].sample(1, random_state = 33)['full_path'].values[0]\nhaiwoo = train_csv[train_csv['primary_label'] == \"tenwar\"].sample(1, random_state = 33)['full_path'].values[0]\npingro = train_csv[train_csv['primary_label'] == \"hutvir\"].sample(1, random_state = 33)['full_path'].values[0]\nvesspa = train_csv[train_csv['primary_label'] == \"wilsni1\"].sample(1, random_state = 33)['full_path'].values[0]\n\nbird_sample_list = [\"btywar\", \"solsan\", \"tenwar\", \"hutvir\", \"wilsni1\"]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3.4 Extracting Features from Sounds\n\n> The audio data is composed by:\n1. **Sound**: sequence of vibrations in varying pressure strengths (`y`)\n2. **Sample Rate**: (`sr`) is the number of samples of audio carried per second, measured in Hz or kHz","metadata":{}},{"cell_type":"code","source":"# Importing 1 file\ny, sr = librosa.load(amered)\n\nprint('y:', y, '\\n')\nprint('y shape:', np.shape(y), '\\n')\nprint('Sample Rate (KHz):', sr, '\\n')\n\n# Verify length of the audio\nprint('Check Len of Audio:', np.shape(y)[0]/sr)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Trim leading and trailing silence from an audio signal (silence before and after the actual audio)\naudio_file, _ = librosa.effects.trim(y)\n\n# the result is an numpy ndarray\nprint('Audio File:', audio_file, '\\n')\nprint('Audio File shape:', np.shape(audio_file))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Importing the 5 files\ny_amered, sr_amered = librosa.load(amered)\naudio_amered, _ = librosa.effects.trim(y_amered)\n\ny_cangoo, sr_cangoo = librosa.load(cangoo)\naudio_cangoo, _ = librosa.effects.trim(y_cangoo)\n\ny_haiwoo, sr_haiwoo = librosa.load(haiwoo)\naudio_haiwoo, _ = librosa.effects.trim(y_haiwoo)\n\ny_pingro, sr_pingro = librosa.load(pingro)\naudio_pingro, _ = librosa.effects.trim(y_pingro)\n\ny_vesspa, sr_vesspa = librosa.load(vesspa)\naudio_vesspa, _ = librosa.effects.trim(y_vesspa)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #1. Sound Waves (2D Representation)","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(5, figsize = (16, 9))\nfig.suptitle('Sound Waves', fontsize=16)\n\nlibrosa.display.waveplot(y = audio_amered, sr = sr_amered, color = \"#A300F9\", ax=ax[0])\nlibrosa.display.waveplot(y = audio_cangoo, sr = sr_cangoo, color = \"#4300FF\", ax=ax[1])\nlibrosa.display.waveplot(y = audio_haiwoo, sr = sr_haiwoo, color = \"#009DFF\", ax=ax[2])\nlibrosa.display.waveplot(y = audio_pingro, sr = sr_pingro, color = \"#00FFB0\", ax=ax[3])\nlibrosa.display.waveplot(y = audio_vesspa, sr = sr_vesspa, color = \"#D9FF00\", ax=ax[4]);\n\nfor i, name in zip(range(5), bird_sample_list):\n    ax[i].set_ylabel(name, fontsize=13)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #2. Fourier Transform 🥁\n\n> 📌**Note**: Function that gets a signal in the time domain as input, and outputs its decomposition into frequencies. Transform both the y-axis (frequency) to log scale, and the “color” axis (amplitude) to Decibels, which is approx. the log scale of amplitudes.","metadata":{}},{"cell_type":"code","source":"# Default FFT window size\nn_fft = 2048 # FFT window size\nhop_length = 512 # number audio of frames between STFT columns (looks like a good default)\n\n# Short-time Fourier transform (STFT)\nD_amered = np.abs(librosa.stft(audio_amered, n_fft = n_fft, hop_length = hop_length))\nD_cangoo = np.abs(librosa.stft(audio_cangoo, n_fft = n_fft, hop_length = hop_length))\nD_haiwoo = np.abs(librosa.stft(audio_haiwoo, n_fft = n_fft, hop_length = hop_length))\nD_pingro = np.abs(librosa.stft(audio_pingro, n_fft = n_fft, hop_length = hop_length))\nD_vesspa = np.abs(librosa.stft(audio_vesspa, n_fft = n_fft, hop_length = hop_length))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print('Shape of D object:', np.shape(D_amered))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(5, figsize = (16, 9))\nfig.suptitle('Sound Waves', fontsize=16)\n\nlibrosa.display.waveplot(y = D_amered, sr = sr_amered, color = \"#A300F9\", ax=ax[0])\nlibrosa.display.waveplot(y = D_cangoo, sr = sr_cangoo, color = \"#4300FF\", ax=ax[1])\nlibrosa.display.waveplot(y = D_haiwoo, sr = sr_haiwoo, color = \"#009DFF\", ax=ax[2])\nlibrosa.display.waveplot(y = D_pingro, sr = sr_pingro, color = \"#00FFB0\", ax=ax[3])\nlibrosa.display.waveplot(y = D_vesspa, sr = sr_vesspa, color = \"#D9FF00\", ax=ax[4]);\n\nfor i, name in zip(range(5), bird_sample_list):\n    ax[i].set_ylabel(name, fontsize=13)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #3. Spectrogram 🎷\n\n> 📌**Note**: \n* What is a spectrogram? A spectrogram is a visual representation of the spectrum of frequencies of a signal as it varies with time. When applied to an audio signal, spectrograms are sometimes called sonographs, voiceprints, or voicegrams (wiki).\n* Here we convert the frequency axis to a logarithmic one.","metadata":{}},{"cell_type":"code","source":"# Convert an amplitude spectrogram to Decibels-scaled spectrogram.\nDB_amered = librosa.amplitude_to_db(D_amered, ref = np.max)\nDB_cangoo = librosa.amplitude_to_db(D_cangoo, ref = np.max)\nDB_haiwoo = librosa.amplitude_to_db(D_haiwoo, ref = np.max)\nDB_pingro = librosa.amplitude_to_db(D_pingro, ref = np.max)\nDB_vesspa = librosa.amplitude_to_db(D_vesspa, ref = np.max)\n\n# === PLOT ===\nfig, ax = plt.subplots(2, 3, figsize=(16, 9))\nfig.suptitle('Spectrogram', fontsize=16)\nfig.delaxes(ax[1, 2])\n\nlibrosa.display.specshow(DB_amered, sr = sr_amered, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'cool', ax=ax[0, 0])\nlibrosa.display.specshow(DB_cangoo, sr = sr_cangoo, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'cool', ax=ax[0, 1])\nlibrosa.display.specshow(DB_haiwoo, sr = sr_haiwoo, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'cool', ax=ax[0, 2])\nlibrosa.display.specshow(DB_pingro, sr = sr_pingro, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'cool', ax=ax[1, 0])\nlibrosa.display.specshow(DB_vesspa, sr = sr_vesspa, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'cool', ax=ax[1, 1]);\n\nfor i, name in zip(range(0, 2*3), bird_sample_list):\n    x = i // 3\n    y = i % 3\n    ax[x, y].set_title(name, fontsize=13) ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #4. Mel Spectrogram 🎷\n> 📌**Note**: The Mel Scale, mathematically speaking, is the result of some non-linear transformation of the frequency scale. The Mel Spectrogram is a normal Spectrogram, but with a Mel Scale on the y axis.","metadata":{}},{"cell_type":"code","source":"# Create the Mel Spectrograms\nS_amered = librosa.feature.melspectrogram(y_amered, sr=sr_amered)\nS_DB_amered = librosa.amplitude_to_db(S_amered, ref=np.max)\n\nS_cangoo = librosa.feature.melspectrogram(y_cangoo, sr=sr_cangoo)\nS_DB_cangoo = librosa.amplitude_to_db(S_cangoo, ref=np.max)\n\nS_haiwoo = librosa.feature.melspectrogram(y_haiwoo, sr=sr_haiwoo)\nS_DB_haiwoo = librosa.amplitude_to_db(S_haiwoo, ref=np.max)\n\nS_pingro = librosa.feature.melspectrogram(y_pingro, sr=sr_pingro)\nS_DB_pingro = librosa.amplitude_to_db(S_pingro, ref=np.max)\n\nS_vesspa = librosa.feature.melspectrogram(y_vesspa, sr=sr_vesspa)\nS_DB_vesspa = librosa.amplitude_to_db(S_vesspa, ref=np.max)\n\n# === PLOT ====\nfig, ax = plt.subplots(2, 3, figsize=(16, 9))\nfig.suptitle('Mel Spectrogram', fontsize=16)\nfig.delaxes(ax[1, 2])\n\nlibrosa.display.specshow(S_DB_amered, sr = sr_amered, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'rainbow', ax=ax[0, 0])\nlibrosa.display.specshow(S_DB_cangoo, sr = sr_cangoo, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'rainbow', ax=ax[0, 1])\nlibrosa.display.specshow(S_DB_haiwoo, sr = sr_haiwoo, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'rainbow', ax=ax[0, 2])\nlibrosa.display.specshow(S_DB_pingro, sr = sr_pingro, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'rainbow', ax=ax[1, 0])\nlibrosa.display.specshow(S_DB_vesspa, sr = sr_vesspa, hop_length = hop_length, x_axis = 'time', \n                         y_axis = 'log', cmap = 'rainbow', ax=ax[1, 1]);\n\nfor i, name in zip(range(0, 2*3), bird_sample_list):\n    x = i // 3\n    y = i % 3\n    ax[x, y].set_title(name, fontsize=13)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #5. Zero Crossing Rate 🚷\n\n> 📌**Note**: the rate at which the signal changes from positive to negative or back.","metadata":{}},{"cell_type":"code","source":"# Total zero_crossings in our 1 song\nzero_amered = librosa.zero_crossings(audio_amered, pad=False)\nzero_cangoo = librosa.zero_crossings(audio_cangoo, pad=False)\nzero_haiwoo = librosa.zero_crossings(audio_haiwoo, pad=False)\nzero_pingro = librosa.zero_crossings(audio_pingro, pad=False)\nzero_vesspa = librosa.zero_crossings(audio_vesspa, pad=False)\n\nzero_birds_list = [zero_amered, zero_cangoo, zero_haiwoo, zero_pingro, zero_vesspa]\n\nfor bird, name in zip(zero_birds_list, bird_sample_list):\n    print(\"{} change rate is {:,}\".format(name, sum(bird)))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #6. Harmonics and Perceptrual 🎹\n\n> 📌**Note**: \n* Harmonics are characteristichs that represent the sound *color*\n* Perceptrual shock wave represents the sound *rhythm and emotion*","metadata":{}},{"cell_type":"code","source":"y_harm_haiwoo, y_perc_haiwoo = librosa.effects.hpss(audio_haiwoo)\n\nplt.figure(figsize = (16, 6))\nplt.plot(y_perc_haiwoo, color = '#FFB100')\nplt.plot(y_harm_haiwoo, color = '#A300F9')\nplt.legend((\"Perceptrual\", \"Harmonics\"))\nplt.title(\"Harmonics and Perceptrual : Haiwoo Bird\", fontsize=16);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #7. Spectral Centroid 🎯\n\n> 📌**Note**: \nIndicates where the ”centre of mass” for a sound is located and is calculated as the weighted mean of the frequencies present in the sound.","metadata":{}},{"cell_type":"code","source":"# Calculate the Spectral Centroids\nspectral_centroids = librosa.feature.spectral_centroid(audio_cangoo, sr=sr)[0]\n\n# Shape is a vector\nprint('Centroids:', spectral_centroids, '\\n')\nprint('Shape of Spectral Centroids:', spectral_centroids.shape, '\\n')\n\n# Computing the time variable for visualization\nframes = range(len(spectral_centroids))\n\n# Converts frame counts to time (seconds)\nt = librosa.frames_to_time(frames)\n\nprint('frames:', frames, '\\n')\nprint('t:', t)\n\n# Function that normalizes the Sound Data\ndef normalize(x, axis=0):\n    return sklearn.preprocessing.minmax_scale(x, axis=axis)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Plotting the Spectral Centroid along the waveform\nplt.figure(figsize = (16, 6))\nlibrosa.display.waveplot(audio_cangoo, sr=sr, alpha=0.4, color = '#A300F9', lw=3)\nplt.plot(t, normalize(spectral_centroids), color='#FFB100', lw=2)\nplt.legend([\"Spectral Centroid\", \"Wave\"])\nplt.title(\"Spectral Centroid: Cangoo Bird\", fontsize=16);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #8. Chroma Frequencies\n\n> 📌**Note**: Chroma features are an interesting and powerful representation for music audio in which the entire spectrum is projected onto 12 bins representing the 12 distinct semitones (or chromas) of the musical octave.","metadata":{}},{"cell_type":"code","source":"# Increase or decrease hop_length to change how granular you want your data to be\nhop_length = 5000\n\n# Chromogram Vesspa\nchromagram = librosa.feature.chroma_stft(audio_vesspa, sr=sr_vesspa, hop_length=hop_length)\nprint('Chromogram Vesspa shape:', chromagram.shape)\n\nplt.figure(figsize=(16, 6))\nlibrosa.display.specshow(chromagram, x_axis='time', y_axis='chroma', hop_length=hop_length, cmap='twilight')\n\nplt.title(\"Chromogram: Vesspa\", fontsize=16);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #9. Tempo BPM (beats per minute)🎤\n> 📌**Note**: Dynamic programming beat tracker.","metadata":{}},{"cell_type":"code","source":"# Create Tempo BPM variable\ntempo_amered, _ = librosa.beat.beat_track(y_amered, sr = sr_amered)\ntempo_cangoo, _ = librosa.beat.beat_track(y_cangoo, sr = sr_cangoo)\ntempo_haiwoo, _ = librosa.beat.beat_track(y_haiwoo, sr = sr_haiwoo)\ntempo_pingro, _ = librosa.beat.beat_track(y_pingro, sr = sr_pingro)\ntempo_vesspa, _ = librosa.beat.beat_track(y_vesspa, sr = sr_vesspa)\n\ndata = pd.DataFrame({\"Type\": bird_sample_list , \n                     \"BPM\": [tempo_amered, tempo_cangoo, tempo_haiwoo, tempo_pingro, tempo_vesspa] })\n\n# Plot\nplt.figure(figsize = (16, 6))\nax = sns.barplot(y = data[\"BPM\"], x = data[\"Type\"], palette=\"hls\")\n\nplt.ylabel(\"BPM\", fontsize=14)\nplt.yticks(fontsize=13)\nplt.xticks(fontsize=13)\nplt.xlabel(\"\")\nplt.title(\"BPM for 5 Different Bird Species\", fontsize=16);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### #10. Spectral Rolloff 🥏\n> 📌**Note**: Is a measure of the *shape of the signal*. It represents the frequency below which a specified percentage of the total spectral energy (e.g. 85%) lies.","metadata":{}},{"cell_type":"code","source":"# Spectral RollOff Vector\nspectral_rolloff = librosa.feature.spectral_rolloff(audio_amered, sr=sr_amered)[0]\n\n# Computing the time variable for visualization\nframes = range(len(spectral_rolloff))\n# Converts frame counts to time (seconds)\nt = librosa.frames_to_time(frames)\n\n# The plot\nplt.figure(figsize = (16, 6))\nlibrosa.display.waveplot(audio_amered, sr=sr_amered, alpha=0.4, color = '#A300F9', lw=3)\nplt.plot(t, normalize(spectral_rolloff), color='#FFB100', lw=3)\nplt.legend([\"Spectral Rolloff\", \"Wave\"])\nplt.title(\"Spectral Rolloff: Btywar Bird\", fontsize=16);","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}