blob: e7155c74354775f93bb398a2035b6d1002011036 [file] [log] [blame]
alexander3c798932021-03-26 21:42:19 +00001# Copyright (c) 2021 Arm Limited. All rights reserved.
2# SPDX-License-Identifier: Apache-2.0
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16"""
17Utility script to convert a set of audio clip in a given location into
18corresponding cpp files and a single hpp file referencing the vectors
19from the cpp files.
20"""
21import datetime
22import glob
23import math
24import os
25
26import numpy as np
27from os import path
28from argparse import ArgumentParser
29from jinja2 import Environment, FileSystemLoader
30from gen_utils import AudioUtils
31
32parser = ArgumentParser()
33parser.add_argument("--audio_path", type=str, help="path to audio folder to convert.")
34parser.add_argument("--source_folder_path", type=str, help="path to source folder to be generated.")
35parser.add_argument("--header_folder_path", type=str, help="path to header folder to be generated.")
36parser.add_argument("--sampling_rate", type=int, help="target sampling rate.", default=16000)
37parser.add_argument("--mono", type=bool, help="convert signal to mono.", default=True)
38parser.add_argument("--offset", type=float, help="start reading after this time (in seconds).", default=0)
39parser.add_argument("--duration", type=float, help="only load up to this much audio (in seconds).", default=0)
40parser.add_argument("--res_type", type=AudioUtils.res_data_type, help=f"Resample type: {AudioUtils.res_type_list()}.",
41 default='kaiser_best')
42parser.add_argument("--min_samples", type=int, help="Minimum sample number.", default=16000)
43parser.add_argument("--license_template", type=str, help="Header template file",
44 default="header_template.txt")
45parser.add_argument("-v", "--verbosity", action="store_true")
46args = parser.parse_args()
47
48env = Environment(loader=FileSystemLoader(os.path.join(os.path.dirname(__file__), 'templates')),
49 trim_blocks=True,
50 lstrip_blocks=True)
51
52
53def write_hpp_file(header_filepath, cc_filepath, header_template_file, num_audios, audio_filenames, audio_array_namesizes):
54 print(f"++ Generating {header_filepath}")
55
56 header_template = env.get_template(header_template_file)
57 hdr = header_template.render(script_name=os.path.basename(__file__),
58 gen_time=datetime.datetime.now(),
59 year=datetime.datetime.now().year)
60 env.get_template('AudioClips.hpp.template').stream(common_template_header=hdr,
61 clips_count=num_audios,
62 varname_size=audio_array_namesizes
63 ) \
64 .dump(str(header_filepath))
65
66 print(f"++ Generating {cc_filepath}")
67
68 env.get_template('AudioClips.cc.template').stream(common_template_header=hdr,
69 clips_count=num_audios,
70 var_names=(name for name, _ in audio_array_namesizes),
71 clip_sizes=(size for _, size in audio_array_namesizes),
72 clip_names=audio_filenames) \
73 .dump(str(cc_filepath))
74
75
76def write_individual_audio_cc_file(clip_dirpath, clip_filename,
77 cc_filename, header_template_file, array_name,
Kshitij Sisodia659fcd92021-05-19 10:30:06 +010078 sampling_rate_value, mono_value, offset_value,
alexander3c798932021-03-26 21:42:19 +000079 duration_value, res_type_value, min_len):
80 print(f"++ Converting {clip_filename} to {path.basename(cc_filename)}")
81 audio_filepath = path.join(clip_dirpath, clip_filename)
82 clip_data, samplerate = AudioUtils.load_resample_audio_clip(audio_filepath,
83 sampling_rate_value, mono_value,
84 offset_value, duration_value,
85 res_type_value, min_len)
86
87 # Change from [-1, 1] fp32 range to int16 range.
Kshitij Sisodia659fcd92021-05-19 10:30:06 +010088 clip_data = np.clip((clip_data * (1 << 15)),
89 np.iinfo(np.int16).min,
alexander3c798932021-03-26 21:42:19 +000090 np.iinfo(np.int16).max).flatten().astype(np.int16)
91
92 header_template = env.get_template(header_template_file)
93 hdr = header_template.render(script_name=os.path.basename(__file__),
94 gen_time=datetime.datetime.now(),
95 file_name=clip_filename,
96 year=datetime.datetime.now().year)
97
98 hex_line_generator = (', '.join(map(hex, sub_arr))
99 for sub_arr in np.array_split(clip_data, math.ceil(len(clip_data)/20)))
100
101 env.get_template('audio.cc.template').stream(common_template_header=hdr,
102 size=len(clip_data),
103 var_name=array_name,
104 audio_data=hex_line_generator) \
105 .dump(str(cc_filename))
106
107 return len(clip_data)
108
109
110def main(args):
111 # Keep the count of the audio files converted
112 audioclip_idx = 0
113 audioclip_filenames = []
114 audioclip_array_names = []
115 header_filename = "InputFiles.hpp"
116 common_cc_filename = "InputFiles.cc"
117 header_filepath = path.join(args.header_folder_path, header_filename)
118 common_cc_filepath = path.join(args.source_folder_path, common_cc_filename)
119
Kshitij Sisodia659fcd92021-05-19 10:30:06 +0100120 if os.path.isdir(args.audio_path):
alexander3c798932021-03-26 21:42:19 +0000121 filepaths = sorted(glob.glob(path.join(args.audio_path, '**/*.wav'), recursive=True))
122 elif os.path.isfile(args.audio_path):
123 filepaths = [args.audio_path]
124 else:
125 raise OSError("Directory or file does not exist.")
126
127 for filepath in filepaths:
Kshitij Sisodia659fcd92021-05-19 10:30:06 +0100128 filename = path.basename(filepath)
alexander3c798932021-03-26 21:42:19 +0000129 clip_dirpath = path.dirname(filepath)
130 try:
131 audioclip_filenames.append(filename)
132
133 # Save the cc file
134 cc_filename = path.join(args.source_folder_path,
135 (filename.rsplit(".")[0]).replace(" ", "_") + ".cc")
136 array_name = "audio" + str(audioclip_idx)
137 array_size = write_individual_audio_cc_file(clip_dirpath, filename, cc_filename, args.license_template, array_name,
138 args.sampling_rate, args.mono, args.offset,
139 args.duration, args.res_type, args.min_samples)
140
141 audioclip_array_names.append((array_name, array_size))
142 # Increment audio index
143 audioclip_idx = audioclip_idx + 1
144 except:
145 if args.verbosity:
146 print(f"Failed to open {filename} as an audio.")
147
Kshitij Sisodia659fcd92021-05-19 10:30:06 +0100148 if len(audioclip_filenames) > 0:
149 write_hpp_file(header_filepath, common_cc_filepath, args.license_template,
150 audioclip_idx, audioclip_filenames, audioclip_array_names)
151 else:
152 raise FileNotFoundError("No valid audio clip files found.")
alexander3c798932021-03-26 21:42:19 +0000153
154
155if __name__ == '__main__':
156 main(args)