nvidia-audiofx-filter.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944
  1. #include <stdint.h>
  2. #include <inttypes.h>
  3. #include <obs-module.h>
  4. #include <util/deque.h>
  5. #include <util/threading.h>
  6. #include <media-io/audio-resampler.h>
  7. #include "nvafx-load.h"
  8. #include <pthread.h>
  9. /* -------------------------------------------------------- */
  10. #define do_log(level, format, ...) \
  11. blog(level, "[NVIDIA Audio Effects: '%s'] " format, obs_source_get_name(ng->context), ##__VA_ARGS__)
  12. #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
  13. #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
  14. #ifdef _DEBUG
  15. #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
  16. #else
  17. #define debug(format, ...)
  18. #endif
  19. /* -------------------------------------------------------- */
  20. #define S_NVAFX_INTENSITY "intensity"
  21. #define S_METHOD "method"
  22. #define S_METHOD_NVAFX_DENOISER NVAFX_EFFECT_DENOISER
  23. #define S_METHOD_NVAFX_DEREVERB NVAFX_EFFECT_DEREVERB
  24. #define S_METHOD_NVAFX_DEREVERB_DENOISER NVAFX_EFFECT_DEREVERB_DENOISER
  25. #define S_NVAFX_VAD "vad"
  26. #define MT_ obs_module_text
  27. #define TEXT_NVAFX_INTENSITY MT_("Nvafx.Intensity")
  28. #define TEXT_METHOD MT_("Nvafx.Method")
  29. #define TEXT_METHOD_NVAFX_DENOISER MT_("Nvafx.Method.Denoiser")
  30. #define TEXT_METHOD_NVAFX_DEREVERB MT_("Nvafx.Method.Dereverb")
  31. #define TEXT_METHOD_NVAFX_DEREVERB_DENOISER MT_("Nvafx.Method.DenoiserPlusDereverb")
  32. #define TEXT_METHOD_NVAFX_DEPRECATION MT_("Nvafx.OutdatedSDK")
  33. #define TEXT_NVAFX_VAD MT_("Nvafx.VAD")
  34. #define MAX_PREPROC_CHANNELS 8
  35. #define BUFFER_SIZE_MSEC 10
  36. /* NVAFX constants, these can't be changed */
  37. #define NVAFX_SAMPLE_RATE 48000
  38. /* The SDK does not explicitly set this as a constant though it relies on it.*/
  39. #define NVAFX_FRAME_SIZE 480
  40. #ifdef _MSC_VER
  41. #define ssize_t intptr_t
  42. #endif
  43. bool nvafx_new_sdk = false;
  44. struct nvidia_audio_data {
  45. obs_source_t *context;
  46. uint64_t last_timestamp;
  47. uint64_t latency;
  48. size_t frames;
  49. size_t channels;
  50. struct deque info_buffer;
  51. struct deque input_buffers[MAX_PREPROC_CHANNELS];
  52. struct deque output_buffers[MAX_PREPROC_CHANNELS];
  53. /* This bool is quite important but it is easy to get lost. So let's
  54. * explain how it's used. One big issue is that the NVIDIA FX takes
  55. * ages to load an FX; so its initialization is deferred to a separate
  56. * thread.
  57. * First stage (creation):
  58. * - use_nvafx is set to true at creation of the filter, IF the SDK dir
  59. * path is set.
  60. * - if initialization fails, the bool is set to false & the filter is
  61. * destroyed.
  62. * Later stages (running or updating of the FX):
  63. * - they are executed ONLY if initialization was successful;
  64. * - if at any step, there's an FX failure, the bool is updated to false
  65. * & the filter is destroyed.
  66. */
  67. bool use_nvafx;
  68. /* this tracks if the SDK is found */
  69. bool nvidia_sdk_dir_found;
  70. bool has_mono_src;
  71. volatile bool reinit_done;
  72. /* NVAFX handle, one per audio channel */
  73. NvAFX_Handle handle[MAX_PREPROC_CHANNELS];
  74. uint32_t sample_rate;
  75. float intensity_ratio;
  76. unsigned int num_samples_per_frame, num_channels;
  77. char *model;
  78. bool nvafx_initialized;
  79. const char *fx;
  80. char *sdk_path;
  81. /* Resampler */
  82. audio_resampler_t *nvafx_resampler;
  83. audio_resampler_t *nvafx_resampler_back;
  84. /* We load the DLL in a separate thread because its loading is very
  85. * long and unnecessarily blocks OBS initial loading.
  86. * This bool is true once the thread which side loads the FX DLL is started */
  87. bool nvafx_loading;
  88. pthread_t nvafx_thread;
  89. pthread_mutex_t nvafx_mutex;
  90. /* PCM buffers */
  91. float *copy_buffers[MAX_PREPROC_CHANNELS];
  92. float *nvafx_segment_buffers[MAX_PREPROC_CHANNELS];
  93. /* output data */
  94. struct obs_audio_data output_audio;
  95. DARRAY(float) output_data;
  96. /* Optimization for Voice Audio Data (VAD) ; requires SDK >= 0.7.6 */
  97. bool vad;
  98. };
  99. static const char *nvidia_audio_name(void *unused)
  100. {
  101. UNUSED_PARAMETER(unused);
  102. return obs_module_text("Nvafx");
  103. }
  104. static void nvidia_audio_destroy(void *data)
  105. {
  106. struct nvidia_audio_data *ng = data;
  107. if (ng->nvidia_sdk_dir_found)
  108. pthread_mutex_lock(&ng->nvafx_mutex);
  109. NvAFX_UninitializeLogger();
  110. for (size_t i = 0; i < ng->channels; i++) {
  111. if (ng->handle[0]) {
  112. if (NvAFX_DestroyEffect) {
  113. NvAFX_Status err = NvAFX_DestroyEffect(ng->handle[i]);
  114. if (err != NVAFX_STATUS_SUCCESS) {
  115. do_log(LOG_ERROR, "NvAFX_Release() failed");
  116. }
  117. }
  118. }
  119. deque_free(&ng->input_buffers[i]);
  120. deque_free(&ng->output_buffers[i]);
  121. }
  122. bfree(ng->nvafx_segment_buffers[0]);
  123. if (ng->nvafx_resampler) {
  124. audio_resampler_destroy(ng->nvafx_resampler);
  125. audio_resampler_destroy(ng->nvafx_resampler_back);
  126. }
  127. bfree(ng->model);
  128. bfree(ng->sdk_path);
  129. bfree((void *)ng->fx);
  130. if (ng->nvidia_sdk_dir_found) {
  131. pthread_join(ng->nvafx_thread, NULL);
  132. pthread_mutex_unlock(&ng->nvafx_mutex);
  133. pthread_mutex_destroy(&ng->nvafx_mutex);
  134. }
  135. bfree(ng->copy_buffers[0]);
  136. deque_free(&ng->info_buffer);
  137. da_free(ng->output_data);
  138. bfree(ng);
  139. }
  140. bool nvidia_afx_initializer_mutex_initialized;
  141. pthread_mutex_t nvidia_afx_initializer_mutex;
  142. bool nvidia_afx_loaded = false;
  143. #ifdef _MSC_VER
  144. #pragma warning(push)
  145. #pragma warning(disable : 4706)
  146. #endif
  147. void release_afxlib(void)
  148. {
  149. NvAFX_GetEffectList = NULL;
  150. NvAFX_CreateEffect = NULL;
  151. NvAFX_CreateChainedEffect = NULL;
  152. NvAFX_DestroyEffect = NULL;
  153. NvAFX_SetU32 = NULL;
  154. NvAFX_SetU32List = NULL;
  155. NvAFX_SetString = NULL;
  156. NvAFX_SetStringList = NULL;
  157. NvAFX_SetFloat = NULL;
  158. NvAFX_SetFloatList = NULL;
  159. NvAFX_GetU32 = NULL;
  160. NvAFX_GetString = NULL;
  161. NvAFX_GetStringList = NULL;
  162. NvAFX_GetFloat = NULL;
  163. NvAFX_GetFloatList = NULL;
  164. NvAFX_Load = NULL;
  165. NvAFX_GetSupportedDevices = NULL;
  166. NvAFX_Run = NULL;
  167. NvAFX_Reset = NULL;
  168. if (nv_audiofx) {
  169. FreeLibrary(nv_audiofx);
  170. nv_audiofx = NULL;
  171. }
  172. cuCtxGetCurrent = NULL;
  173. cuCtxPopCurrent = NULL;
  174. cuInit = NULL;
  175. if (nv_cuda) {
  176. FreeLibrary(nv_cuda);
  177. nv_cuda = NULL;
  178. }
  179. }
  180. bool load_nvidia_afx(void)
  181. {
  182. unsigned int version = get_lib_version();
  183. uint8_t major = (version >> 24) & 0xff;
  184. uint8_t minor = (version >> 16) & 0x00ff;
  185. uint8_t build = (version >> 8) & 0x0000ff;
  186. uint8_t revision = (version >> 0) & 0x000000ff;
  187. if (version) {
  188. blog(LOG_INFO, "[NVIDIA Audio Effects:] version: %i.%i.%i.%i", major, minor, build, revision);
  189. if (version < MIN_AFX_SDK_VERSION) {
  190. blog(LOG_INFO,
  191. "[NVIDIA Audio Effects:]: SDK is outdated. Please update both audio & video SDK.\nRequired SDK versions, audio: %i.%i.%i; video: %i.%i.%i",
  192. (MIN_AFX_SDK_VERSION >> 24) & 0xff, (MIN_AFX_SDK_VERSION >> 16) & 0x00ff,
  193. (MIN_AFX_SDK_VERSION >> 8) & 0x0000ff, (MIN_VFX_SDK_VERSION >> 24) & 0xff,
  194. (MIN_VFX_SDK_VERSION >> 16) & 0x00ff, (MIN_VFX_SDK_VERSION >> 8) & 0x0000ff);
  195. }
  196. }
  197. if (!load_lib()) {
  198. blog(LOG_INFO,
  199. "[NVIDIA Audio Effects:] NVIDIA denoiser disabled, redistributable not found or could not be loaded.");
  200. return false;
  201. }
  202. nvidia_afx_initializer_mutex_initialized = pthread_mutex_init(&nvidia_afx_initializer_mutex, NULL) == 0;
  203. #define LOAD_SYM_FROM_LIB(sym, lib, dll) \
  204. if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \
  205. DWORD err = GetLastError(); \
  206. printf("[NVIDIA Audio Effects:]: Couldn't load " #sym " from " dll ": %lu (0x%lx)", err, err); \
  207. goto unload_everything; \
  208. }
  209. #define LOAD_SYM_FROM_LIB2(sym, lib, dll) \
  210. if (!(sym = (sym##_t)GetProcAddress(lib, #sym))) { \
  211. DWORD err = GetLastError(); \
  212. printf("[NVIDIA Audio Effects:]: Couldn't load " #sym " from " dll ": %lu (0x%lx)", err, err); \
  213. nvafx_new_sdk = false; \
  214. } else { \
  215. nvafx_new_sdk = true; \
  216. }
  217. #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_audiofx, "NVAudioEffects.dll")
  218. LOAD_SYM(NvAFX_GetEffectList);
  219. LOAD_SYM(NvAFX_CreateEffect);
  220. LOAD_SYM(NvAFX_CreateChainedEffect);
  221. LOAD_SYM(NvAFX_DestroyEffect);
  222. LOAD_SYM(NvAFX_SetU32);
  223. LOAD_SYM(NvAFX_SetU32List);
  224. LOAD_SYM(NvAFX_SetString);
  225. LOAD_SYM(NvAFX_SetStringList);
  226. LOAD_SYM(NvAFX_SetFloat);
  227. LOAD_SYM(NvAFX_SetFloatList);
  228. LOAD_SYM(NvAFX_GetU32);
  229. LOAD_SYM(NvAFX_GetString);
  230. LOAD_SYM(NvAFX_GetStringList);
  231. LOAD_SYM(NvAFX_GetFloat);
  232. LOAD_SYM(NvAFX_GetFloatList);
  233. LOAD_SYM(NvAFX_Load);
  234. LOAD_SYM(NvAFX_GetSupportedDevices);
  235. LOAD_SYM(NvAFX_Run);
  236. LOAD_SYM(NvAFX_Reset);
  237. #undef LOAD_SYM
  238. #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB(sym, nv_cuda, "nvcuda.dll")
  239. LOAD_SYM(cuCtxGetCurrent);
  240. LOAD_SYM(cuCtxPopCurrent);
  241. LOAD_SYM(cuInit);
  242. #undef LOAD_SYM
  243. #define LOAD_SYM(sym) LOAD_SYM_FROM_LIB2(sym, nv_audiofx, "NVAudioEffects.dll")
  244. LOAD_SYM(NvAFX_InitializeLogger);
  245. bool new_sdk = nvafx_new_sdk;
  246. LOAD_SYM(NvAFX_UninitializeLogger);
  247. if (!nvafx_new_sdk || !new_sdk) {
  248. blog(LOG_INFO, "[NVIDIA AUDIO FX]: SDK loaded but old redistributable detected. Please upgrade.");
  249. nvafx_new_sdk = false;
  250. }
  251. #undef LOAD_SYM
  252. NvAFX_Status err;
  253. CUresult cudaerr;
  254. NvAFX_Handle h = NULL;
  255. cudaerr = cuInit(0);
  256. if (cudaerr != CUDA_SUCCESS) {
  257. goto cuda_errors;
  258. }
  259. CUcontext old = {0};
  260. CUcontext curr = {0};
  261. cudaerr = cuCtxGetCurrent(&old);
  262. if (cudaerr != CUDA_SUCCESS) {
  263. goto cuda_errors;
  264. }
  265. err = NvAFX_CreateEffect(NVAFX_EFFECT_DENOISER, &h);
  266. cudaerr = cuCtxGetCurrent(&curr);
  267. if (cudaerr != CUDA_SUCCESS) {
  268. goto cuda_errors;
  269. }
  270. if (curr != old) {
  271. cudaerr = cuCtxPopCurrent(NULL);
  272. if (cudaerr != CUDA_SUCCESS)
  273. goto cuda_errors;
  274. }
  275. if (err != NVAFX_STATUS_SUCCESS) {
  276. if (err == NVAFX_STATUS_GPU_UNSUPPORTED) {
  277. blog(LOG_INFO, "[NVIDIA Audio Effects:] disabled: unsupported GPU");
  278. } else {
  279. blog(LOG_ERROR, "[NVIDIA Audio Effects:] disabled, error %i", err);
  280. }
  281. goto unload_everything;
  282. }
  283. err = NvAFX_DestroyEffect(h);
  284. if (err != NVAFX_STATUS_SUCCESS) {
  285. blog(LOG_ERROR, "[NVIDIA Audio Effects:]: disabled, error %i", err);
  286. goto unload_everything;
  287. }
  288. nvidia_afx_loaded = true;
  289. blog(LOG_INFO, "[NVIDIA Audio Effects:] enabled");
  290. return true;
  291. cuda_errors:
  292. blog(LOG_ERROR, "[NVIDIA Audio Effects:] disabled, CUDA error %i", cudaerr);
  293. unload_everything:
  294. release_afxlib();
  295. return false;
  296. }
  297. #ifdef _MSC_VER
  298. #pragma warning(pop)
  299. #endif
  300. void unload_nvidia_afx(void)
  301. {
  302. release_afxlib();
  303. if (nvidia_afx_initializer_mutex_initialized) {
  304. pthread_mutex_destroy(&nvidia_afx_initializer_mutex);
  305. nvidia_afx_initializer_mutex_initialized = false;
  306. }
  307. }
  308. static bool nvidia_audio_initialize_internal(void *data)
  309. {
  310. struct nvidia_audio_data *ng = data;
  311. NvAFX_Status err;
  312. if (!ng->handle[0]) {
  313. ng->sample_rate = NVAFX_SAMPLE_RATE;
  314. for (size_t i = 0; i < ng->channels; i++) {
  315. // Create FX
  316. CUcontext old = {0};
  317. CUcontext curr = {0};
  318. if (cuCtxGetCurrent(&old) != CUDA_SUCCESS) {
  319. goto failure;
  320. }
  321. err = NvAFX_CreateEffect(ng->fx, &ng->handle[i]);
  322. if (err != NVAFX_STATUS_SUCCESS) {
  323. do_log(LOG_ERROR, "%s FX creation failed, error %i", ng->fx, err);
  324. goto failure;
  325. }
  326. if (cuCtxGetCurrent(&curr) != CUDA_SUCCESS) {
  327. goto failure;
  328. }
  329. if (curr != old) {
  330. cuCtxPopCurrent(NULL);
  331. }
  332. // Set sample rate of FX
  333. err = NvAFX_SetU32(ng->handle[i], NVAFX_PARAM_INPUT_SAMPLE_RATE, ng->sample_rate);
  334. if (err != NVAFX_STATUS_SUCCESS) {
  335. do_log(LOG_ERROR, "NvAFX_SetU32(Sample Rate: %u) failed, error %i", ng->sample_rate,
  336. err);
  337. goto failure;
  338. }
  339. // Set intensity of FX
  340. err = NvAFX_SetFloat(ng->handle[i], NVAFX_PARAM_INTENSITY_RATIO, ng->intensity_ratio);
  341. if (err != NVAFX_STATUS_SUCCESS) {
  342. do_log(LOG_ERROR, "NvAFX_SetFloat(Intensity Ratio: %f) failed, error %i",
  343. ng->intensity_ratio, err);
  344. goto failure;
  345. }
  346. // Set VAD (Voice Audio Data)
  347. if (nvafx_new_sdk) {
  348. err = NvAFX_SetU32(ng->handle[i], NVAFX_PARAM_ENABLE_VAD, ng->vad);
  349. if (err != NVAFX_STATUS_SUCCESS) {
  350. do_log(LOG_ERROR, "NvAFX_SetU32(VAD: %i) failed, error %i", ng->vad, err);
  351. goto failure;
  352. }
  353. }
  354. // Set AI models path
  355. err = NvAFX_SetString(ng->handle[i], NVAFX_PARAM_MODEL_PATH, ng->model);
  356. if (err != NVAFX_STATUS_SUCCESS) {
  357. do_log(LOG_ERROR, "NvAFX_SetString() failed, error %i", err);
  358. goto failure;
  359. }
  360. // Load FX (this is a very long step, about 2 seconds)
  361. err = NvAFX_Load(ng->handle[i]);
  362. if (err != NVAFX_STATUS_SUCCESS) {
  363. do_log(LOG_ERROR, "NvAFX_Load() failed with error %i", err);
  364. goto failure;
  365. }
  366. os_atomic_set_bool(&ng->reinit_done, true);
  367. }
  368. }
  369. return true;
  370. failure:
  371. ng->use_nvafx = false;
  372. return false;
  373. }
  374. static void *nvidia_audio_disable(void *data)
  375. {
  376. struct nvidia_audio_data *ng = data;
  377. obs_source_t *filter = ng->context;
  378. obs_source_set_enabled(filter, false);
  379. info("NVIDIA Audio FX disabled due to an internal error.");
  380. return NULL;
  381. }
  382. static void *nvidia_audio_initialize(void *data)
  383. {
  384. struct nvidia_audio_data *ng = data;
  385. NvAFX_Status err;
  386. if (!ng->use_nvafx && !nvidia_afx_loaded) {
  387. return NULL;
  388. }
  389. pthread_mutex_lock(&ng->nvafx_mutex);
  390. pthread_mutex_lock(&nvidia_afx_initializer_mutex);
  391. if (!nvidia_audio_initialize_internal(data)) {
  392. goto failure;
  393. }
  394. if (ng->use_nvafx) {
  395. err = NvAFX_GetU32(ng->handle[0], NVAFX_PARAM_NUM_INPUT_CHANNELS, &ng->num_channels);
  396. if (err != NVAFX_STATUS_SUCCESS) {
  397. do_log(LOG_ERROR, "NvAFX_GetU32() failed to get the number of channels, error %i", err);
  398. goto failure;
  399. }
  400. if (ng->num_channels != 1) {
  401. do_log(LOG_ERROR, "The number of channels is not 1 in the sdk any more ==> update code");
  402. goto failure;
  403. }
  404. NvAFX_Status err = NvAFX_GetU32(ng->handle[0], NVAFX_PARAM_NUM_INPUT_SAMPLES_PER_FRAME,
  405. &ng->num_samples_per_frame);
  406. if (err != NVAFX_STATUS_SUCCESS) {
  407. do_log(LOG_ERROR, "NvAFX_GetU32() failed to get the number of samples per frame, error %i",
  408. err);
  409. goto failure;
  410. }
  411. if (ng->num_samples_per_frame != NVAFX_FRAME_SIZE) {
  412. do_log(LOG_ERROR,
  413. "The number of samples per frame has changed from 480 (= 10 ms) ==> update code");
  414. goto failure;
  415. }
  416. }
  417. ng->nvafx_initialized = true;
  418. ng->nvafx_loading = false;
  419. pthread_mutex_unlock(&nvidia_afx_initializer_mutex);
  420. pthread_mutex_unlock(&ng->nvafx_mutex);
  421. return NULL;
  422. failure:
  423. ng->use_nvafx = false;
  424. pthread_mutex_unlock(&nvidia_afx_initializer_mutex);
  425. pthread_mutex_unlock(&ng->nvafx_mutex);
  426. nvidia_audio_disable(ng);
  427. return NULL;
  428. }
  429. static inline enum speaker_layout nv_convert_speaker_layout(uint8_t channels)
  430. {
  431. switch (channels) {
  432. case 0:
  433. return SPEAKERS_UNKNOWN;
  434. case 1:
  435. return SPEAKERS_MONO;
  436. case 2:
  437. return SPEAKERS_STEREO;
  438. case 3:
  439. return SPEAKERS_2POINT1;
  440. case 4:
  441. return SPEAKERS_4POINT0;
  442. case 5:
  443. return SPEAKERS_4POINT1;
  444. case 6:
  445. return SPEAKERS_5POINT1;
  446. case 8:
  447. return SPEAKERS_7POINT1;
  448. default:
  449. return SPEAKERS_UNKNOWN;
  450. }
  451. }
  452. static void set_nv_model(void *data, const char *method)
  453. {
  454. struct nvidia_audio_data *ng = data;
  455. const char *file;
  456. if (strcmp(NVAFX_EFFECT_DEREVERB, method) == 0)
  457. file = NVAFX_EFFECT_DEREVERB_MODEL;
  458. else if (strcmp(NVAFX_EFFECT_DEREVERB_DENOISER, method) == 0)
  459. file = NVAFX_EFFECT_DEREVERB_DENOISER_MODEL;
  460. else
  461. file = NVAFX_EFFECT_DENOISER_MODEL;
  462. size_t size = strlen(ng->sdk_path) + strlen(file) + 1;
  463. char *buffer = (char *)bmalloc(size);
  464. strcpy(buffer, ng->sdk_path);
  465. strcat(buffer, file);
  466. ng->model = buffer;
  467. }
  468. static void nvidia_audio_update(void *data, obs_data_t *s)
  469. {
  470. struct nvidia_audio_data *ng = data;
  471. if (!ng->use_nvafx)
  472. return;
  473. const char *method = obs_data_get_string(s, S_METHOD);
  474. ng->latency = 1000000000LL / (1000 / BUFFER_SIZE_MSEC);
  475. float intensity = (float)obs_data_get_double(s, S_NVAFX_INTENSITY);
  476. bool vad = obs_data_get_bool(s, S_NVAFX_VAD);
  477. /*-------------------------------------------------------------------*/
  478. /* STAGE 1 : the following is run only when the filter is created. */
  479. /* If the DLL hasn't been loaded & isn't loading, start the side loading. */
  480. if (!ng->nvafx_initialized && !ng->nvafx_loading) {
  481. ng->intensity_ratio = intensity;
  482. ng->vad = vad;
  483. ng->nvafx_loading = true;
  484. pthread_create(&ng->nvafx_thread, NULL, nvidia_audio_initialize, ng);
  485. }
  486. /*-------------------------------------------------------------------*/
  487. /* STAGE 2 : this is executed only after the FX has been initialized */
  488. if (ng->nvafx_initialized) {
  489. /* updating the intensity of the FX */
  490. if (intensity != ng->intensity_ratio && (strcmp(ng->fx, method) == 0)) {
  491. NvAFX_Status err;
  492. ng->intensity_ratio = intensity;
  493. pthread_mutex_lock(&ng->nvafx_mutex);
  494. for (size_t i = 0; i < ng->channels; i++) {
  495. err = NvAFX_SetFloat(ng->handle[i], NVAFX_PARAM_INTENSITY_RATIO, ng->intensity_ratio);
  496. if (err != NVAFX_STATUS_SUCCESS) {
  497. do_log(LOG_ERROR, "NvAFX_SetFloat(Intensity Ratio: %f) failed, error %i",
  498. ng->intensity_ratio, err);
  499. nvidia_audio_disable(ng);
  500. }
  501. }
  502. pthread_mutex_unlock(&ng->nvafx_mutex);
  503. }
  504. /* updating for VAD toggled on or off */
  505. if (nvafx_new_sdk) {
  506. if (vad != ng->vad && (strcmp(ng->fx, method) == 0)) {
  507. NvAFX_Status err;
  508. ng->vad = vad;
  509. pthread_mutex_lock(&ng->nvafx_mutex);
  510. for (size_t i = 0; i < ng->channels; i++) {
  511. err = NvAFX_SetU32(ng->handle[i], NVAFX_PARAM_ENABLE_VAD, ng->vad);
  512. if (err != NVAFX_STATUS_SUCCESS) {
  513. do_log(LOG_ERROR, "NvAFX_SetU32(VAD: %i) failed, error %i", ng->vad,
  514. err);
  515. nvidia_audio_disable(ng);
  516. }
  517. }
  518. pthread_mutex_unlock(&ng->nvafx_mutex);
  519. }
  520. }
  521. /* swapping to a new FX requires a reinitialization */
  522. if ((strcmp(ng->fx, method) != 0)) {
  523. pthread_mutex_lock(&ng->nvafx_mutex);
  524. bfree((void *)ng->fx);
  525. ng->fx = bstrdup(method);
  526. ng->intensity_ratio = intensity;
  527. ng->vad = vad;
  528. set_nv_model(ng, method);
  529. os_atomic_set_bool(&ng->reinit_done, false);
  530. for (int i = 0; i < (int)ng->channels; i++) {
  531. /* Destroy previous FX */
  532. if (NvAFX_DestroyEffect(ng->handle[i]) != NVAFX_STATUS_SUCCESS) {
  533. do_log(LOG_ERROR, "FX failed to be destroyed.");
  534. nvidia_audio_disable(ng);
  535. } else {
  536. ng->handle[i] = NULL;
  537. }
  538. }
  539. if (!nvidia_audio_initialize_internal(data))
  540. nvidia_audio_disable(ng);
  541. pthread_mutex_unlock(&ng->nvafx_mutex);
  542. }
  543. }
  544. }
  545. static void nvafx_logger_callback(void *data, const char *msg)
  546. {
  547. UNUSED_PARAMETER(data);
  548. blog(LOG_ERROR, "[NVIDIA Audio Effects: Error - '%s'] ", msg);
  549. }
  550. static void *nvidia_audio_create(obs_data_t *settings, obs_source_t *filter)
  551. {
  552. struct nvidia_audio_data *ng = bzalloc(sizeof(struct nvidia_audio_data));
  553. ng->context = filter;
  554. char sdk_path[MAX_PATH];
  555. /* find SDK */
  556. if (!nvafx_get_sdk_path(sdk_path, sizeof(sdk_path))) {
  557. ng->nvidia_sdk_dir_found = false;
  558. do_log(LOG_ERROR, "NVAFX redist is not installed.");
  559. nvidia_audio_destroy(ng);
  560. return NULL;
  561. } else {
  562. size_t size = sizeof(sdk_path) + 1;
  563. ng->sdk_path = bmalloc(size);
  564. strcpy(ng->sdk_path, sdk_path);
  565. ng->nvidia_sdk_dir_found = true;
  566. ng->nvafx_initialized = false;
  567. ng->nvafx_loading = false;
  568. ng->fx = NULL;
  569. pthread_mutex_init(&ng->nvafx_mutex, NULL);
  570. info("NVAFX SDK redist path was found here %s", sdk_path);
  571. // set FX
  572. const char *method = obs_data_get_string(settings, S_METHOD);
  573. set_nv_model(ng, method);
  574. ng->fx = bstrdup(method);
  575. ng->use_nvafx = true;
  576. }
  577. /* Process 10 millisecond segments to keep latency low. */
  578. /* At 48kHz, NVAFX processes 480 samples which corresponds to 10 ms.*/
  579. uint32_t sample_rate = audio_output_get_sample_rate(obs_get_audio());
  580. size_t channels = audio_output_get_channels(obs_get_audio());
  581. size_t frames = (size_t)sample_rate / (1000 / BUFFER_SIZE_MSEC);
  582. ng->frames = frames;
  583. ng->channels = channels;
  584. /* allocate buffers */
  585. ng->copy_buffers[0] = bmalloc(frames * channels * sizeof(float));
  586. ng->nvafx_segment_buffers[0] = bmalloc(NVAFX_FRAME_SIZE * channels * sizeof(float));
  587. for (size_t c = 1; c < channels; ++c) {
  588. ng->copy_buffers[c] = ng->copy_buffers[c - 1] + frames;
  589. ng->nvafx_segment_buffers[c] = ng->nvafx_segment_buffers[c - 1] + NVAFX_FRAME_SIZE;
  590. }
  591. /* reserve circular buffers */
  592. for (size_t i = 0; i < channels; i++) {
  593. deque_reserve(&ng->input_buffers[i], frames * sizeof(float));
  594. deque_reserve(&ng->output_buffers[i], frames * sizeof(float));
  595. }
  596. /* create resampler if the source is not at 48 kHz */
  597. if (sample_rate == NVAFX_SAMPLE_RATE) {
  598. ng->nvafx_resampler = NULL;
  599. ng->nvafx_resampler_back = NULL;
  600. } else {
  601. struct resample_info src, dst;
  602. src.samples_per_sec = sample_rate;
  603. src.format = AUDIO_FORMAT_FLOAT_PLANAR;
  604. src.speakers = nv_convert_speaker_layout((uint8_t)channels);
  605. dst.samples_per_sec = NVAFX_SAMPLE_RATE;
  606. dst.format = AUDIO_FORMAT_FLOAT_PLANAR;
  607. dst.speakers = nv_convert_speaker_layout((uint8_t)channels);
  608. ng->nvafx_resampler = audio_resampler_create(&dst, &src);
  609. ng->nvafx_resampler_back = audio_resampler_create(&src, &dst);
  610. }
  611. /* VAD */
  612. ng->vad = 1;
  613. nvidia_audio_update(ng, settings);
  614. /* Setup NVIDIA logger */
  615. if (nvafx_new_sdk) {
  616. NvAFX_Status err = NvAFX_InitializeLogger(NVAFX_LOG_LEVEL_ERROR, LOG_TARGET_CALLBACK, NULL,
  617. &nvafx_logger_callback, ng);
  618. if (err != NVAFX_STATUS_SUCCESS) {
  619. warn("NvAFX logger failed to initialize.");
  620. }
  621. }
  622. return ng;
  623. }
  624. static inline void process_fx(struct nvidia_audio_data *ng)
  625. {
  626. /* Resample if necessary */
  627. if (ng->nvafx_resampler) {
  628. float *output[MAX_PREPROC_CHANNELS];
  629. uint32_t out_frames;
  630. uint64_t ts_offset;
  631. audio_resampler_resample(ng->nvafx_resampler, (uint8_t **)output, &out_frames, &ts_offset,
  632. (const uint8_t **)ng->copy_buffers, (uint32_t)ng->frames);
  633. for (size_t i = 0; i < ng->channels; i++) {
  634. for (ssize_t j = 0, k = (ssize_t)out_frames - NVAFX_FRAME_SIZE; j < NVAFX_FRAME_SIZE;
  635. ++j, ++k) {
  636. if (k >= 0) {
  637. ng->nvafx_segment_buffers[i][j] = output[i][k];
  638. } else {
  639. ng->nvafx_segment_buffers[i][j] = 0;
  640. }
  641. }
  642. }
  643. } else {
  644. for (size_t i = 0; i < ng->channels; i++) {
  645. for (size_t j = 0; j < NVAFX_FRAME_SIZE; ++j) {
  646. ng->nvafx_segment_buffers[i][j] = ng->copy_buffers[i][j];
  647. }
  648. }
  649. }
  650. /* Execute */
  651. size_t runs = ng->has_mono_src ? 1 : ng->channels;
  652. if (ng->reinit_done) {
  653. pthread_mutex_lock(&ng->nvafx_mutex);
  654. for (size_t i = 0; i < runs; i++) {
  655. NvAFX_Status err = NvAFX_Run(ng->handle[i], &ng->nvafx_segment_buffers[i],
  656. &ng->nvafx_segment_buffers[i], ng->num_samples_per_frame,
  657. ng->num_channels);
  658. if (err != NVAFX_STATUS_SUCCESS) {
  659. if (err == NVAFX_STATUS_FAILED) {
  660. do_log(LOG_DEBUG,
  661. "NvAFX_Run() failed, error NVAFX_STATUS_FAILED.\n"
  662. "This can occur when changing the FX and is not consequential.");
  663. // stop all processing; this will be reset at new init
  664. os_atomic_set_bool(&ng->reinit_done, false);
  665. } else {
  666. do_log(LOG_ERROR, "NvAFX_Run() failed, error %i.\n", err);
  667. }
  668. }
  669. }
  670. pthread_mutex_unlock(&ng->nvafx_mutex);
  671. }
  672. if (ng->has_mono_src) {
  673. memcpy(ng->nvafx_segment_buffers[1], ng->nvafx_segment_buffers[0], NVAFX_FRAME_SIZE * sizeof(float));
  674. }
  675. /* Revert signal level adjustment, resample back if necessary */
  676. if (ng->nvafx_resampler) {
  677. float *output[MAX_PREPROC_CHANNELS];
  678. uint32_t out_frames;
  679. uint64_t ts_offset;
  680. audio_resampler_resample(ng->nvafx_resampler_back, (uint8_t **)output, &out_frames, &ts_offset,
  681. (const uint8_t **)ng->nvafx_segment_buffers, NVAFX_FRAME_SIZE);
  682. for (size_t i = 0; i < ng->channels; i++) {
  683. for (ssize_t j = 0, k = (ssize_t)out_frames - ng->frames; j < (ssize_t)ng->frames; ++j, ++k) {
  684. if (k >= 0) {
  685. ng->copy_buffers[i][j] = output[i][k];
  686. } else {
  687. ng->copy_buffers[i][j] = 0;
  688. }
  689. }
  690. }
  691. } else {
  692. for (size_t i = 0; i < ng->channels; i++) {
  693. for (size_t j = 0; j < NVAFX_FRAME_SIZE; ++j) {
  694. ng->copy_buffers[i][j] = ng->nvafx_segment_buffers[i][j];
  695. }
  696. }
  697. }
  698. }
  699. static inline void process(struct nvidia_audio_data *ng)
  700. {
  701. /* Pop from input deque */
  702. for (size_t i = 0; i < ng->channels; i++)
  703. deque_pop_front(&ng->input_buffers[i], ng->copy_buffers[i], ng->frames * sizeof(float));
  704. if (ng->use_nvafx && nvidia_afx_loaded && ng->nvafx_initialized) {
  705. process_fx(ng);
  706. }
  707. /* Push to output deque */
  708. for (size_t i = 0; i < ng->channels; i++)
  709. deque_push_back(&ng->output_buffers[i], ng->copy_buffers[i], ng->frames * sizeof(float));
  710. }
  711. struct nv_audio_info {
  712. uint32_t frames;
  713. uint64_t timestamp;
  714. };
  715. static inline void clear_deque(struct deque *buf)
  716. {
  717. deque_pop_front(buf, NULL, buf->size);
  718. }
  719. static void reset_data(struct nvidia_audio_data *ng)
  720. {
  721. for (size_t i = 0; i < ng->channels; i++) {
  722. clear_deque(&ng->input_buffers[i]);
  723. clear_deque(&ng->output_buffers[i]);
  724. }
  725. clear_deque(&ng->info_buffer);
  726. }
  727. static struct obs_audio_data *nvidia_audio_filter_audio(void *data, struct obs_audio_data *audio)
  728. {
  729. struct nvidia_audio_data *ng = data;
  730. struct nv_audio_info info;
  731. size_t segment_size = ng->frames * sizeof(float);
  732. size_t out_size;
  733. obs_source_t *parent = obs_filter_get_parent(ng->context);
  734. if (!parent)
  735. return NULL;
  736. enum speaker_layout layout = obs_source_get_speaker_layout(parent);
  737. ng->has_mono_src = layout == SPEAKERS_MONO && ng->channels == 2;
  738. /* -----------------------------------------------
  739. * If timestamp has dramatically changed, consider it a new stream of
  740. * audio data. Clear all circular buffers to prevent old audio data
  741. * from being processed as part of the new data. */
  742. if (ng->last_timestamp) {
  743. int64_t diff = llabs((int64_t)ng->last_timestamp - (int64_t)audio->timestamp);
  744. if (diff > 1000000000LL)
  745. reset_data(ng);
  746. }
  747. ng->last_timestamp = audio->timestamp;
  748. /* -----------------------------------------------
  749. * push audio packet info (timestamp/frame count) to info deque */
  750. info.frames = audio->frames;
  751. info.timestamp = audio->timestamp;
  752. deque_push_back(&ng->info_buffer, &info, sizeof(info));
  753. /* -----------------------------------------------
  754. * push back current audio data to input deque */
  755. for (size_t i = 0; i < ng->channels; i++)
  756. deque_push_back(&ng->input_buffers[i], audio->data[i], audio->frames * sizeof(float));
  757. /* -----------------------------------------------
  758. * pop/process each 10ms segments, push back to output deque */
  759. while (ng->input_buffers[0].size >= segment_size)
  760. process(ng);
  761. /* -----------------------------------------------
  762. * peek front of info deque, check to see if we have enough to
  763. * pop the expected packet size, if not, return null */
  764. memset(&info, 0, sizeof(info));
  765. deque_peek_front(&ng->info_buffer, &info, sizeof(info));
  766. out_size = info.frames * sizeof(float);
  767. if (ng->output_buffers[0].size < out_size)
  768. return NULL;
  769. /* -----------------------------------------------
  770. * if there's enough audio data buffered in the output deque,
  771. * pop and return a packet */
  772. deque_pop_front(&ng->info_buffer, NULL, sizeof(info));
  773. da_resize(ng->output_data, out_size * ng->channels);
  774. for (size_t i = 0; i < ng->channels; i++) {
  775. ng->output_audio.data[i] = (uint8_t *)&ng->output_data.array[i * out_size];
  776. deque_pop_front(&ng->output_buffers[i], ng->output_audio.data[i], out_size);
  777. }
  778. ng->output_audio.frames = info.frames;
  779. ng->output_audio.timestamp = info.timestamp - ng->latency;
  780. return &ng->output_audio;
  781. }
  782. static void nvidia_audio_defaults(obs_data_t *s)
  783. {
  784. obs_data_set_default_double(s, S_NVAFX_INTENSITY, 1.0);
  785. obs_data_set_default_string(s, S_METHOD, S_METHOD_NVAFX_DENOISER);
  786. if (nvafx_new_sdk)
  787. obs_data_set_default_bool(s, S_NVAFX_VAD, 1);
  788. }
  789. static obs_properties_t *nvidia_audio_properties(void *data)
  790. {
  791. obs_properties_t *ppts = obs_properties_create();
  792. struct nvidia_audio_data *ng = (struct nvidia_audio_data *)data;
  793. obs_property_t *method =
  794. obs_properties_add_list(ppts, S_METHOD, TEXT_METHOD, OBS_COMBO_TYPE_LIST, OBS_COMBO_FORMAT_STRING);
  795. if (ng->nvidia_sdk_dir_found) {
  796. obs_property_list_add_string(method, TEXT_METHOD_NVAFX_DENOISER, S_METHOD_NVAFX_DENOISER);
  797. obs_property_list_add_string(method, TEXT_METHOD_NVAFX_DEREVERB, S_METHOD_NVAFX_DEREVERB);
  798. obs_property_list_add_string(method, TEXT_METHOD_NVAFX_DEREVERB_DENOISER,
  799. S_METHOD_NVAFX_DEREVERB_DENOISER);
  800. obs_property_t *slider = obs_properties_add_float_slider(ppts, S_NVAFX_INTENSITY, TEXT_NVAFX_INTENSITY,
  801. 0.0f, 1.0f, 0.01f);
  802. obs_property_t *vad = obs_properties_add_bool(ppts, S_NVAFX_VAD, TEXT_NVAFX_VAD);
  803. if (!nvafx_new_sdk)
  804. obs_property_set_visible(vad, 0);
  805. unsigned int version = get_lib_version();
  806. obs_property_t *warning = obs_properties_add_text(ppts, "deprecation", NULL, OBS_TEXT_INFO);
  807. if (version && version < MIN_AFX_SDK_VERSION) {
  808. obs_property_text_set_info_type(warning, OBS_TEXT_INFO_WARNING);
  809. obs_property_set_long_description(warning, TEXT_METHOD_NVAFX_DEPRECATION);
  810. } else {
  811. obs_property_set_visible(warning, 0);
  812. }
  813. }
  814. return ppts;
  815. }
  816. struct obs_source_info nvidia_audiofx_filter = {
  817. .id = "nvidia_audiofx_filter",
  818. .type = OBS_SOURCE_TYPE_FILTER,
  819. .output_flags = OBS_SOURCE_AUDIO,
  820. .get_name = nvidia_audio_name,
  821. .create = nvidia_audio_create,
  822. .destroy = nvidia_audio_destroy,
  823. .update = nvidia_audio_update,
  824. .filter_audio = nvidia_audio_filter_audio,
  825. .get_defaults = nvidia_audio_defaults,
  826. .get_properties = nvidia_audio_properties,
  827. };