nvidia-audiofx-filter.c 26 KB

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