noise-suppress-filter.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. #include <stdint.h>
  2. #include <inttypes.h>
  3. #include <util/deque.h>
  4. #include <util/threading.h>
  5. #include <obs-module.h>
  6. #ifdef LIBSPEEXDSP_ENABLED
  7. #include <speex/speex_preprocess.h>
  8. #endif
  9. #ifdef LIBRNNOISE_ENABLED
  10. #ifdef _MSC_VER
  11. #define ssize_t intptr_t
  12. #endif
  13. #include <rnnoise.h>
  14. #include <media-io/audio-resampler.h>
  15. #endif
  16. bool nvafx_loaded = false;
  17. #ifdef LIBNVAFX_ENABLED
  18. #include "nvafx-load.h"
  19. #include <pthread.h>
  20. #endif
  21. /* -------------------------------------------------------- */
  22. #define do_log(level, format, ...) \
  23. blog(level, "[noise suppress: '%s'] " format, \
  24. obs_source_get_name(ng->context), ##__VA_ARGS__)
  25. #define warn(format, ...) do_log(LOG_WARNING, format, ##__VA_ARGS__)
  26. #define info(format, ...) do_log(LOG_INFO, format, ##__VA_ARGS__)
  27. #ifdef _DEBUG
  28. #define debug(format, ...) do_log(LOG_DEBUG, format, ##__VA_ARGS__)
  29. #else
  30. #define debug(format, ...)
  31. #endif
  32. /* -------------------------------------------------------- */
  33. #define S_SUPPRESS_LEVEL "suppress_level"
  34. #define S_NVAFX_INTENSITY "intensity"
  35. #define S_METHOD "method"
  36. #define S_METHOD_SPEEX "speex"
  37. #define S_METHOD_RNN "rnnoise"
  38. #define S_METHOD_NVAFX_DENOISER "denoiser"
  39. #define S_METHOD_NVAFX_DEREVERB "dereverb"
  40. #define S_METHOD_NVAFX_DEREVERB_DENOISER "dereverb_denoiser"
  41. #define MT_ obs_module_text
  42. #define TEXT_SUPPRESS_LEVEL MT_("NoiseSuppress.SuppressLevel")
  43. #define TEXT_NVAFX_INTENSITY MT_("NoiseSuppress.Intensity")
  44. #define TEXT_METHOD MT_("NoiseSuppress.Method")
  45. #define TEXT_METHOD_SPEEX MT_("NoiseSuppress.Method.Speex")
  46. #define TEXT_METHOD_RNN MT_("NoiseSuppress.Method.RNNoise")
  47. #define TEXT_METHOD_NVAFX_DENOISER MT_("NoiseSuppress.Method.Nvafx.Denoiser")
  48. #define TEXT_METHOD_NVAFX_DEREVERB MT_("NoiseSuppress.Method.Nvafx.Dereverb")
  49. #define TEXT_METHOD_NVAFX_DEREVERB_DENOISER \
  50. MT_("NoiseSuppress.Method.Nvafx.DenoiserPlusDereverb")
  51. #define TEXT_METHOD_NVAFX_DEPRECATION \
  52. MT_("NoiseSuppress.Method.Nvafx.Deprecation")
  53. #define TEXT_METHOD_NVAFX_DEPRECATION2 \
  54. MT_("NoiseSuppress.Method.Nvafx.Deprecation2")
  55. #define MAX_PREPROC_CHANNELS 8
  56. /* RNNoise constants, these can't be changed */
  57. #define RNNOISE_SAMPLE_RATE 48000
  58. #define RNNOISE_FRAME_SIZE 480
  59. /* nvafx constants, these can't be changed */
  60. #define NVAFX_SAMPLE_RATE 48000
  61. #define NVAFX_FRAME_SIZE \
  62. 480 /* the sdk does not explicitly set this as a constant though it relies on it*/
  63. /* If the following constant changes, RNNoise breaks */
  64. #define BUFFER_SIZE_MSEC 10
  65. /* -------------------------------------------------------- */
  66. struct noise_suppress_data {
  67. obs_source_t *context;
  68. int suppress_level;
  69. uint64_t last_timestamp;
  70. uint64_t latency;
  71. size_t frames;
  72. size_t channels;
  73. struct deque info_buffer;
  74. struct deque input_buffers[MAX_PREPROC_CHANNELS];
  75. struct deque output_buffers[MAX_PREPROC_CHANNELS];
  76. bool use_rnnoise;
  77. bool nvafx_enabled;
  78. bool nvafx_migrated;
  79. #ifdef LIBNVAFX_ENABLED
  80. obs_source_t *migrated_filter;
  81. #endif
  82. bool has_mono_src;
  83. volatile bool reinit_done;
  84. #ifdef LIBSPEEXDSP_ENABLED
  85. /* Speex preprocessor state */
  86. SpeexPreprocessState *spx_states[MAX_PREPROC_CHANNELS];
  87. #endif
  88. #ifdef LIBRNNOISE_ENABLED
  89. /* RNNoise state */
  90. DenoiseState *rnn_states[MAX_PREPROC_CHANNELS];
  91. /* Resampler */
  92. audio_resampler_t *rnn_resampler;
  93. audio_resampler_t *rnn_resampler_back;
  94. #endif
  95. /* PCM buffers */
  96. float *copy_buffers[MAX_PREPROC_CHANNELS];
  97. #ifdef LIBSPEEXDSP_ENABLED
  98. spx_int16_t *spx_segment_buffers[MAX_PREPROC_CHANNELS];
  99. #endif
  100. #ifdef LIBRNNOISE_ENABLED
  101. float *rnn_segment_buffers[MAX_PREPROC_CHANNELS];
  102. #endif
  103. /* output data */
  104. struct obs_audio_data output_audio;
  105. DARRAY(float) output_data;
  106. };
  107. /* -------------------------------------------------------- */
  108. #define SUP_MIN -60
  109. #define SUP_MAX 0
  110. #ifdef LIBSPEEXDSP_ENABLED
  111. static const float c_32_to_16 = (float)INT16_MAX;
  112. static const float c_16_to_32 = ((float)INT16_MAX + 1.0f);
  113. #endif
  114. /* -------------------------------------------------------- */
  115. static const char *noise_suppress_name(void *unused)
  116. {
  117. UNUSED_PARAMETER(unused);
  118. return obs_module_text("NoiseSuppress");
  119. }
  120. static void noise_suppress_destroy(void *data)
  121. {
  122. struct noise_suppress_data *ng = data;
  123. for (size_t i = 0; i < ng->channels; i++) {
  124. #ifdef LIBSPEEXDSP_ENABLED
  125. speex_preprocess_state_destroy(ng->spx_states[i]);
  126. #endif
  127. #ifdef LIBRNNOISE_ENABLED
  128. rnnoise_destroy(ng->rnn_states[i]);
  129. #endif
  130. deque_free(&ng->input_buffers[i]);
  131. deque_free(&ng->output_buffers[i]);
  132. }
  133. #ifdef LIBSPEEXDSP_ENABLED
  134. bfree(ng->spx_segment_buffers[0]);
  135. #endif
  136. #ifdef LIBRNNOISE_ENABLED
  137. bfree(ng->rnn_segment_buffers[0]);
  138. if (ng->rnn_resampler) {
  139. audio_resampler_destroy(ng->rnn_resampler);
  140. audio_resampler_destroy(ng->rnn_resampler_back);
  141. }
  142. #endif
  143. bfree(ng->copy_buffers[0]);
  144. deque_free(&ng->info_buffer);
  145. da_free(ng->output_data);
  146. bfree(ng);
  147. }
  148. static inline void alloc_channel(struct noise_suppress_data *ng,
  149. uint32_t sample_rate, size_t channel,
  150. size_t frames)
  151. {
  152. #ifdef LIBSPEEXDSP_ENABLED
  153. ng->spx_states[channel] =
  154. speex_preprocess_state_init((int)frames, sample_rate);
  155. #else
  156. UNUSED_PARAMETER(sample_rate);
  157. #endif
  158. #ifdef LIBRNNOISE_ENABLED
  159. ng->rnn_states[channel] = rnnoise_create(NULL);
  160. #endif
  161. deque_reserve(&ng->input_buffers[channel], frames * sizeof(float));
  162. deque_reserve(&ng->output_buffers[channel], frames * sizeof(float));
  163. }
  164. static inline enum speaker_layout convert_speaker_layout(uint8_t channels)
  165. {
  166. switch (channels) {
  167. case 0:
  168. return SPEAKERS_UNKNOWN;
  169. case 1:
  170. return SPEAKERS_MONO;
  171. case 2:
  172. return SPEAKERS_STEREO;
  173. case 3:
  174. return SPEAKERS_2POINT1;
  175. case 4:
  176. return SPEAKERS_4POINT0;
  177. case 5:
  178. return SPEAKERS_4POINT1;
  179. case 6:
  180. return SPEAKERS_5POINT1;
  181. case 8:
  182. return SPEAKERS_7POINT1;
  183. default:
  184. return SPEAKERS_UNKNOWN;
  185. }
  186. }
  187. static void noise_suppress_update(void *data, obs_data_t *s)
  188. {
  189. struct noise_suppress_data *ng = data;
  190. uint32_t sample_rate = audio_output_get_sample_rate(obs_get_audio());
  191. size_t channels = audio_output_get_channels(obs_get_audio());
  192. size_t frames = (size_t)sample_rate / (1000 / BUFFER_SIZE_MSEC);
  193. const char *method = obs_data_get_string(s, S_METHOD);
  194. ng->suppress_level = (int)obs_data_get_int(s, S_SUPPRESS_LEVEL);
  195. ng->latency = 1000000000LL / (1000 / BUFFER_SIZE_MSEC);
  196. ng->use_rnnoise = strcmp(method, S_METHOD_RNN) == 0;
  197. /* Process 10 millisecond segments to keep latency low. */
  198. /* Also RNNoise only supports buffers of this exact size. */
  199. ng->frames = frames;
  200. ng->channels = channels;
  201. /* Ignore if already allocated */
  202. #if defined(LIBSPEEXDSP_ENABLED)
  203. if (!ng->use_rnnoise && ng->spx_states[0])
  204. return;
  205. #endif
  206. #ifdef LIBRNNOISE_ENABLED
  207. if (ng->use_rnnoise && ng->rnn_states[0])
  208. return;
  209. #endif
  210. /* One speex/rnnoise state for each channel (limit 2) */
  211. ng->copy_buffers[0] = bmalloc(frames * channels * sizeof(float));
  212. #ifdef LIBSPEEXDSP_ENABLED
  213. ng->spx_segment_buffers[0] =
  214. bmalloc(frames * channels * sizeof(spx_int16_t));
  215. #endif
  216. #ifdef LIBRNNOISE_ENABLED
  217. ng->rnn_segment_buffers[0] =
  218. bmalloc(RNNOISE_FRAME_SIZE * channels * sizeof(float));
  219. #endif
  220. for (size_t c = 1; c < channels; ++c) {
  221. ng->copy_buffers[c] = ng->copy_buffers[c - 1] + frames;
  222. #ifdef LIBSPEEXDSP_ENABLED
  223. ng->spx_segment_buffers[c] =
  224. ng->spx_segment_buffers[c - 1] + frames;
  225. #endif
  226. #ifdef LIBRNNOISE_ENABLED
  227. ng->rnn_segment_buffers[c] =
  228. ng->rnn_segment_buffers[c - 1] + RNNOISE_FRAME_SIZE;
  229. #endif
  230. }
  231. for (size_t i = 0; i < channels; i++)
  232. alloc_channel(ng, sample_rate, i, frames);
  233. #ifdef LIBRNNOISE_ENABLED
  234. if (sample_rate == RNNOISE_SAMPLE_RATE) {
  235. ng->rnn_resampler = NULL;
  236. ng->rnn_resampler_back = NULL;
  237. } else {
  238. struct resample_info src, dst;
  239. src.samples_per_sec = sample_rate;
  240. src.format = AUDIO_FORMAT_FLOAT_PLANAR;
  241. src.speakers = convert_speaker_layout((uint8_t)channels);
  242. dst.samples_per_sec = RNNOISE_SAMPLE_RATE;
  243. dst.format = AUDIO_FORMAT_FLOAT_PLANAR;
  244. dst.speakers = convert_speaker_layout((uint8_t)channels);
  245. ng->rnn_resampler = audio_resampler_create(&dst, &src);
  246. ng->rnn_resampler_back = audio_resampler_create(&src, &dst);
  247. }
  248. #endif
  249. }
  250. static void *noise_suppress_create(obs_data_t *settings, obs_source_t *filter)
  251. {
  252. struct noise_suppress_data *ng =
  253. bzalloc(sizeof(struct noise_suppress_data));
  254. ng->context = filter;
  255. ng->nvafx_enabled = false;
  256. ng->nvafx_migrated = false;
  257. #ifdef LIBNVAFX_ENABLED
  258. ng->migrated_filter = NULL;
  259. // If a NVAFX entry is detected, create a new instance of NVAFX filter.
  260. const char *method = obs_data_get_string(settings, S_METHOD);
  261. ng->nvafx_enabled = strcmp(method, S_METHOD_NVAFX_DENOISER) == 0 ||
  262. strcmp(method, S_METHOD_NVAFX_DEREVERB) == 0 ||
  263. strcmp(method, S_METHOD_NVAFX_DEREVERB_DENOISER) ==
  264. 0;
  265. if (ng->nvafx_enabled) {
  266. const char *str1 = obs_source_get_name(filter);
  267. char *str2 = "_ported";
  268. char *new_name =
  269. (char *)malloc(1 + strlen(str1) + strlen(str2));
  270. strcpy(new_name, str1);
  271. strcat(new_name, str2);
  272. obs_data_t *new_settings = obs_data_create();
  273. obs_data_set_string(new_settings, S_METHOD, method);
  274. double intensity =
  275. obs_data_get_double(settings, S_NVAFX_INTENSITY);
  276. obs_data_set_double(new_settings, S_NVAFX_INTENSITY, intensity);
  277. ng->migrated_filter = obs_source_create(
  278. "nvidia_audiofx_filter", new_name, new_settings, NULL);
  279. obs_data_release(new_settings);
  280. }
  281. #endif
  282. noise_suppress_update(ng, settings);
  283. return ng;
  284. }
  285. static inline void process_speexdsp(struct noise_suppress_data *ng)
  286. {
  287. #ifdef LIBSPEEXDSP_ENABLED
  288. /* Set args */
  289. for (size_t i = 0; i < ng->channels; i++)
  290. speex_preprocess_ctl(ng->spx_states[i],
  291. SPEEX_PREPROCESS_SET_NOISE_SUPPRESS,
  292. &ng->suppress_level);
  293. /* Convert to 16bit */
  294. for (size_t i = 0; i < ng->channels; i++)
  295. for (size_t j = 0; j < ng->frames; j++) {
  296. float s = ng->copy_buffers[i][j];
  297. if (s > 1.0f)
  298. s = 1.0f;
  299. else if (s < -1.0f)
  300. s = -1.0f;
  301. ng->spx_segment_buffers[i][j] =
  302. (spx_int16_t)(s * c_32_to_16);
  303. }
  304. /* Execute */
  305. for (size_t i = 0; i < ng->channels; i++)
  306. speex_preprocess_run(ng->spx_states[i],
  307. ng->spx_segment_buffers[i]);
  308. /* Convert back to 32bit */
  309. for (size_t i = 0; i < ng->channels; i++)
  310. for (size_t j = 0; j < ng->frames; j++)
  311. ng->copy_buffers[i][j] =
  312. (float)ng->spx_segment_buffers[i][j] /
  313. c_16_to_32;
  314. #else
  315. UNUSED_PARAMETER(ng);
  316. #endif
  317. }
  318. static inline void process_rnnoise(struct noise_suppress_data *ng)
  319. {
  320. #ifdef LIBRNNOISE_ENABLED
  321. /* Adjust signal level to what RNNoise expects, resample if necessary */
  322. if (ng->rnn_resampler) {
  323. float *output[MAX_PREPROC_CHANNELS];
  324. uint32_t out_frames;
  325. uint64_t ts_offset;
  326. audio_resampler_resample(ng->rnn_resampler, (uint8_t **)output,
  327. &out_frames, &ts_offset,
  328. (const uint8_t **)ng->copy_buffers,
  329. (uint32_t)ng->frames);
  330. for (size_t i = 0; i < ng->channels; i++) {
  331. for (ssize_t j = 0, k = (ssize_t)out_frames -
  332. RNNOISE_FRAME_SIZE;
  333. j < RNNOISE_FRAME_SIZE; ++j, ++k) {
  334. if (k >= 0) {
  335. ng->rnn_segment_buffers[i][j] =
  336. output[i][k] * 32768.0f;
  337. } else {
  338. ng->rnn_segment_buffers[i][j] = 0;
  339. }
  340. }
  341. }
  342. } else {
  343. for (size_t i = 0; i < ng->channels; i++) {
  344. for (size_t j = 0; j < RNNOISE_FRAME_SIZE; ++j) {
  345. ng->rnn_segment_buffers[i][j] =
  346. ng->copy_buffers[i][j] * 32768.0f;
  347. }
  348. }
  349. }
  350. /* Execute */
  351. for (size_t i = 0; i < ng->channels; i++) {
  352. rnnoise_process_frame(ng->rnn_states[i],
  353. ng->rnn_segment_buffers[i],
  354. ng->rnn_segment_buffers[i]);
  355. }
  356. /* Revert signal level adjustment, resample back if necessary */
  357. if (ng->rnn_resampler) {
  358. float *output[MAX_PREPROC_CHANNELS];
  359. uint32_t out_frames;
  360. uint64_t ts_offset;
  361. audio_resampler_resample(
  362. ng->rnn_resampler_back, (uint8_t **)output, &out_frames,
  363. &ts_offset, (const uint8_t **)ng->rnn_segment_buffers,
  364. RNNOISE_FRAME_SIZE);
  365. for (size_t i = 0; i < ng->channels; i++) {
  366. for (ssize_t j = 0,
  367. k = (ssize_t)out_frames - ng->frames;
  368. j < (ssize_t)ng->frames; ++j, ++k) {
  369. if (k >= 0) {
  370. ng->copy_buffers[i][j] =
  371. output[i][k] / 32768.0f;
  372. } else {
  373. ng->copy_buffers[i][j] = 0;
  374. }
  375. }
  376. }
  377. } else {
  378. for (size_t i = 0; i < ng->channels; i++) {
  379. for (size_t j = 0; j < RNNOISE_FRAME_SIZE; ++j) {
  380. ng->copy_buffers[i][j] =
  381. ng->rnn_segment_buffers[i][j] /
  382. 32768.0f;
  383. }
  384. }
  385. }
  386. #else
  387. UNUSED_PARAMETER(ng);
  388. #endif
  389. }
  390. static inline void process(struct noise_suppress_data *ng)
  391. {
  392. if (ng->nvafx_enabled)
  393. return;
  394. /* Pop from input deque */
  395. for (size_t i = 0; i < ng->channels; i++)
  396. deque_pop_front(&ng->input_buffers[i], ng->copy_buffers[i],
  397. ng->frames * sizeof(float));
  398. if (ng->use_rnnoise) {
  399. process_rnnoise(ng);
  400. } else {
  401. process_speexdsp(ng);
  402. }
  403. /* Push to output deque */
  404. for (size_t i = 0; i < ng->channels; i++)
  405. deque_push_back(&ng->output_buffers[i], ng->copy_buffers[i],
  406. ng->frames * sizeof(float));
  407. }
  408. struct ng_audio_info {
  409. uint32_t frames;
  410. uint64_t timestamp;
  411. };
  412. static inline void clear_deque(struct deque *buf)
  413. {
  414. deque_pop_front(buf, NULL, buf->size);
  415. }
  416. static void reset_data(struct noise_suppress_data *ng)
  417. {
  418. for (size_t i = 0; i < ng->channels; i++) {
  419. clear_deque(&ng->input_buffers[i]);
  420. clear_deque(&ng->output_buffers[i]);
  421. }
  422. clear_deque(&ng->info_buffer);
  423. }
  424. static struct obs_audio_data *
  425. noise_suppress_filter_audio(void *data, struct obs_audio_data *audio)
  426. {
  427. struct noise_suppress_data *ng = data;
  428. struct ng_audio_info info;
  429. size_t segment_size = ng->frames * sizeof(float);
  430. size_t out_size;
  431. obs_source_t *parent = obs_filter_get_parent(ng->context);
  432. enum speaker_layout layout = obs_source_get_speaker_layout(parent);
  433. ng->has_mono_src = layout == SPEAKERS_MONO && ng->channels == 2;
  434. #ifdef LIBNVAFX_ENABLED
  435. /* Migrate nvafx to new filter. */
  436. if (ng->nvafx_enabled) {
  437. if (!ng->nvafx_migrated) {
  438. obs_source_filter_add(parent, ng->migrated_filter);
  439. obs_source_set_enabled(ng->migrated_filter, true);
  440. obs_source_filter_remove(parent, ng->context);
  441. ng->nvafx_migrated = true;
  442. }
  443. return audio;
  444. }
  445. #endif
  446. #ifdef LIBSPEEXDSP_ENABLED
  447. if (!ng->spx_states[0])
  448. return audio;
  449. #endif
  450. #ifdef LIBRNNOISE_ENABLED
  451. if (!ng->rnn_states[0])
  452. return audio;
  453. #endif
  454. /* -----------------------------------------------
  455. * if timestamp has dramatically changed, consider it a new stream of
  456. * audio data. clear all circular buffers to prevent old audio data
  457. * from being processed as part of the new data. */
  458. if (ng->last_timestamp) {
  459. int64_t diff = llabs((int64_t)ng->last_timestamp -
  460. (int64_t)audio->timestamp);
  461. if (diff > 1000000000LL)
  462. reset_data(ng);
  463. }
  464. ng->last_timestamp = audio->timestamp;
  465. /* -----------------------------------------------
  466. * push audio packet info (timestamp/frame count) to info deque */
  467. info.frames = audio->frames;
  468. info.timestamp = audio->timestamp;
  469. deque_push_back(&ng->info_buffer, &info, sizeof(info));
  470. /* -----------------------------------------------
  471. * push back current audio data to input deque */
  472. for (size_t i = 0; i < ng->channels; i++)
  473. deque_push_back(&ng->input_buffers[i], audio->data[i],
  474. audio->frames * sizeof(float));
  475. /* -----------------------------------------------
  476. * pop/process each 10ms segments, push back to output deque */
  477. while (ng->input_buffers[0].size >= segment_size)
  478. process(ng);
  479. /* -----------------------------------------------
  480. * peek front of info deque, check to see if we have enough to
  481. * pop the expected packet size, if not, return null */
  482. memset(&info, 0, sizeof(info));
  483. deque_peek_front(&ng->info_buffer, &info, sizeof(info));
  484. out_size = info.frames * sizeof(float);
  485. if (ng->output_buffers[0].size < out_size)
  486. return NULL;
  487. /* -----------------------------------------------
  488. * if there's enough audio data buffered in the output deque,
  489. * pop and return a packet */
  490. deque_pop_front(&ng->info_buffer, NULL, sizeof(info));
  491. da_resize(ng->output_data, out_size * ng->channels);
  492. for (size_t i = 0; i < ng->channels; i++) {
  493. ng->output_audio.data[i] =
  494. (uint8_t *)&ng->output_data.array[i * out_size];
  495. deque_pop_front(&ng->output_buffers[i],
  496. ng->output_audio.data[i], out_size);
  497. }
  498. ng->output_audio.frames = info.frames;
  499. ng->output_audio.timestamp = info.timestamp - ng->latency;
  500. return &ng->output_audio;
  501. }
  502. static bool noise_suppress_method_modified(obs_properties_t *props,
  503. obs_property_t *property,
  504. obs_data_t *settings)
  505. {
  506. obs_property_t *p_suppress_level =
  507. obs_properties_get(props, S_SUPPRESS_LEVEL);
  508. obs_property_t *p_navfx_intensity =
  509. obs_properties_get(props, S_NVAFX_INTENSITY);
  510. const char *method = obs_data_get_string(settings, S_METHOD);
  511. bool enable_level = strcmp(method, S_METHOD_SPEEX) == 0;
  512. bool enable_intensity =
  513. strcmp(method, S_METHOD_NVAFX_DENOISER) == 0 ||
  514. strcmp(method, S_METHOD_NVAFX_DEREVERB) == 0 ||
  515. strcmp(method, S_METHOD_NVAFX_DEREVERB_DENOISER) == 0;
  516. obs_property_set_visible(p_suppress_level, enable_level);
  517. obs_property_set_visible(p_navfx_intensity, enable_intensity);
  518. UNUSED_PARAMETER(property);
  519. return true;
  520. }
  521. static void noise_suppress_defaults_v1(obs_data_t *s)
  522. {
  523. obs_data_set_default_int(s, S_SUPPRESS_LEVEL, -30);
  524. #if defined(LIBRNNOISE_ENABLED) && !defined(LIBSPEEXDSP_ENABLED)
  525. obs_data_set_default_string(s, S_METHOD, S_METHOD_RNN);
  526. #else
  527. obs_data_set_default_string(s, S_METHOD, S_METHOD_SPEEX);
  528. #endif
  529. #if defined(LIBNVAFX_ENABLED)
  530. obs_data_set_default_double(s, S_NVAFX_INTENSITY, 1.0);
  531. #endif
  532. }
  533. static void noise_suppress_defaults_v2(obs_data_t *s)
  534. {
  535. obs_data_set_default_int(s, S_SUPPRESS_LEVEL, -30);
  536. #if defined(LIBRNNOISE_ENABLED)
  537. obs_data_set_default_string(s, S_METHOD, S_METHOD_RNN);
  538. #else
  539. obs_data_set_default_string(s, S_METHOD, S_METHOD_SPEEX);
  540. #endif
  541. #if defined(LIBNVAFX_ENABLED)
  542. obs_data_set_default_double(s, S_NVAFX_INTENSITY, 1.0);
  543. #endif
  544. }
  545. static obs_properties_t *noise_suppress_properties(void *data)
  546. {
  547. obs_properties_t *ppts = obs_properties_create();
  548. #ifdef LIBNVAFX_ENABLED
  549. struct noise_suppress_data *ng = (struct noise_suppress_data *)data;
  550. #else
  551. UNUSED_PARAMETER(data);
  552. #endif
  553. #if defined(LIBRNNOISE_ENABLED) && defined(LIBSPEEXDSP_ENABLED)
  554. obs_property_t *method = obs_properties_add_list(
  555. ppts, S_METHOD, TEXT_METHOD, OBS_COMBO_TYPE_LIST,
  556. OBS_COMBO_FORMAT_STRING);
  557. obs_property_list_add_string(method, TEXT_METHOD_SPEEX, S_METHOD_SPEEX);
  558. obs_property_list_add_string(method, TEXT_METHOD_RNN, S_METHOD_RNN);
  559. #ifdef LIBNVAFX_ENABLED
  560. if (ng->nvafx_enabled) {
  561. obs_property_list_add_string(method, TEXT_METHOD_NVAFX_DENOISER,
  562. S_METHOD_NVAFX_DENOISER);
  563. obs_property_list_add_string(method, TEXT_METHOD_NVAFX_DEREVERB,
  564. S_METHOD_NVAFX_DEREVERB);
  565. obs_property_list_add_string(
  566. method, TEXT_METHOD_NVAFX_DEREVERB_DENOISER,
  567. S_METHOD_NVAFX_DEREVERB_DENOISER);
  568. obs_property_list_item_disable(method, 2, true);
  569. obs_property_list_item_disable(method, 3, true);
  570. obs_property_list_item_disable(method, 4, true);
  571. }
  572. #endif
  573. obs_property_set_modified_callback(method,
  574. noise_suppress_method_modified);
  575. #endif
  576. #ifdef LIBSPEEXDSP_ENABLED
  577. obs_property_t *speex_slider = obs_properties_add_int_slider(
  578. ppts, S_SUPPRESS_LEVEL, TEXT_SUPPRESS_LEVEL, SUP_MIN, SUP_MAX,
  579. 1);
  580. obs_property_int_set_suffix(speex_slider, " dB");
  581. #endif
  582. #ifdef LIBNVAFX_ENABLED
  583. if (ng->nvafx_enabled) {
  584. obs_properties_add_float_slider(ppts, S_NVAFX_INTENSITY,
  585. TEXT_NVAFX_INTENSITY, 0.0f,
  586. 1.0f, 0.01f);
  587. obs_property_t *warning2 = obs_properties_add_text(
  588. ppts, "deprecation2", NULL, OBS_TEXT_INFO);
  589. obs_property_text_set_info_type(warning2,
  590. OBS_TEXT_INFO_WARNING);
  591. obs_property_set_long_description(
  592. warning2, TEXT_METHOD_NVAFX_DEPRECATION2);
  593. }
  594. #if defined(LIBRNNOISE_ENABLED) && defined(LIBSPEEXDSP_ENABLED)
  595. if (!nvafx_loaded) {
  596. obs_property_list_item_disable(method, 2, true);
  597. obs_property_list_item_disable(method, 3, true);
  598. obs_property_list_item_disable(method, 4, true);
  599. }
  600. #endif
  601. #endif
  602. return ppts;
  603. }
  604. struct obs_source_info noise_suppress_filter = {
  605. .id = "noise_suppress_filter",
  606. .type = OBS_SOURCE_TYPE_FILTER,
  607. .output_flags = OBS_SOURCE_AUDIO | OBS_SOURCE_CAP_OBSOLETE,
  608. .get_name = noise_suppress_name,
  609. .create = noise_suppress_create,
  610. .destroy = noise_suppress_destroy,
  611. .update = noise_suppress_update,
  612. .filter_audio = noise_suppress_filter_audio,
  613. .get_defaults = noise_suppress_defaults_v1,
  614. .get_properties = noise_suppress_properties,
  615. };
  616. struct obs_source_info noise_suppress_filter_v2 = {
  617. .id = "noise_suppress_filter",
  618. .version = 2,
  619. .type = OBS_SOURCE_TYPE_FILTER,
  620. .output_flags = OBS_SOURCE_AUDIO,
  621. .get_name = noise_suppress_name,
  622. .create = noise_suppress_create,
  623. .destroy = noise_suppress_destroy,
  624. .update = noise_suppress_update,
  625. .filter_audio = noise_suppress_filter_audio,
  626. .get_defaults = noise_suppress_defaults_v2,
  627. .get_properties = noise_suppress_properties,
  628. };