CoolFace
Modelpublic

RASMUS/Finnish-ASR-Canary-v2

sourceHugging Facemitupdated 7mo agoView on Hugging Face
0likes2.2kdownloads
code_switching_audio_data_creation.py290 linesDownload Raw Back to code_switching
1# Copyright (c) 2022, NVIDIA CORPORATION.  All rights reserved.2#3# Licensed under the Apache License, Version 2.0 (the "License");4# you may not use this file except in compliance with the License.5# You may obtain a copy of the License at6#7#     http://www.apache.org/licenses/LICENSE-2.08#9# Unless required by applicable law or agreed to in writing, software10# distributed under the License is distributed on an "AS IS" BASIS,11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12# See the License for the specific language governing permissions and13# limitations under the License.14 15import argparse16import json17import logging18import os19 20import librosa21import numpy as np22from joblib import Parallel, delayed23from scipy.io import wavfile24from tqdm import tqdm25from nemo.collections.asr.parts.utils.manifest_utils import read_manifest26 27parser = argparse.ArgumentParser(description='Create synthetic code-switching data audio data from monolingual data')28parser.add_argument("--manifest_path", default=None, type=str, help='Path to CS indermediate manifest', required=True)29parser.add_argument(30    "--audio_save_folder_path",31    default=None,32    type=str,33    help='Path to directory where created synthetic set would be saved',34    required=True,35)36parser.add_argument(37    "--manifest_save_path", default=None, type=str, help='Path to save the created manifest', required=True38)39parser.add_argument(40    "--audio_normalized_amplitude", default=15000, type=int, help='Normalized amplitdue of audio samples'41)42parser.add_argument(43    "--cs_data_sampling_rate",44    default=16000,45    type=int,46    help='Desired sampling rate for the audios in the generated dataset',47)48parser.add_argument(49    "--sample_beginning_pause_msec",50    default=20,51    type=int,52    help='Pause to be added at the beginning of the sample (msec)',53)54parser.add_argument(55    "--sample_joining_pause_msec",56    default=100,57    type=int,58    help='Pause to be added between different phrases of the sample (msec)',59)60parser.add_argument(61    "--sample_end_pause_msec", default=20, type=int, help='Pause to be added at the end of the sample (msec)'62)63parser.add_argument(64    "--is_lid_manifest",65    default=True,66    type=bool,67    help='If true, generate manifest in the multi-sample lid format, else the standard manifest format',68)69parser.add_argument("--workers", default=1, type=int, help='Number of worker processes')70 71args = parser.parse_args()72 73 74def split_list(input_list: list, num_splits: int):75    """76    Args:77        input_list: the input list to split78        num_splits: number of splits required79 80    Returns:81        iterator of split lists82 83    """84    k, m = divmod(len(input_list), num_splits)85    return (input_list[i * k + min(i, m) : (i + 1) * k + min(i + 1, m)] for i in range(num_splits))86 87 88def combine_manifests(manifest_save_path: str, num_split: int):89    """90    Args:91        manifest_save_path: absolute path to save the combined manifest92        num_splits: number of splits of manifest93 94    Returns:95        num_samples_combined: the total number of samples in the generated dataset96    """97    num_samples_combined = 098    base_directory = os.path.dirname(manifest_save_path)99 100    with open(manifest_save_path, 'w') as outfile:101        for i in range(num_split):102            split_manifest_path = base_directory + '/temp_' + str(i) + '.json'103            data_split = read_manifest(split_manifest_path)104 105            for elem in data_split:106                s = json.dumps(elem)107                outfile.write(s + '\n')108                num_samples_combined += 1109 110            # removing the intermediate file111            os.remove(split_manifest_path)112 113    return num_samples_combined114 115 116def create_cs_data(117    intermediate_cs_manifest_list: list,118    audio_save_folder: str,119    manfest_save_path: str,120    audio_amplitude_normalization: int,121    pause_beg_msec: int,122    pause_join_msec: int,123    pause_end_msec: int,124    cs_data_sampling_rate: int,125    is_lid_manifest: bool,126):127 128    """129    Args:130        intermediate_cs_manifest_list: the intermediate cs manifest obtained from code_switching_manifest_creation.py as a list131        audio_save_folder: Absolute path to save the generated audio samples132        manfest_save_path: Absolute path to save the corresponding manifest133        audio_amplitude_normalization: The amplitude to scale to after normalization134        pause_beg_msec: Pause to be added at the beginning of the sample (msec)135        pause_join_msec: Pause to be added between different phrases of the sample (msec)136        pause_end_msec: Pause to be added at the end of the sample (msec)137        cs_data_sampling_rate: Desired sampling rate of the generated samples138        is_lid_manifest: If true, generate manifest in the multi-sample lid format, else the standard manifest format139 140    Returns:141 142    """143 144    fs = cs_data_sampling_rate145    incorrect_sample_flag = 0146 147    with open(manfest_save_path, 'w') as outfile:148        for data in tqdm(intermediate_cs_manifest_list):149 150            combined_audio = []151 152            staring_pause = np.zeros(int(pause_beg_msec * fs / 1000))153            combined_audio += list(staring_pause)154 155            text_entry_list = []156            for index in range(len(data['lang_ids'])):157 158                phrase_entry = {}159                # dictionary to store the phrase information which will be added to the complete sentence160 161                data_sample, fs_sample = librosa.load(data['paths'][index], sr=fs)162                # Alternative-  fs_sample, data_sample = wavfile.read(data['paths'][index])163 164                if fs_sample != fs:165                    logging.error('Sampling rate error inside create_cs_data function')166                    exit167 168                # Remove leading and trailing zeros169                data_sample = np.trim_zeros(data_sample)170 171                # take care of empty arrays: rare172                if data_sample.size == 0:173                    incorrect_sample_flag = 1174                    continue175 176                # normalizing data177                data_sample_norm = (178                    data_sample179                    / np.maximum(np.abs(data_sample.max()), np.abs(data_sample.min()))180                    * audio_amplitude_normalization181                )182 183                combined_audio += list(data_sample_norm)184 185                phrase_entry['str'] = data['texts'][index]186                phrase_entry['lang'] = data['lang_ids'][index]187 188                text_entry_list.append(phrase_entry)189 190                # adding small pause between semgments191                if index != (len(data['lang_ids']) - 1):192                    pause = np.zeros(int(pause_join_msec * fs / 1000))193                    combined_audio += list(pause)194 195            if incorrect_sample_flag == 1:196                incorrect_sample_flag = 0197                continue198 199            ending_pause = np.zeros(int(pause_end_msec * fs / 1000))200            combined_audio += list(ending_pause)201 202            sample_id = data['uid']203            audio_file_path = audio_save_folder + '/' + str(sample_id) + ".wav"204 205            # saving audio206            wavfile.write(audio_file_path, fs, np.array(combined_audio).astype(np.int16))207            # Alternative-  librosa.output.write_wav(audio_file_path, combined_audio, fs)208 209            metadata_json = {}210            metadata_json['audio_filepath'] = audio_file_path211            metadata_json['duration'] = float(len(combined_audio) / fs)212            if is_lid_manifest:213                metadata_json['text'] = text_entry_list214            else:215                metadata_json['text'] = ' '.join(data['texts'])216 217            metadata_json['language_ids'] = data['lang_ids']218            metadata_json['original_texts'] = data['texts']219            metadata_json['original_paths'] = data['paths']220            metadata_json['original_durations'] = data['durations']221 222            s = json.dumps(metadata_json)223            outfile.write(s + '\n')224 225 226def main():227 228    cs_intermediate_manifest_path = args.manifest_path229    audio_save_folder = args.audio_save_folder_path230    manifest_save_path = args.manifest_save_path231    audio_amplitude_normalization = args.audio_normalized_amplitude232    pause_beg_msec = args.sample_beginning_pause_msec233    pause_join_msec = args.sample_joining_pause_msec234    pause_end_msec = args.sample_end_pause_msec235    cs_data_sampling_rate = args.cs_data_sampling_rate236    is_lid_manifest = args.is_lid_manifest237    num_process = args.workers238 239    # Sanity Checks240    if (cs_intermediate_manifest_path is None) or (not os.path.exists(cs_intermediate_manifest_path)):241        logging.error('Please provide correct CS manifest (obtained from code_switching_manifest_creation.py)')242        exit243 244    if (audio_save_folder is None) or (not os.path.exists(audio_save_folder)):245        logging.error('audio_save_folder_path is incorrect or does not exist')246        exit247 248    if manifest_save_path is None:249        logging.error('Please provide valid manifest_save_path')250        exit251 252    # Reading data253    logging.info('Reading manifests')254    intermediate_cs_manifest = read_manifest(cs_intermediate_manifest_path)255 256    # Spliting the data257    data_split = split_list(intermediate_cs_manifest, num_process)258 259    # Creating Audio data260    logging.info('Creating synthetic audio data')261    base_directory = os.path.dirname(manifest_save_path)262 263    Parallel(n_jobs=num_process)(264        delayed(create_cs_data)(265            split_manifest,266            audio_save_folder,267            base_directory + '/temp_' + str(idx) + '.json',268            audio_amplitude_normalization,269            pause_beg_msec,270            pause_join_msec,271            pause_end_msec,272            cs_data_sampling_rate,273            is_lid_manifest,274        )275        for idx, split_manifest in enumerate(data_split)276    )277 278    # Combining manifests279    num_samples_combined = combine_manifests(manifest_save_path, num_process)280 281    print("Synthetic CS audio data saved at :", audio_save_folder)282    print("Synthetic CS manifest saved at :", manifest_save_path)283    print("Total number of samples in the generated dataset :", str(num_samples_combined))284 285    logging.info('Done!')286 287 288if __name__ == "__main__":289    main()290