eq-filter.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #include <media-io/audio-math.h>
  2. #include <util/circlebuf.h>
  3. #include <util/darray.h>
  4. #include <obs-module.h>
  5. #include <math.h>
  6. #define LOW_FREQ 800.0f
  7. #define HIGH_FREQ 5000.0f
  8. struct eq_channel_state {
  9. float lf_delay0;
  10. float lf_delay1;
  11. float lf_delay2;
  12. float lf_delay3;
  13. float hf_delay0;
  14. float hf_delay1;
  15. float hf_delay2;
  16. float hf_delay3;
  17. float sample_delay1;
  18. float sample_delay2;
  19. float sample_delay3;
  20. };
  21. struct eq_data {
  22. obs_source_t *context;
  23. size_t channels;
  24. struct eq_channel_state eqs[MAX_AUDIO_CHANNELS];
  25. float lf;
  26. float hf;
  27. float low_gain;
  28. float mid_gain;
  29. float high_gain;
  30. };
  31. static const char *eq_name(void *unused)
  32. {
  33. UNUSED_PARAMETER(unused);
  34. return obs_module_text("3BandEq");
  35. }
  36. static void eq_update(void *data, obs_data_t *settings)
  37. {
  38. struct eq_data *eq = data;
  39. eq->low_gain = db_to_mul((float)obs_data_get_double(settings, "low"));
  40. eq->mid_gain = db_to_mul((float)obs_data_get_double(settings, "mid"));
  41. eq->high_gain = db_to_mul((float)obs_data_get_double(settings, "high"));
  42. }
  43. static void eq_defaults(obs_data_t *defaults)
  44. {
  45. obs_data_set_default_double(defaults, "low", 0.0);
  46. obs_data_set_default_double(defaults, "mid", 0.0);
  47. obs_data_set_default_double(defaults, "high", 0.0);
  48. }
  49. static obs_properties_t *eq_properties(void *unused)
  50. {
  51. obs_properties_t *props = obs_properties_create();
  52. obs_property_t *p;
  53. #define make_db_slider(name) \
  54. p = obs_properties_add_float_slider(props, name, \
  55. obs_module_text("3BandEq." name), \
  56. -20.0f, 20.0, 0.1); \
  57. obs_property_float_set_suffix(p, " dB");
  58. make_db_slider("high");
  59. make_db_slider("mid");
  60. make_db_slider("low");
  61. #undef make_db_slider
  62. UNUSED_PARAMETER(unused);
  63. return props;
  64. }
  65. static void *eq_create(obs_data_t *settings, obs_source_t *filter)
  66. {
  67. struct eq_data *eq = bzalloc(sizeof(*eq));
  68. eq->channels = audio_output_get_channels(obs_get_audio());
  69. eq->context = filter;
  70. float freq = (float)audio_output_get_sample_rate(obs_get_audio());
  71. eq->lf = 2.0f * sinf(M_PI * LOW_FREQ / freq);
  72. eq->hf = 2.0f * sinf(M_PI * HIGH_FREQ / freq);
  73. eq_update(eq, settings);
  74. return eq;
  75. }
  76. static void eq_destroy(void *data)
  77. {
  78. struct eq_data *eq = data;
  79. bfree(eq);
  80. }
  81. #define EQ_EPSILON (1.0f / 4294967295.0f)
  82. static inline float eq_process(struct eq_data *eq, struct eq_channel_state *c,
  83. float sample)
  84. {
  85. float l, m, h;
  86. c->lf_delay0 += eq->lf * (sample - c->lf_delay0) + EQ_EPSILON;
  87. c->lf_delay1 += eq->lf * (c->lf_delay0 - c->lf_delay1);
  88. c->lf_delay2 += eq->lf * (c->lf_delay1 - c->lf_delay2);
  89. c->lf_delay3 += eq->lf * (c->lf_delay2 - c->lf_delay3);
  90. l = c->lf_delay3;
  91. c->hf_delay0 += eq->hf * (sample - c->hf_delay0) + EQ_EPSILON;
  92. c->hf_delay1 += eq->hf * (c->hf_delay0 - c->hf_delay1);
  93. c->hf_delay2 += eq->hf * (c->hf_delay1 - c->hf_delay2);
  94. c->hf_delay3 += eq->hf * (c->hf_delay2 - c->hf_delay3);
  95. h = c->sample_delay3 - c->hf_delay3;
  96. m = c->sample_delay3 - (h + l);
  97. l *= eq->low_gain;
  98. m *= eq->mid_gain;
  99. h *= eq->high_gain;
  100. c->sample_delay3 = c->sample_delay2;
  101. c->sample_delay2 = c->sample_delay1;
  102. c->sample_delay1 = sample;
  103. return l + m + h;
  104. }
  105. static struct obs_audio_data *eq_filter_audio(void *data,
  106. struct obs_audio_data *audio)
  107. {
  108. struct eq_data *eq = data;
  109. const uint32_t frames = audio->frames;
  110. for (size_t c = 0; c < eq->channels; c++) {
  111. float *adata = (float *)audio->data[c];
  112. struct eq_channel_state *channel = &eq->eqs[c];
  113. for (size_t i = 0; i < frames; i++) {
  114. adata[i] = eq_process(eq, channel, adata[i]);
  115. }
  116. }
  117. return audio;
  118. }
  119. struct obs_source_info eq_filter = {
  120. .id = "basic_eq_filter",
  121. .type = OBS_SOURCE_TYPE_FILTER,
  122. .output_flags = OBS_SOURCE_AUDIO,
  123. .get_name = eq_name,
  124. .create = eq_create,
  125. .destroy = eq_destroy,
  126. .update = eq_update,
  127. .filter_audio = eq_filter_audio,
  128. .get_defaults = eq_defaults,
  129. .get_properties = eq_properties,
  130. };