From 78603bd3c2374655a779ea179eef8be1cf84bb5c Mon Sep 17 00:00:00 2001 From: Matthew Scholefield Date: Wed, 5 Sep 2018 05:02:52 -0500 Subject: [PATCH] Add precise-add-noise script This is used to generate noise into a dataset --- precise/scripts/add_noise.py | 120 +++++++++++++++++++++++++++++++++++ setup.py | 1 + 2 files changed, 121 insertions(+) create mode 100755 precise/scripts/add_noise.py diff --git a/precise/scripts/add_noise.py b/precise/scripts/add_noise.py new file mode 100755 index 0000000..7965726 --- /dev/null +++ b/precise/scripts/add_noise.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# Copyright 2018 Mycroft AI Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from itertools import chain +from math import sqrt + +import numpy as np +import os +from glob import glob +from os import makedirs +from os.path import join, dirname, abspath +from pip._vendor.distlib._backport import shutil +from prettyparse import create_parser +from random import random + +from precise.train_data import TrainData +from precise.util import load_audio +from precise.util import save_audio + +usage = ''' + Create a duplicate dataset with added noise + + :folder str + Folder containing source dataset + + :-tg --tags-file str - + Tags file to optionally load from + + :noise_folder str + Folder with wav files containing noise to be added + + :output_folder str + Folder to write the duplicate generated dataset + ... +''' + + +class NoiseData: + def __init__(self, noise_folder: str): + self.noise_data = [ + load_audio(file) + for file in glob(join(noise_folder, '*.wav')) + ] + self.noise_data_id = 0 + self.noise_pos = 0 + self.repeat_count = 0 + + def get_fresh_noise(self, n: int) -> np.ndarray: + noise_audio = np.empty(0) + while len(noise_audio) < n: + noise_source = self.noise_data[self.noise_data_id] + noise_chunk = noise_source[self.noise_pos:self.noise_pos + n - len(noise_audio)] + self.noise_pos += n - len(noise_audio) + if self.noise_pos >= len(noise_source): + self.noise_pos = 0 + self.noise_data_id += 1 + if self.noise_data_id >= len(self.noise_data): + self.noise_data_id = 0 + self.repeat_count += 1 + if self.repeat_count == 100: + print('Warning: Repeating noise 100+ times. Add more to prevent ' + 'overfitting.') + + noise_audio = np.concatenate([noise_audio, noise_chunk]) + return noise_audio + + def noised_audio(self, audio: np.ndarray) -> np.ndarray: + noise_data = self.get_fresh_noise(len(audio)) + audio_volume = sqrt(sum(audio ** 2)) + noise_volume = sqrt(sum(noise_data ** 2)) + adjusted_noise = audio_volume * noise_data / noise_volume + ratio = 0.0 + 0.4 * random() + return ratio * adjusted_noise + (1.0 - ratio) * audio + + +def main(): + args = create_parser(usage).parse_args() + args.tags_file = abspath(args.tags_file) + args.folder = abspath(args.folder) + args.output_folder = abspath(args.output_folder) + + data = TrainData.from_both(args.tags_file, args.folder, args.folder) + noise_data = NoiseData(args.noise_folder) + print('Data:', data) + + def translate_filename(source: str) -> str: + assert source.startswith(args.folder) + relative_file = source[len(args.folder):].strip(os.path.sep) + return join(args.output_folder, relative_file) + + all_filenames = sum(data.train_files + data.test_files, []) + for i, filename in enumerate(all_filenames): + print('{0:.2%} \r'.format(i / (len(all_filenames) - 1)), end='', flush=True) + + audio = load_audio(filename) + altered = noise_data.noised_audio(audio) + output_filename = translate_filename(filename) + + makedirs(dirname(output_filename), exist_ok=True) + save_audio(output_filename, altered) + + print('Done!') + + if args.tags_file and args.tags_file.startswith(args.folder): + shutil.copy2(args.tags_file, translate_filename(args.tags_file)) + + +if __name__ == '__main__': + main() diff --git a/setup.py b/setup.py index c68de78..8138dc1 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,7 @@ setup( ], entry_points={ 'console_scripts': [ + 'precise-add-noise=precise.scripts.add_noise:main', 'precise-collect=precise.scripts.collect:main', 'precise-convert=precise.scripts.convert:main', 'precise-eval=precise.scripts.eval:main',