zohann commited on
Commit
136b70a
·
verified ·
1 Parent(s): 821547c

Upload Audio_Effects_SDK/samples/effects_delayed_streams_demo/effects_delayed_streams_demo.cpp with huggingface_hub

Browse files
Audio_Effects_SDK/samples/effects_delayed_streams_demo/effects_delayed_streams_demo.cpp ADDED
@@ -0,0 +1,924 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*
2
+ Copyright (c) 2021-2022, NVIDIA CORPORATION. All rights reserved.
3
+
4
+ NVIDIA CORPORATION and its licensors retain all intellectual property
5
+ and proprietary rights in and to this software, related documentation
6
+ and any modifications thereto. Any use, reproduction, disclosure or
7
+ distribution of this software and related documentation without an express
8
+ license agreement from NVIDIA CORPORATION is strictly prohibited.
9
+ */
10
+ #include <math.h>
11
+ #include <limits.h>
12
+
13
+ #include <algorithm>
14
+ #include <chrono>
15
+ #include <cstring>
16
+ #include <iostream>
17
+ #include <iomanip>
18
+ #include <map>
19
+ #include <memory>
20
+ #include <set>
21
+ #include <sstream>
22
+ #include <thread>
23
+ #include <tuple>
24
+
25
+ #include "utils/wave_reader/waveReadWrite.hpp"
26
+ #include "utils/ConfigReader.hpp"
27
+
28
+ #include <nvAudioEffects.h>
29
+
30
+ namespace {
31
+
32
+ const char kConfigEffectVariable[] = "effect";
33
+ const char kConfigSampleRateVariable[] = "sample_rate";
34
+ const char kConfigFileInputVariable[] = "input_wav_list";
35
+ const char kConfigFileInputFarendVariable[] = "input_farend_wav_list";
36
+ const char kConfigFileOutputVariable[] = "output_wav_list";
37
+ const char kConfigResetVariable[] = "reset";
38
+ const char kConfigFrameSize[] = "frame_size";
39
+ const char kConfigOneStepDelayStreams[] = "one_step_delay_streams";
40
+ const char kConfigTwoStepDelayStreams[] = "two_step_delay_streams";
41
+ const char kConfigLogTarget[] = "log_target_list";
42
+ const char kConfigLogTargetFile[] = "log_target_file";
43
+ const char kConfigLogLevel[] = "log_level";
44
+ const char kConfigLogTargetFileDefault[] = "/tmp/nvAudioEffects_log.txt";
45
+ const char kConfigFileModelVariable[] = "model";
46
+ const char kConfigVadEnable[] = "enable_vad";
47
+
48
+ /* allowed sample rates */
49
+ const std::vector<uint32_t> kAllowedSampleRates = { 8000, 16000, 48000 };
50
+
51
+ static std::vector<uint32_t> ConvertStrVectorToUINT32Vector(const std::vector<std::string>& string_vector) {
52
+ std::vector<uint32_t> uint_vector;
53
+ std::transform(string_vector.begin(), string_vector.end(), std::back_inserter(uint_vector),
54
+ [](const std::string& str){ return std::strtoul(str.c_str(), nullptr, 0); });
55
+ return uint_vector;
56
+ }
57
+
58
+ static bool ValidateDelayedStreams(std::vector<uint32_t> one_step_delay_streams,
59
+ std::vector<uint32_t> two_step_delay_streams,
60
+ uint32_t num_streams) {
61
+ // stream ids should be less than the total number of streams
62
+ if (std::all_of(one_step_delay_streams.begin(), one_step_delay_streams.end(),
63
+ [num_streams](uint32_t v) { return v < num_streams; }) == false) {
64
+ std::cout << "Error: One or more streams ids in one_step_delay_streams is greater than the total number of streams"
65
+ << std::endl;
66
+ return false;
67
+ }
68
+ if (std::all_of(two_step_delay_streams.begin(), two_step_delay_streams.end(),
69
+ [num_streams](uint32_t v) { return v < num_streams; }) == false) {
70
+ std::cout << "Error: One or more streams ids in two_step_delay_streams is greater than the total number of streams"
71
+ << std::endl;
72
+ return false;
73
+ }
74
+
75
+ // one_step_delay_streams and two_step_delay_streams should not have common stream ids
76
+ for (const auto& stream_id : one_step_delay_streams) {
77
+ auto itr = std::find(two_step_delay_streams.begin(), two_step_delay_streams.end(), stream_id);
78
+ if (itr != two_step_delay_streams.end()) {
79
+ std::cout << "Error: one_step_delay_streams and two_steps_delayed_streams cannot have common stream indices"
80
+ << std::endl;
81
+ return false;
82
+ }
83
+ }
84
+
85
+ // one_step_delay_streams should not have duplicates
86
+ std::sort(one_step_delay_streams.begin(), one_step_delay_streams.end());
87
+ auto itr = std::adjacent_find(one_step_delay_streams.begin(), one_step_delay_streams.end());
88
+ if (itr != one_step_delay_streams.end()) {
89
+ std::cout << "Error: one_step_delay_streams cannot have duplicate stream indices"
90
+ << std::endl;
91
+ return false;
92
+ }
93
+ // two_step_delay_streams should not have duplicates
94
+ std::sort(two_step_delay_streams.begin(), two_step_delay_streams.end());
95
+ itr = std::adjacent_find(two_step_delay_streams.begin(), two_step_delay_streams.end());
96
+ if (itr != two_step_delay_streams.end()) {
97
+ std::cout << "Error: two_step_delay_streams cannot have duplicate stream indices"
98
+ << std::endl;
99
+ return false;
100
+ }
101
+ return true;
102
+ }
103
+
104
+ } // namespace
105
+
106
+ struct StreamData {
107
+ // Wav file name(s) separated by ';'
108
+ std::string input_wav_file;
109
+ // Total number of samples in all input wav files together
110
+ unsigned num_samples = 0;
111
+ // Number of audio samples written to output file
112
+ unsigned already_written = 0;
113
+ // Current offset for the input in the input data of the stream
114
+ unsigned current_offset = 0;
115
+ // 32-bit float audio samples read from all input wav files
116
+ std::vector<float>* input_wav_samples;
117
+ // (AEC only) 32-bit float audio samples for farend input wav files
118
+ std::vector<float>* input_farend_wav_samples;
119
+ // Wav file name(s) to write the output data
120
+ std::string output_wav_file;
121
+ // Object for wav writing library
122
+ std::unique_ptr<CWaveFileWrite> wav_write;
123
+ // Index of each input file end in the audio data vector
124
+ std::vector<int> file_end_offsets;
125
+ // Index of current output file used as suffix to filename
126
+ int output_file_num;
127
+ };
128
+
129
+ class EffectsDemoApp {
130
+ public:
131
+ bool run(const ConfigReader& config_reader);
132
+
133
+ private:
134
+ // Validate configuration data.
135
+ bool validateConfig(const ConfigReader& config_reader);
136
+ // write to output wav
137
+ bool writeOutputWav(const float* output_samples, size_t num_samples, int stream_index);
138
+ // Apply the effect on the streams
139
+ bool runEffect(NvAFX_Handle handle, const std::vector<uint32_t>& streams,
140
+ std::vector<float>& input_frame, std::vector<float>& output_frame);
141
+ // Load the input data
142
+ void loadInputFrame(const std::vector<uint32_t>& streams, std::vector<float>& input_frame);
143
+
144
+ // sample rate config
145
+ uint32_t input_sample_rate_ = 0;
146
+ // output sample rate config
147
+ uint32_t output_sample_rate_ = 0;
148
+ // number of samples per frame
149
+ unsigned int num_input_samples_per_frame_ = 0;
150
+ // number of output samples per frame
151
+ unsigned int num_output_samples_per_frame_ = 0;
152
+ // number of input channels
153
+ uint32_t num_input_channels_ = 0;
154
+ // number of output channels
155
+ uint32_t num_output_channels_ = 0;
156
+ // Total run time of the effect
157
+ float total_run_time_ = 0.f;
158
+ // stream data
159
+ std::vector<StreamData> stream_data_;
160
+ // Input files list
161
+ std::vector<std::string> input_wav_list_;
162
+ // Whether AEC is enabled
163
+ bool is_aec_ = false;
164
+ // VAD
165
+ bool vad_supported_ = false;
166
+ // Obtain farend audio if effect is AEC
167
+ std::vector<std::string> input_farend_wav_list_;
168
+ // Output files list
169
+ std::vector<std::string> output_wav_list_;
170
+ // Reset list. Set based on entries in config file
171
+ std::vector<bool> reset_list_;
172
+ // Reset map. Set based on reset_list and stream input change
173
+ std::vector<NvAFX_Bool> reset_map_;
174
+ // Activity map
175
+ std::vector<NvAFX_Bool> activity_map_;
176
+ };
177
+
178
+ bool EffectsDemoApp::validateConfig(const ConfigReader& config_reader) {
179
+ if (config_reader.IsConfigValueAvailable(kConfigEffectVariable) == false) {
180
+ std::cerr << "No " << kConfigEffectVariable << " variable found" << std::endl;
181
+ return false;
182
+ }
183
+
184
+ std::string input_sample_rate_str;
185
+ if (config_reader.GetConfigValue(kConfigSampleRateVariable, &input_sample_rate_str)) {
186
+ input_sample_rate_ = std::strtoul(input_sample_rate_str.c_str(), nullptr, 0);
187
+ if (std::find(kAllowedSampleRates.begin(), kAllowedSampleRates.end(), input_sample_rate_) ==
188
+ kAllowedSampleRates.end()) {
189
+ std::cerr << "Sample rate " << input_sample_rate_ << " not supported" << std::endl;
190
+ return false;
191
+ }
192
+ } else {
193
+ std::cerr << "No " << kConfigSampleRateVariable << " variable found" << std::endl;
194
+ return false;
195
+ }
196
+
197
+ if (config_reader.IsConfigValueAvailable(kConfigFileModelVariable) == false) {
198
+ std::cerr << "No " << kConfigFileModelVariable << " variable found" << std::endl;
199
+ return false;
200
+ }
201
+
202
+ if (config_reader.IsConfigValueAvailable(kConfigFileInputVariable) == false) {
203
+ std::cerr << "No " << kConfigFileInputVariable << " variable found" << std::endl;
204
+ return false;
205
+ }
206
+
207
+ if (config_reader.IsConfigValueAvailable(kConfigFileOutputVariable) == false) {
208
+ std::cerr << "No " << kConfigFileOutputVariable << " variable found" << std::endl;
209
+ return false;
210
+ }
211
+
212
+ if (config_reader.IsConfigValueAvailable(kConfigResetVariable)) {
213
+ std::cout << "Reset available" << std::endl;
214
+ }
215
+
216
+ if (config_reader.IsConfigValueAvailable(kConfigOneStepDelayStreams) == false) {
217
+ std::cerr << "No " << kConfigOneStepDelayStreams << " variable found" << std::endl;
218
+ return false;
219
+ }
220
+
221
+ if (config_reader.IsConfigValueAvailable(kConfigTwoStepDelayStreams) == false) {
222
+ std::cerr << "No " << kConfigTwoStepDelayStreams << " variable found" << std::endl;
223
+ return false;
224
+ }
225
+
226
+ return true;
227
+ }
228
+
229
+ bool EffectsDemoApp::writeOutputWav(const float* output_samples, size_t num_samples,
230
+ int stream_index) {
231
+ auto to_write = num_samples;
232
+ auto max_allowed = stream_data_[stream_index].num_samples *
233
+ (output_sample_rate_/input_sample_rate_);
234
+ auto already_written = stream_data_[stream_index].already_written;
235
+ auto can_write = static_cast<size_t>(max_allowed - already_written);
236
+ if (can_write == 0) { return true; }
237
+ auto will_write = std::min(to_write, can_write);
238
+ if (!stream_data_[stream_index].wav_write->writeChunk(output_samples,
239
+ will_write * sizeof(float))) {
240
+ std::cerr << "Could not write output to file "
241
+ << stream_data_[stream_index].output_wav_file << std::endl;
242
+ return false;
243
+ }
244
+ stream_data_[stream_index].already_written += will_write;
245
+ return true;
246
+ }
247
+
248
+ void EffectsDemoApp::loadInputFrame(const std::vector<uint32_t>& streams,
249
+ std::vector<float>& input_frame) {
250
+ for (const auto& stream_id : streams) {
251
+ auto stream_offset = stream_data_[stream_id].current_offset;
252
+ float *in = stream_data_[stream_id].input_wav_samples->data() + stream_offset;
253
+ std::copy(in, in + num_input_samples_per_frame_, &input_frame[stream_id * num_input_samples_per_frame_]);
254
+ if (is_aec_) {
255
+ int num_streams = stream_data_.size();
256
+ in = stream_data_[stream_id].input_farend_wav_samples->data() + stream_offset;
257
+ std::copy(in, in + num_input_samples_per_frame_,
258
+ &input_frame[(num_streams + stream_id) * num_input_samples_per_frame_]);
259
+ }
260
+ // Check if this file is finished, if so, start a new file
261
+ if (stream_data_[stream_id].file_end_offsets.size() &&
262
+ stream_offset == static_cast<unsigned>(stream_data_[stream_id].file_end_offsets[0])) {
263
+ stream_data_[stream_id].file_end_offsets
264
+ .erase(stream_data_[stream_id].file_end_offsets.begin());
265
+ if (stream_data_[stream_id].file_end_offsets.size()) {
266
+ // Open a new file only if this isn't the last one
267
+ stream_data_[stream_id].wav_write->commitFile();
268
+ auto ext = output_wav_list_[stream_id].find_last_of(".");
269
+ std::string filename = output_wav_list_[stream_id].substr(0, ext) + "_" +
270
+ std::to_string(++stream_data_[stream_id].output_file_num) + ".wav";
271
+ stream_data_[stream_id].wav_write =
272
+ std::unique_ptr<CWaveFileWrite>(new CWaveFileWrite(filename, output_sample_rate_, 1, 32, true));
273
+ if (reset_list_[stream_id]) {
274
+ reset_map_[stream_id] = NVAFX_TRUE;
275
+ }
276
+ }
277
+ }
278
+ stream_data_[stream_id].current_offset += num_input_samples_per_frame_;
279
+ }
280
+ }
281
+
282
+ bool EffectsDemoApp::runEffect(NvAFX_Handle handle, const std::vector<uint32_t>& streams,
283
+ std::vector<float>& input_frame, std::vector<float>& output_frame) {
284
+ loadInputFrame(streams, input_frame);
285
+
286
+ for (const auto& stream_id : streams) {
287
+ activity_map_[stream_id] = NVAFX_TRUE;
288
+ }
289
+ if (NvAFX_SetBoolList(handle, NVAFX_PARAM_ACTIVE_STREAMS,
290
+ activity_map_.data(), activity_map_.size()) != NVAFX_STATUS_SUCCESS) {
291
+ std::cerr << "NvAFX_SetBoolList() failed" << std::endl;
292
+ return false;
293
+ }
294
+ memset(activity_map_.data(), NVAFX_FALSE, sizeof(activity_map_[0]) * activity_map_.size());
295
+
296
+ if (std::find(reset_map_.begin(), reset_map_.end(), NVAFX_TRUE) != reset_map_.end()) {
297
+ if (NvAFX_Reset(handle, reset_map_.data(), reset_map_.size()) != NVAFX_STATUS_SUCCESS) {
298
+ std::cerr << "Reset failed" << std::endl;
299
+ return false;
300
+ }
301
+ memset(reset_map_.data(), NVAFX_FALSE, sizeof(reset_map_[0]) * reset_map_.size());
302
+ }
303
+
304
+ const float* input[2];
305
+ float* output[1];
306
+ input[0] = input_frame.data();
307
+ if (is_aec_) {
308
+ input[1] = &input_frame[input_frame.size()/num_input_channels_];
309
+ }
310
+ output[0] = output_frame.data();
311
+ auto start_tick = std::chrono::high_resolution_clock::now();
312
+ if (NvAFX_Run(handle, input, output, num_input_samples_per_frame_, num_input_channels_) != NVAFX_STATUS_SUCCESS) {
313
+ std::cerr << "NvAFX_Run() failed" << std::endl;
314
+ return false;
315
+ }
316
+ auto run_end_tick = std::chrono::high_resolution_clock::now();
317
+ total_run_time_ += (std::chrono::duration<float>(run_end_tick - start_tick)).count();
318
+ return true;
319
+ }
320
+
321
+ void logger_cb(LoggingSeverity level, const char* log, void* userdata) {
322
+ std::cout << "LOG" << '(' << LogSeverityToString(level) << ") " << log << '\n';
323
+ }
324
+
325
+ inline LoggingSeverity StringToLogSeverity(std::string &severity) {
326
+ if ("ERROR" == severity) return LOG_LEVEL_ERROR;
327
+ if ("WARNING" == severity) return LOG_LEVEL_WARNING;
328
+ if ("INFO" == severity) return LOG_LEVEL_INFO;
329
+ return LOG_LEVEL_ERROR;
330
+ }
331
+
332
+ inline LoggingTarget StringToLogTarget(std::string &severity) {
333
+ if ("NONE" == severity) return LOG_TARGET_NONE;
334
+ if ("STDERR" == severity) return LOG_TARGET_STDERR;
335
+ if ("FILE" == severity) return LOG_TARGET_FILE;
336
+ if ("CALLBACK" == severity) return LOG_TARGET_CALLBACK;
337
+ return LOG_TARGET_NONE;
338
+ }
339
+
340
+ bool EffectsDemoApp::run(const ConfigReader& config_reader)
341
+ {
342
+ if (validateConfig(config_reader) == false)
343
+ return false;
344
+
345
+ std::vector<std::string> log_targets;
346
+ if (config_reader.IsConfigValueAvailable(kConfigLogTarget)) {
347
+ log_targets = config_reader.GetConfigValueList(kConfigLogTarget);
348
+ }
349
+ LoggingSeverity severity = LOG_LEVEL_INFO;
350
+ int target = LOG_TARGET_STDERR;
351
+ std::string log_file(kConfigLogTargetFileDefault);
352
+
353
+ if (!log_targets.empty()) {
354
+ target = LOG_TARGET_NONE;
355
+ for (auto& item : log_targets) {
356
+ target |= StringToLogTarget(item);
357
+ }
358
+ }
359
+
360
+ if (target & LOG_TARGET_FILE) {
361
+ if (config_reader.IsConfigValueAvailable(kConfigLogTargetFile)) {
362
+ log_file = config_reader.GetConfigValue(kConfigLogTargetFile);
363
+ }
364
+ }
365
+
366
+ if (config_reader.IsConfigValueAvailable(kConfigLogLevel)) {
367
+ auto log_level = config_reader.GetConfigValue(kConfigLogLevel);
368
+ if (!log_level.empty()) {
369
+ severity = StringToLogSeverity(log_level);
370
+ }
371
+ }
372
+ NvAFX_Status log_status;
373
+ log_status = NvAFX_InitializeLogger(severity, target, log_file.c_str(),
374
+ target & LOG_TARGET_CALLBACK ? logger_cb : nullptr,
375
+ nullptr);
376
+
377
+ if (log_status != NVAFX_STATUS_SUCCESS) {
378
+ std::cerr << "NvAFX_InitializeLogger() failed" << std::endl;
379
+ return false;
380
+ }
381
+
382
+ input_wav_list_ = config_reader.GetConfigValueList(kConfigFileInputVariable);
383
+ output_wav_list_ = config_reader.GetConfigValueList(kConfigFileOutputVariable);
384
+ if (input_wav_list_.size() != output_wav_list_.size()) {
385
+ std::cout << "Error: Input and output wav files list size mismatch found" << std::endl;
386
+ return false;
387
+ }
388
+
389
+ reset_list_.resize(input_wav_list_.size(), false);
390
+ if (config_reader.IsConfigValueAvailable(kConfigResetVariable)) {
391
+ auto config_list = config_reader.GetConfigValueList(kConfigResetVariable);
392
+ for (auto& item : config_list) {
393
+ char* p;
394
+ unsigned int num = strtol(item.c_str(), &p, 10);
395
+ if (*p != 0) {
396
+ // Invalid?
397
+ continue;
398
+ }
399
+ if (num < 1 || num > input_wav_list_.size()) {
400
+ std::cerr << "Error: Invalid stream specified for reset" <<std::endl;
401
+ return false;
402
+ }
403
+ reset_list_[num-1] = true;
404
+ }
405
+ }
406
+
407
+ const unsigned num_streams = input_wav_list_.size();
408
+
409
+ // Get the stream ids for delayed streams
410
+ std::vector<uint32_t> active_streams, one_step_delay_streams, two_step_delay_streams;
411
+ auto val = config_reader.GetConfigValueList(kConfigOneStepDelayStreams);
412
+ if (val[0] != "none") {
413
+ one_step_delay_streams = ConvertStrVectorToUINT32Vector(val);
414
+ }
415
+ val = config_reader.GetConfigValueList(kConfigTwoStepDelayStreams);
416
+ if (val[0] != "none") {
417
+ two_step_delay_streams = ConvertStrVectorToUINT32Vector(val);
418
+ }
419
+ if (!ValidateDelayedStreams(one_step_delay_streams, two_step_delay_streams, num_streams)) {
420
+ std::cout << "Delayed streams validation failed." << std::endl;
421
+ return false;
422
+ }
423
+ // Create active_streams.
424
+ for (unsigned i = 0; i < num_streams; ++i) {
425
+ if (std::find(one_step_delay_streams.begin(), one_step_delay_streams.end(), i) ==
426
+ one_step_delay_streams.end() &&
427
+ std::find(two_step_delay_streams.begin(), two_step_delay_streams.end(), i) ==
428
+ two_step_delay_streams.end()) {
429
+ active_streams.push_back(i);
430
+ }
431
+ }
432
+
433
+ if (config_reader.IsConfigValueAvailable(kConfigFrameSize)) {
434
+ auto config_value = config_reader.GetConfigValue(kConfigFrameSize);
435
+ unsigned frame_size = std::strtoul(config_value.c_str(), nullptr, 0);
436
+ // frame_size is in milliseconds.
437
+ num_input_samples_per_frame_ = (input_sample_rate_ * frame_size) / 1000;
438
+ }
439
+
440
+ int num_effects;
441
+ NvAFX_EffectSelector* supported_effects;
442
+ if (NvAFX_GetEffectList(&num_effects, &supported_effects) != NVAFX_STATUS_SUCCESS) {
443
+ std::cerr << "NvAFX_GetEffectList() failed" << std::endl;
444
+ return false;
445
+ }
446
+
447
+ std::cout << "Total Effects supported: " << num_effects << std::endl;
448
+ for (int i = 0; i < num_effects; ++i) {
449
+ std::cout << "(" << i + 1 << ") " << supported_effects[i] << std::endl;
450
+ }
451
+
452
+ NvAFX_Handle handle;
453
+ std::vector<std::string> effects = config_reader.GetConfigValueList(kConfigEffectVariable);
454
+ std::vector<std::string> sample_rate_str = config_reader.GetConfigValueList(kConfigSampleRateVariable);
455
+ std::vector<uint32_t> sample_rates;
456
+ for (auto& s: sample_rate_str) {
457
+ sample_rates.push_back(std::strtoul(s.c_str(), nullptr, 0));
458
+ }
459
+
460
+ std::string effect_name;
461
+ if (effects.size() == 1) {
462
+ // Single effect
463
+ if (sample_rates.size() != effects.size()) {
464
+ std::cerr << "Expected single sample rate for single effect" << std::endl;
465
+ return false;
466
+ }
467
+ input_sample_rate_ = sample_rates[0];
468
+ if (std::find(kAllowedSampleRates.begin(), kAllowedSampleRates.end(), input_sample_rate_) ==
469
+ kAllowedSampleRates.end()) {
470
+ std::cerr << "Sample rate " << input_sample_rate_ << " not supported" << std::endl;
471
+ return false;
472
+ }
473
+ NvAFX_Status status = NVAFX_STATUS_FAILED;
474
+ if (effects[0] == "denoiser") {
475
+ status = NvAFX_CreateEffect(NVAFX_EFFECT_DENOISER, &handle);
476
+ } else if (effects[0] == "dereverb") {
477
+ status = NvAFX_CreateEffect(NVAFX_EFFECT_DEREVERB, &handle);
478
+ } else if (effects[0] == "dereverb_denoiser") {
479
+ status = NvAFX_CreateEffect(NVAFX_EFFECT_DEREVERB_DENOISER, &handle);
480
+ } else if (effects[0] == "aec") {
481
+ status = NvAFX_CreateEffect(NVAFX_EFFECT_AEC, &handle);
482
+ is_aec_ = true;
483
+ } else if (effects[0] == "superres") {
484
+ status = NvAFX_CreateEffect(NVAFX_EFFECT_SUPERRES, &handle);
485
+ } else {
486
+ std::cerr << "NvAFX_CreateEffect() failed. Invalid Effect Value : " << effects[0] << std::endl;
487
+ return false;
488
+ }
489
+
490
+ if (status == NVAFX_UNSUPPORTED_RUNTIME) {
491
+ float version = (CUDA_SUPPORTED_RUNTIME / 1000) + (CUDA_SUPPORTED_RUNTIME%100)/100.f;
492
+ std::cerr << "Unsupported CUDA runtime found (requires >= " << version << "). "
493
+ "Please ensure that a driver supporting the required CUDA version is installed (or if using FCU, library path "
494
+ "contains the correct CUDA compat libraries). For more details, please refer to the "
495
+ "programming guide." << std::endl;
496
+ return false;
497
+ } else if (status != NVAFX_STATUS_SUCCESS) {
498
+ std::cerr << "NvAFX_CreateEffect() failed" << std::endl;
499
+ return false;
500
+ }
501
+ const std::set<std::string> kVadSupportedEffects = {"denoiser", "dereverb_denoiser"};
502
+ vad_supported_ = (kVadSupportedEffects.find(effects[0]) != kVadSupportedEffects.end()) &&
503
+ config_reader.IsConfigValueAvailable(kConfigVadEnable) &&
504
+ std::strtoul(config_reader.GetConfigValue(kConfigVadEnable).c_str(), nullptr, 0);
505
+
506
+ if (vad_supported_) {
507
+ std::cout << "Enabling VAD" << std::endl;
508
+ if (NvAFX_SetU32(handle, NVAFX_PARAM_ENABLE_VAD, 1) != NVAFX_STATUS_SUCCESS) {
509
+ std::cerr << "Could not enable VAD" << std::endl;
510
+ return false;
511
+ }
512
+ }
513
+
514
+ status = NvAFX_SetU32(handle, NVAFX_PARAM_INPUT_SAMPLE_RATE, input_sample_rate_);
515
+ if (status == NVAFX_STATUS_INVALID_PARAM) {
516
+ // Try depreciated param
517
+ status = NvAFX_SetU32(handle, NVAFX_PARAM_SAMPLE_RATE, input_sample_rate_);
518
+ }
519
+ if (status!= NVAFX_STATUS_SUCCESS) {
520
+ std::cerr << "NvAFX_SetU32(Sample Rate: " << input_sample_rate_ << ") failed" << std::endl;
521
+ return false;
522
+ }
523
+ effect_name = effects[0];
524
+ } else {
525
+ const std::map<std::tuple<std::string, std::string, uint32_t, uint32_t>, NvAFX_EffectSelector> supported_configs =
526
+ {
527
+ // 16k Effect + Superres 16k-48k
528
+ {std::make_tuple(std::string("denoiser"), std::string("superres"), 16000, 16000), NVAFX_CHAINED_EFFECT_DENOISER_16k_SUPERRES_16k_TO_48k},
529
+ {std::make_tuple(std::string("dereverb"), std::string("superres"), 16000, 16000), NVAFX_CHAINED_EFFECT_DEREVERB_16k_SUPERRES_16k_TO_48k},
530
+ {std::make_tuple(std::string("dereverb_denoiser"), std::string("superres"), 16000, 16000),
531
+ NVAFX_CHAINED_EFFECT_DEREVERB_DENOISER_16k_SUPERRES_16k_TO_48k},
532
+
533
+ // Superres 8k-16k + 16k Effect
534
+ {std::make_tuple("superres", "denoiser", 8000, 16000), NVAFX_CHAINED_EFFECT_SUPERRES_8k_TO_16k_DENOISER_16k },
535
+ {std::make_tuple("superres", "dereverb", 8000, 16000), NVAFX_CHAINED_EFFECT_SUPERRES_8k_TO_16k_DEREVERB_16k },
536
+ {std::make_tuple("superres", "dereverb_denoiser", 8000, 16000),
537
+ NVAFX_CHAINED_EFFECT_SUPERRES_8k_TO_16k_DEREVERB_DENOISER_16k },
538
+ };
539
+ auto effect_config = supported_configs.find(std::make_tuple(effects[0], effects[1], sample_rates[0], sample_rates[1]));
540
+ if (effect_config == supported_configs.end()) {
541
+ std::cerr << "Unsupported effect chain" <<std::endl;
542
+ return false;
543
+ }
544
+ auto status = NvAFX_CreateChainedEffect(effect_config->second,&handle);
545
+ if (status == NVAFX_UNSUPPORTED_RUNTIME) {
546
+ float version = (CUDA_SUPPORTED_RUNTIME / 1000) + (CUDA_SUPPORTED_RUNTIME%100)/100.f;
547
+ std::cerr << "Unsupported CUDA runtime found (requires >= " << version << "). "
548
+ "Please ensure that a driver supporting the required CUDA version is installed (or if using FCU, library path "
549
+ "contains the correct CUDA compat libraries). For more details, please refer to the "
550
+ "programming guide." << std::endl;
551
+ return false;
552
+ } else if (status != NVAFX_STATUS_SUCCESS) {
553
+ std::cerr << "Could not create effect" << std::endl;
554
+ }
555
+ input_sample_rate_ = sample_rates[0];
556
+ effect_name = "Chained Effect (" + effects[0] + " + " + effects[1] + ")";
557
+ }
558
+
559
+ unsigned num_input_samples_per_frame = 0;
560
+ //Superres has more number of output samples
561
+ // Note: Number of samples are per channel
562
+ unsigned num_output_samples_per_frame = 0;
563
+ if (config_reader.IsConfigValueAvailable(kConfigFrameSize)) {
564
+ auto config_value = config_reader.GetConfigValue(kConfigFrameSize);
565
+ unsigned frame_size = std::strtoul(config_value.c_str(), nullptr, 0);
566
+ // frame_size is in milliseconds.
567
+ num_input_samples_per_frame = (input_sample_rate_ * frame_size) / 1000;
568
+ }
569
+
570
+ // Obtain farend audio if effect is AEC
571
+ std::vector<std::string> input_farend_wav_list;
572
+ if (is_aec_) {
573
+ input_farend_wav_list_ = config_reader.GetConfigValueList(kConfigFileInputFarendVariable);
574
+ if (input_farend_wav_list_.size() != input_wav_list_.size()) {
575
+ std::cerr << "AEC effect requires farend audio as input in addition to nearend audio."
576
+ "Please ensure that the config value \"" << kConfigFileInputFarendVariable <<
577
+ "\" is present and has correct number of files" << std::endl;
578
+ return false;
579
+ }
580
+ }
581
+
582
+ NvAFX_Status status;
583
+
584
+ std::vector<std::string> model_files = config_reader.GetConfigValueList(kConfigFileModelVariable);
585
+ // Note: For single effect, model can be passed in as a single string or as a list of strings with size 1
586
+ std::unique_ptr<char*[]> model_files_param(new char*[model_files.size()]);
587
+ for (int i = 0; i < model_files.size(); i++) {
588
+ model_files_param[i] = (char*) model_files[i].data();
589
+ }
590
+ if (NvAFX_SetStringList(handle, NVAFX_PARAM_MODEL_PATH, (const char**)model_files_param.get(),
591
+ model_files.size())
592
+ != NVAFX_STATUS_SUCCESS) {
593
+ std::cerr << "NvAFX_SetString() failed" << std::endl;
594
+ return false;
595
+ }
596
+
597
+ if (NvAFX_SetU32(handle, NVAFX_PARAM_NUM_STREAMS, num_streams) != NVAFX_STATUS_SUCCESS) {
598
+ std::cerr << "NvAFX_SetU32(NVAFX_PARAM_NUM_STREAMS) failed" << std::endl;
599
+ return false;
600
+ }
601
+
602
+ unsigned int list_size = 0;
603
+ std::unique_ptr<unsigned int[]> supported_list = nullptr;
604
+ auto ret = NvAFX_GetU32List(handle, NVAFX_PARAM_SUPPORTED_NUM_SAMPLES_PER_FRAME,
605
+ supported_list.get(), &list_size);
606
+ if (ret != NVAFX_STATUS_OUTPUT_BUFFER_TOO_SMALL) {
607
+ std::cerr << "NvAFX_GetU32List(NVAFX_PARAM_SUPPORTED_NUM_SAMPLES_PER_FRAME) failed."
608
+ << std::endl;
609
+ return false;
610
+ }
611
+ supported_list.reset(new unsigned int[list_size]);
612
+ if (NvAFX_GetU32List(handle, NVAFX_PARAM_SUPPORTED_NUM_SAMPLES_PER_FRAME,
613
+ supported_list.get(), &list_size) != NVAFX_STATUS_SUCCESS) {
614
+ std::cerr << "NvAFX_GetU32List(NVAFX_PARAM_SUPPORTED_NUM_SAMPLES_PER_FRAME) failed."
615
+ << std::endl;
616
+ return false;
617
+ }
618
+ // If config specifies certain value check if it is in supported list
619
+ if (config_reader.IsConfigValueAvailable(kConfigFrameSize)) {
620
+ auto pointer = std::find(supported_list.get(), supported_list.get() + list_size,
621
+ num_input_samples_per_frame_);
622
+ if (pointer == supported_list.get() + list_size) {
623
+ std::ostringstream oss;
624
+ std::string separator("");
625
+ oss << "'";
626
+ for (unsigned i = 0; i < list_size; ++i) {
627
+ oss << separator << (supported_list[i] * 1000) / input_sample_rate_;
628
+ separator = ", ";
629
+ }
630
+ oss << "'.";
631
+ std::cerr << "Supplied value for " << kConfigFrameSize << " is not supported. Supplied value: "
632
+ << config_reader.GetConfigValue(kConfigFrameSize) << "." << " Supported values: "
633
+ << oss.str() << std::endl;
634
+ return false;
635
+ }
636
+ } else {
637
+ num_input_samples_per_frame_ = supported_list[0];
638
+ }
639
+
640
+ status = NvAFX_SetU32(handle, NVAFX_PARAM_NUM_SAMPLES_PER_INPUT_FRAME, num_input_samples_per_frame_);
641
+ if (status == NVAFX_STATUS_INVALID_PARAM) {
642
+ status = NvAFX_SetU32(handle, NVAFX_PARAM_NUM_SAMPLES_PER_FRAME, num_input_samples_per_frame_);
643
+ }
644
+ if (status != NVAFX_STATUS_SUCCESS) {
645
+ std::cerr << "NvAFX_SetU32(NVAFX_PARAM_NUM_SAMPLES_PER_FRAME) failed" << std::endl;
646
+ return false;
647
+ }
648
+
649
+ std::cout << "Loading effect" << " ... ";
650
+ if (NvAFX_Load(handle) != NVAFX_STATUS_SUCCESS) {
651
+ std::cerr << "NvAFX_Load() failed" << std::endl;
652
+ return false;
653
+ }
654
+ std::cout << "Done" << std::endl;
655
+
656
+ // Try to get output number of samples per frame (valid only with new SDK)
657
+ status = NvAFX_GetU32(handle, NVAFX_PARAM_NUM_SAMPLES_PER_OUTPUT_FRAME,
658
+ &num_output_samples_per_frame_);
659
+ if (status != NVAFX_STATUS_SUCCESS) {
660
+ if (status == NVAFX_STATUS_INVALID_PARAM) {
661
+ // Old SDK, output samples = input samples
662
+ num_output_samples_per_frame_ = num_input_samples_per_frame_;
663
+ } else {
664
+ std::cerr << "NvAFX_GetU32() failed: NVAFX_PARAM_NUM_SAMPLES_PER_OUTPUT_FRAME" << std::endl;
665
+ return false;
666
+ }
667
+ }
668
+
669
+ // Try to get output sample rate (valid only with new SDK)
670
+ status = NvAFX_GetU32(handle, NVAFX_PARAM_OUTPUT_SAMPLE_RATE, &output_sample_rate_);
671
+ if (status != NVAFX_STATUS_SUCCESS) {
672
+ if (status == NVAFX_STATUS_INVALID_PARAM) {
673
+ // Old SDK, output sample rate = input sample rate
674
+ output_sample_rate_ = input_sample_rate_;
675
+ } else {
676
+ std::cerr << "NvAFX_GetU32() failed: NVAFX_PARAM_OUTPUT_SAMPLE_RATE" << std::endl;
677
+ return false;
678
+ }
679
+ }
680
+
681
+ // Try to get input/output channels, if that fails (old SDK?), try depreciated num_channels
682
+ status = NvAFX_GetU32(handle, NVAFX_PARAM_NUM_INPUT_CHANNELS, &num_input_channels_);
683
+ if (status != NVAFX_STATUS_SUCCESS) {
684
+ if (status == NVAFX_STATUS_INVALID_PARAM) {
685
+ if (NvAFX_GetU32(handle, NVAFX_PARAM_NUM_CHANNELS, &num_input_channels_) != NVAFX_STATUS_SUCCESS) {
686
+ std::cerr << "NvAFX_GetU32(NVAFX_PARAM_NUM_CHANNELS) failed" << std::endl;
687
+ return false;
688
+ } else {
689
+ // For older SDKs, output channels = input channels = 1
690
+ num_output_channels_ = num_input_channels_;
691
+ }
692
+ } else {
693
+ std::cerr << "NvAFX_GetU32() failed" << std::endl;
694
+ return false;
695
+ }
696
+ } else if (NvAFX_GetU32(handle, NVAFX_PARAM_NUM_OUTPUT_CHANNELS, &num_output_channels_) != NVAFX_STATUS_SUCCESS) {
697
+ std::cerr << "NvAFX_GetU32() failed" << std::endl;
698
+ return false;
699
+ }
700
+
701
+ std::cout << "Effect properties:" << std::endl
702
+ << " Effect : " << effect_name << std::endl
703
+ << " Input Channels : " << num_input_channels_ << std::endl
704
+ << " Output Channels : " << num_output_channels_ << std::endl
705
+ << " Input Sample Rate : " << input_sample_rate_ << std::endl
706
+ << " Output Sample Rate : " << output_sample_rate_ << std::endl
707
+ << " Input samples per frame : " << num_input_samples_per_frame_ << std::endl
708
+ << " Output samples per frame : " << num_output_samples_per_frame_ << std::endl
709
+ << " Number of streams : " << num_streams << std::endl;
710
+
711
+ size_t max_num_samples = 0;
712
+ // read the noisy input wav file data and cache it in RAM.
713
+ for (unsigned i = 0; i < num_streams; ++i) {
714
+ StreamData data;
715
+ data.input_wav_file = input_wav_list_[i];
716
+
717
+ if (!ReadWavFile(input_wav_list_[i], input_sample_rate_, &data.input_wav_samples,
718
+ &data.num_samples, &data.file_end_offsets, num_input_samples_per_frame_)) {
719
+ std::cerr << "Unable to read wav file: " << input_wav_list_[i] << std::endl;
720
+ return false;
721
+ }
722
+
723
+ // max_num_samples should be aligned to 'num_input_samples_per_frame_' automatically
724
+ if (max_num_samples < data.input_wav_samples->size()) {
725
+ max_num_samples = data.input_wav_samples->size();
726
+ }
727
+
728
+ if (is_aec_) {
729
+ unsigned int num_samples = 0;
730
+ std::vector<int> end_offsets;
731
+
732
+ if (!ReadWavFile(input_farend_wav_list_[i], input_sample_rate_, &data.input_farend_wav_samples,
733
+ &num_samples, &end_offsets, num_input_samples_per_frame_)) {
734
+ std::cerr << "Unable to read wav file: " << input_farend_wav_list_[i] << std::endl;
735
+ if (errno == EMFILE) {
736
+ std::cerr << "Open file limit reached. Please increase file limit using the ulimit "
737
+ "utility (for example, \"ulimit -n 20000\"). Please refer to the "
738
+ "documentation of the ulimit utility for more details." << std::endl;
739
+ }
740
+ return false;
741
+ }
742
+
743
+ if (num_samples != data.num_samples || end_offsets != data.file_end_offsets) {
744
+ std::cerr << "Input farend file specification does not match nearend file specification."
745
+ "Farend and Nearend files must have the same number of samples";
746
+ return false;
747
+ }
748
+ }
749
+ data.output_wav_file = output_wav_list_[i];
750
+ data.wav_write =
751
+ std::unique_ptr<CWaveFileWrite>(new CWaveFileWrite(output_wav_list_[i], output_sample_rate_,
752
+ num_output_channels_, 32, true));
753
+ if (!data.wav_write->initFile()) {
754
+ std::cerr << "Could not open file for writing: " << output_wav_list_[i] << std::endl;
755
+ return false;
756
+ }
757
+ data.output_file_num = 0;
758
+
759
+ stream_data_.push_back(std::move(data));
760
+ #ifndef ENABLE_PERF_DUMP
761
+ std::cout << "Input wav file: " << input_wav_list_[i] << std::endl
762
+ << "Total " << data.num_samples << " samples read" << std::endl;
763
+ #endif // ENABLE_PERF_DUMP
764
+ }
765
+
766
+ // make all sizes same to ease effect run loop's work
767
+ for (auto& v : stream_data_) {
768
+ v.input_wav_samples->resize(max_num_samples);
769
+ }
770
+
771
+ float frame_in_secs = static_cast<float>(num_input_samples_per_frame_) /
772
+ static_cast<float>(input_sample_rate_);
773
+ float total_audio_duration = 0.f;
774
+ float checkpoint = 0.1f;
775
+ float expected_audio_duration = static_cast<float>(max_num_samples) /
776
+ static_cast<float>(input_sample_rate_);
777
+ std::vector<float> input_frame(num_input_channels_ * num_input_samples_per_frame_ * num_streams);
778
+ std::vector<float> output_frame(num_output_channels_ * num_output_samples_per_frame_ * num_streams);
779
+
780
+ std::string progress_bar = "[ ] ";
781
+ std::cout << "Processed: " << progress_bar << "0%\r";
782
+ std::cout.flush();
783
+
784
+ uint32_t current_iteration = 0;
785
+ activity_map_.resize(input_wav_list_.size(), NVAFX_FALSE);
786
+ reset_map_.resize(input_wav_list_.size(), NVAFX_FALSE);
787
+ std::vector<uint32_t> current_active_streams;
788
+ std::vector<uint32_t> delayed_streams;
789
+ // wav data is already padded to align to num_input_samples_per_frame_ by ReadWavFile()
790
+ for (size_t offset = 0; offset < max_num_samples; offset += num_input_samples_per_frame_) {
791
+ // Run the delayed streams that have arrived now.
792
+ current_active_streams = active_streams;
793
+ delayed_streams = one_step_delay_streams;
794
+ if ((current_iteration + 1) % 3 == 0 && two_step_delay_streams.size()) {
795
+ delayed_streams = two_step_delay_streams;
796
+ runEffect(handle, delayed_streams, input_frame, output_frame);
797
+ for (const auto& stream_id : delayed_streams) {
798
+ if (!writeOutputWav(&output_frame[stream_id * num_output_samples_per_frame_],
799
+ num_output_samples_per_frame_, stream_id)) {
800
+ return false;
801
+ }
802
+ }
803
+ if (current_iteration % 2 != 0 && one_step_delay_streams.size()) {
804
+ delayed_streams.insert(delayed_streams.end(), one_step_delay_streams.begin(),
805
+ one_step_delay_streams.end());
806
+ current_active_streams.insert(current_active_streams.end(), one_step_delay_streams.begin(),
807
+ one_step_delay_streams.end());
808
+ }
809
+ runEffect(handle, delayed_streams, input_frame, output_frame);
810
+ for (const auto& stream_id : delayed_streams) {
811
+ if (!writeOutputWav(&output_frame[stream_id * num_output_samples_per_frame_],
812
+ num_output_samples_per_frame_, stream_id)) {
813
+ return false;
814
+ }
815
+ }
816
+ current_active_streams.insert(current_active_streams.end(), two_step_delay_streams.begin(),
817
+ two_step_delay_streams.end());
818
+ } else if (current_iteration % 2 != 0 && one_step_delay_streams.size()) {
819
+ runEffect(handle, delayed_streams, input_frame, output_frame);
820
+ for (const auto& stream_id : delayed_streams) {
821
+ if (!writeOutputWav(&output_frame[stream_id * num_output_samples_per_frame_],
822
+ num_output_samples_per_frame_, stream_id)) {
823
+ return false;
824
+ }
825
+ }
826
+ current_active_streams.insert(current_active_streams.end(), one_step_delay_streams.begin(),
827
+ one_step_delay_streams.end());
828
+ }
829
+ // Run the streams which are active for current iteration
830
+ runEffect(handle, current_active_streams, input_frame, output_frame);
831
+ total_audio_duration += frame_in_secs;
832
+ if ((total_audio_duration / expected_audio_duration) > checkpoint) {
833
+ progress_bar[checkpoint * 10] = '=';
834
+ std::cout << "Processed: " << progress_bar << checkpoint * 100.f << "% ";
835
+ std::cout << (checkpoint >=1 ? "\n" : "\r");
836
+ std::cout.flush();
837
+ checkpoint += 0.1f;
838
+ }
839
+
840
+ for (const auto& stream_id : current_active_streams) {
841
+ if (!writeOutputWav(&output_frame[stream_id * num_output_samples_per_frame_],
842
+ num_output_samples_per_frame_, stream_id)) {
843
+ return false;
844
+ }
845
+ }
846
+ ++current_iteration;
847
+ }
848
+
849
+ std::cout << "Processing time " << std::setprecision(2) << total_run_time_ << " secs for "
850
+ << total_audio_duration << std::setprecision(2) << " secs audio file (" << total_run_time_ / total_audio_duration
851
+ << " secs processing time per sec of audio)" << std::endl;
852
+
853
+ for (auto& v : stream_data_) {
854
+ v.wav_write->commitFile();
855
+ }
856
+
857
+ std::cout << "Output wav files written. " << std::endl;
858
+ if (NvAFX_DestroyEffect(handle) != NVAFX_STATUS_SUCCESS) {
859
+ std::cerr << "NvAFX_Release() failed" << std::endl;
860
+ return false;
861
+ }
862
+
863
+ if (NvAFX_UninitializeLogger() != NVAFX_STATUS_SUCCESS) {
864
+ std::cerr << "NvAFX_UninitializeLogger() failed" << std::endl;
865
+ return false;
866
+ }
867
+
868
+ return true;
869
+ }
870
+
871
+ void ShowHelpAndExit(const char* szBadOption) {
872
+ std::ostringstream oss;
873
+ bool bThrowError = false;
874
+ if (szBadOption) {
875
+ bThrowError = false;
876
+ oss << "Error parsing \"" << szBadOption << "\"" << std::endl;
877
+ }
878
+ std::cout << "Command Line Options:" << std::endl
879
+ << "-c Config file" << std::endl;
880
+
881
+ if (bThrowError) {
882
+ throw std::invalid_argument(oss.str());
883
+ } else {
884
+ std::cout << oss.str();
885
+ exit(0);
886
+ }
887
+ }
888
+
889
+ void ParseCommandLine(int argc, char* argv[], std::string* config_file) {
890
+ if (argc == 1) {
891
+ ShowHelpAndExit(nullptr);
892
+ }
893
+
894
+ for (int i = 1; i < argc; i++) {
895
+ if (!strcasecmp(argv[i], "-h")) {
896
+ ShowHelpAndExit(nullptr);
897
+ }
898
+ if (!strcasecmp(argv[i], "-c")) {
899
+ if (++i == argc || !config_file->empty()) {
900
+ ShowHelpAndExit("-f");
901
+ }
902
+ config_file->assign(argv[i]);
903
+ continue;
904
+ }
905
+
906
+ ShowHelpAndExit(argv[i]);
907
+ }
908
+ }
909
+
910
+ int main(int argc, char *argv[]) {
911
+ std::string config_file;
912
+ ParseCommandLine(argc, argv, &config_file);
913
+
914
+ ConfigReader config_reader;
915
+ if (config_reader.Load(config_file) == false) {
916
+ std::cerr << "Config file load failed" << std::endl;
917
+ return -1;
918
+ }
919
+
920
+ EffectsDemoApp app;
921
+ if (app.run(config_reader))
922
+ return 0;
923
+ else return -1;
924
+ }