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 |
+
}
|