{"cells":[{"metadata":{},"cell_type":"markdown","source":"**This notebook made from [Theo Viel](https://www.kaggle.com/theoviel)'s [notebook](https://www.kaggle.com/theoviel/spectrogram-generation) and [discussion](https://www.kaggle.com/c/rfcx-species-audio-detection/discussion/198048).**\nThanks.\n\n\nI try to remove noise by using the Sound Envelope from the [previous competition discussion](https://www.kaggle.com/c/birdsong-recognition/discussion/169582#946072).  \nThis notebook generates denoised spectrograms.  \nThe calculated dataset is [here](https://www.kaggle.com/takamichitoda/rfcx-denoise-melspec)."},{"metadata":{},"cell_type":"markdown","source":"# Install denoise library"},{"metadata":{},"cell_type":"markdown","source":"I use [noisereduce library](https://pypi.org/project/noisereduce/)."},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!pip install noisereduce","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Import Python Library"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport shutil\nimport  joblib\nimport numpy as np\nimport pandas as pd\nimport librosa as lb\nimport librosa.display\nimport matplotlib.pyplot as plt\n\nfrom pathlib import Path\nfrom tqdm.notebook import tqdm\nimport IPython.display\n\nimport noisereduce as nr\nfrom matplotlib import pyplot as plt\nfrom scipy.ndimage import maximum_filter1d","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"DATA_ROOT = Path(\"../input/rfcx-species-audio-detection\")\nTRAIN_AUDIO_ROOT = Path(\"../input/rfcx-species-audio-detection/train\")\nTEST_AUDIO_ROOT = Path(\"../input/rfcx-species-audio-detection/test\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.DataFrame({\n    \"recording_id\": [path.stem for path in Path(TRAIN_AUDIO_ROOT).glob(\"*.flac\")],\n})\n\ndf_test = pd.DataFrame({\n    \"recording_id\": [path.stem for path in Path(TEST_AUDIO_ROOT).glob(\"*.flac\")],\n})","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Tools"},{"metadata":{"trusted":true},"cell_type":"code","source":"class params:\n    \"\"\"\n    Parameters used for the audio data\n    \"\"\"\n    sr = 32000\n\n    # Melspectrogram\n    n_mels = 128\n    fmin = 20\n    fmax = sr // 2  # Shannon theorem","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_audio(record, sr=16000, root=\"\"):\n    y, _ = lb.load(\n        root.joinpath(record).with_suffix(\".flac\").as_posix(),\n        sr=sr, \n    )\n    return y","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def compute_melspec(y, params):\n    \"\"\"\n    Computes a mel-spectrogram and puts it at decibel scale\n    Arguments:\n        y {np array} -- signal\n        params {AudioParams} -- Parameters to use for the spectrogram. Expected to have the attributes sr, n_mels, f_min, f_max\n    Returns:\n        np array -- Mel-spectrogram\n    \"\"\"\n    melspec = lb.feature.melspectrogram(\n        y, sr=params.sr, n_mels=params.n_mels, fmin=params.fmin, fmax=params.fmax,\n    )\n\n    melspec = lb.power_to_db(melspec).astype(np.float32)\n    return melspec","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Example"},{"metadata":{},"cell_type":"markdown","source":"original sound"},{"metadata":{"trusted":true},"cell_type":"code","source":"y = load_audio(df_train[\"recording_id\"][0], params.sr, TRAIN_AUDIO_ROOT)\nIPython.display.Audio(y, rate=params.sr)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Denoise"},{"metadata":{},"cell_type":"markdown","source":"I detect point no birdcall by using Sound Envelope."},{"metadata":{"trusted":true},"cell_type":"code","source":"def envelope(y, rate, threshold):\n    mask = []\n    y_mean = maximum_filter1d(np.abs(y), mode=\"constant\", size=rate//20)\n    for mean in y_mean:\n        if mean > threshold:\n            mask.append(True)\n        else:\n            mask.append(False)\n    return mask, y_mean","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"thr = 0.25\nmask, env = envelope(y, params.sr, thr)\n\nplt.plot(y[mask], label=\"birdcall\")\nplt.plot(y[np.logical_not(mask)], label=\"noise\")\nplt.legend(bbox_to_anchor=(1, 1), loc='upper right')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"denoise and check denoise sound"},{"metadata":{"trusted":true},"cell_type":"code","source":"y_denoise = nr.reduce_noise(audio_clip=y, noise_clip=y[np.logical_not(mask)], verbose=True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"compare original sound spectrum and denoise sound spectrum."},{"metadata":{"trusted":true},"cell_type":"code","source":"def tmp_audio_to_spec(audio, sr):\n    spec = librosa.power_to_db(\n        librosa.feature.melspectrogram(audio, sr=sr, fmin=20, fmax=16000, n_mels=128)\n    )\n    return spec.astype(np.float32)\n\nplt.figure(figsize=(16, 8))\nplt.imshow(tmp_audio_to_spec(y, params.sr))\nplt.show()\n\nplt.figure(figsize=(16, 8))\nplt.imshow(tmp_audio_to_spec(y_denoise, params.sr))\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"It seems that noise has been removed."},{"metadata":{},"cell_type":"markdown","source":"# Main"},{"metadata":{},"cell_type":"markdown","source":"## Train"},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_and_save_train(record):\n    y = load_audio(record, params.sr, TRAIN_AUDIO_ROOT)\n    # denoise\n    mask, env = envelope(y, 32000, thr)\n    noise_clip = y[np.logical_not(mask)]\n    if len(noise_clip):\n        y = nr.reduce_noise(audio_clip=y, noise_clip=noise_clip, verbose=False)\n    melspec = compute_melspec(y, params)\n\n    np.save(OUT_TRAIN + record + \".npy\", melspec)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"OUT_TRAIN = 'train/'\nos.mkdir(OUT_TRAIN)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"_ = joblib.Parallel(n_jobs=8)(\n    joblib.delayed(load_and_save_train)(record) for record in tqdm(df_train['recording_id'].values)\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"shutil.make_archive(OUT_TRAIN, 'zip', OUT_TRAIN)\nshutil.rmtree(OUT_TRAIN)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Test"},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_and_save_test(record):\n    y = load_audio(record, params.sr, TEST_AUDIO_ROOT)\n    melspec = compute_melspec(y, params)\n\n    np.save(OUT_TEST + record + \".npy\", melspec)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"OUT_TEST = 'test/'\nos.mkdir(OUT_TEST)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"_ = joblib.Parallel(n_jobs=8)(\n    joblib.delayed(load_and_save_test)(record) for record in tqdm(df_test['recording_id'].values)\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"shutil.make_archive(OUT_TEST, 'zip', OUT_TEST)\nshutil.rmtree(OUT_TEST)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}