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