You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

340 lines
9.8KB

  1. #include "stdafx.h"
  2. #define MY_VERSION "1.12"
  3. /*
  4. change log
  5. 2017-02-04 05:00 UTC - kode54
  6. - Add link to about string
  7. - Version is now 1.12
  8. 2011-12-19 03:09 UTC - kode54
  9. - Changed a number of constants to local variables in preparation for adding a
  10. configuration system
  11. - Restructured to use a large duration gated loudness measurement
  12. - Version is now 1.11
  13. 2011-02-07 14:12 UTC - kode54
  14. - Fixed a stupid bug in libebur128 when handling weird sample rates
  15. - Version is now 1.10
  16. 2011-02-05 06:11 UTC - kode54
  17. - Re-enabled increasing the gain level
  18. - Changed momentary and short-term loudness to gated loudness
  19. - Version is now 1.9
  20. 2011-02-04 13:44 UTC - kode54
  21. - Disabled increasing the gain level, for now
  22. - Version is now 1.8
  23. 2011-01-28 06:19 UTC - kode54
  24. - Fixed initial gain values on startup, again.
  25. - Version is now 1.7
  26. 2011-01-27 23:43 UTC - kode54
  27. - Now correctly flushes the buffer on playback termination
  28. - Version is now 1.6
  29. 2011-01-27 23:07 UTC - kode54
  30. - Reenabled momentary loudness polling
  31. - Changed volume ramping to 1 dB every 50ms
  32. - Current scale is now forced to the detected target scale after the initial
  33. buffering completes.
  34. - Version is now 1.5
  35. 2011-01-27 21:13 UTC - kode54
  36. - And decreased latency to maintain at least 500ms worth of samples
  37. - Version is now 1.4
  38. 2011-01-27 20:19 UTC - kode54
  39. - Increased latency to maintain a buffer of 3 seconds worth of samples
  40. 2011-01-27 20:06 UTC - kode54
  41. - Reverted short-term gain level changes to instantaneous again
  42. - Version is now 1.3
  43. 2011-01-27 19:58 UTC - kode54
  44. - Disabled momentary loudness polling and increased short-term loudness
  45. polling frequency
  46. - Version is now 1.2
  47. 2011-01-27 19:22 UTC - kode54
  48. - Adjusted gain level changes a bit
  49. - Version is now 1.1
  50. 2011-01-27 19:00 UTC - kode54
  51. - Initial release
  52. - Version is now 1.0
  53. 2011-01-27 16:53 UTC - kode54
  54. - Created project
  55. */
  56. class dsp_r128 : public dsp_impl_base
  57. {
  58. unsigned m_rate, m_ch, m_ch_mask;
  59. ebur128_state * m_state;
  60. dsp_chunk_list_impl sample_buffer;
  61. bool startup_complete;
  62. int frames_until_next;
  63. double current_scale;
  64. double target_scale;
  65. double scale_up;
  66. double scale_down;
  67. double latency_startup;
  68. double latency_minimum;
  69. double latency_window;
  70. double latency_update;
  71. double reference_loudness;
  72. unsigned block_count;
  73. public:
  74. dsp_r128() :
  75. current_scale(1.0), target_scale(1.0), latency_startup(10.0), latency_window(20.0), latency_minimum(4.0), latency_update(0.05), reference_loudness(-18.0),
  76. m_rate( 0 ), m_ch( 0 ), m_ch_mask( 0 ), m_state( NULL )
  77. {
  78. }
  79. ~dsp_r128()
  80. {
  81. if ( m_state ) ebur128_destroy( &m_state );
  82. }
  83. static GUID g_get_guid()
  84. {
  85. // {492763AA-867E-4941-9CF6-FAFC81D80737}
  86. static const GUID guid =
  87. { 0x492763aa, 0x867e, 0x4941, { 0x9c, 0xf6, 0xfa, 0xfc, 0x81, 0xd8, 0x7, 0x37 } };
  88. return guid;
  89. }
  90. static void g_get_name( pfc::string_base & p_out ) { p_out = "EBU R128 Compressor"; }
  91. bool on_chunk( audio_chunk * chunk, abort_callback & )
  92. {
  93. if ( chunk->get_srate() != m_rate || chunk->get_channels() != m_ch || chunk->get_channel_config() != m_ch_mask )
  94. {
  95. m_rate = chunk->get_srate();
  96. m_ch = chunk->get_channels();
  97. m_ch_mask = chunk->get_channel_config();
  98. reinitialize();
  99. flush_buffer();
  100. }
  101. if ( !startup_complete )
  102. {
  103. if ( ebur128_add_frames_float( m_state, chunk->get_data(), chunk->get_sample_count() ) ) return true;
  104. if ( sample_buffer.get_duration() + chunk->get_duration() < latency_startup )
  105. {
  106. audio_chunk * chunk_copy = sample_buffer.insert_item( sample_buffer.get_count(), chunk->get_data_size() );
  107. chunk_copy->copy( *chunk );
  108. return false;
  109. }
  110. }
  111. unsigned samples_added = 0;
  112. while ( samples_added < chunk->get_sample_count() )
  113. {
  114. unsigned samples_to_add = chunk->get_sample_count() - samples_added;
  115. if ( frames_until_next > 0 && frames_until_next < samples_to_add ) samples_to_add = frames_until_next;
  116. if ( frames_until_next <= 0 )
  117. {
  118. if (m_rate / 10 < samples_to_add) samples_to_add = m_rate / 10;
  119. frames_until_next += m_rate / 10;
  120. target_scale = loudness_to_scale( ebur128_loudness_global( m_state ) );
  121. }
  122. if ( ebur128_add_frames_float( m_state, chunk->get_data() + chunk->get_channels() * samples_added, samples_to_add ) ) return true;
  123. ebur128_gated_loudness_cleanup( m_state, block_count );
  124. samples_added += samples_to_add;
  125. frames_until_next -= samples_to_add;
  126. }
  127. if ( !startup_complete )
  128. {
  129. startup_complete = true;
  130. current_scale = target_scale;
  131. }
  132. #if 0
  133. flush_buffer();
  134. #else
  135. flush_buffer( latency_minimum );
  136. if ( sample_buffer.get_count() )
  137. {
  138. audio_chunk * copy_chunk = sample_buffer.insert_item( sample_buffer.get_count(), chunk->get_data_size() );
  139. copy_chunk->copy( *chunk );
  140. audio_chunk * output_chunk = sample_buffer.get_item( 0 );
  141. process_chunk( output_chunk );
  142. chunk->copy( *output_chunk );
  143. sample_buffer.remove_by_idx( 0 );
  144. }
  145. else
  146. #endif
  147. process_chunk( chunk );
  148. return true;
  149. }
  150. void on_endofplayback( abort_callback & )
  151. {
  152. flush_buffer();
  153. flush();
  154. }
  155. void on_endoftrack( abort_callback & ) { }
  156. void flush()
  157. {
  158. m_rate = 0;
  159. m_ch = 0;
  160. m_ch_mask = 0;
  161. #ifdef ENABLE_MOMENTARY
  162. momentary_scale = 1.0;
  163. #endif
  164. current_scale = 1.0;
  165. target_scale = 1.0;
  166. sample_buffer.remove_all();
  167. }
  168. double get_latency()
  169. {
  170. return sample_buffer.get_duration();
  171. }
  172. bool need_track_change_mark()
  173. {
  174. return false;
  175. }
  176. private:
  177. void reinitialize(void)
  178. {
  179. if ( m_state ) ebur128_destroy( &m_state );
  180. m_state = ebur128_init( m_ch, m_rate, EBUR128_MODE_I );
  181. if ( !m_state ) throw std::bad_alloc();
  182. pfc::array_t<int> channel_map;
  183. channel_map.set_count( m_ch );
  184. for ( unsigned i = 0; i < m_ch; i++ )
  185. {
  186. int channel = EBUR128_UNUSED;
  187. switch ( audio_chunk::g_extract_channel_flag( m_ch_mask, i ) )
  188. {
  189. case audio_chunk::channel_front_left: channel = EBUR128_LEFT; break;
  190. case audio_chunk::channel_front_right: channel = EBUR128_RIGHT; break;
  191. case audio_chunk::channel_front_center: channel = EBUR128_CENTER; break;
  192. case audio_chunk::channel_back_left: channel = EBUR128_LEFT_SURROUND; break;
  193. case audio_chunk::channel_back_right: channel = EBUR128_RIGHT_SURROUND; break;
  194. }
  195. channel_map[ i ] = channel;
  196. }
  197. ebur128_set_channel_map( m_state, channel_map.get_ptr() );
  198. block_count = (unsigned) (latency_window * 2.5 + 0.5);
  199. frames_until_next = 0;
  200. // Scale up or down by 1 dB every latency_update seconds
  201. scale_up = pow( pow( 10.0, 1.0 / 20.0 ), 1.0 / ( latency_update * double( m_rate ) ) );
  202. scale_down = pow( pow( 10.0, -1.0 / 20.0 ), 1.0 / ( latency_update * double( m_rate ) ) );
  203. startup_complete = false;
  204. }
  205. double loudness_to_scale(double lu)
  206. {
  207. if ( lu == std::numeric_limits<double>::quiet_NaN() || lu == std::numeric_limits<double>::infinity() || lu < -70 ) return 1.0;
  208. else return pow( 10.0, ( reference_loudness - lu ) / 20.0 );
  209. }
  210. // Increase by one decibel every 32 samples, or decrease by one decibel every 256 samples
  211. void update_scale()
  212. {
  213. if ( current_scale < target_scale )
  214. {
  215. current_scale *= scale_up; //1.00360429286956809;
  216. if ( current_scale > target_scale ) current_scale = target_scale;
  217. }
  218. else if ( current_scale > target_scale )
  219. {
  220. current_scale *= scale_down; //0.99955034255981445;
  221. if ( current_scale < target_scale ) current_scale = target_scale;
  222. }
  223. }
  224. void process_chunk( audio_chunk * chunk )
  225. {
  226. unsigned count = chunk->get_sample_count();
  227. unsigned channels = chunk->get_channels();
  228. audio_sample * sample = chunk->get_data();
  229. unsigned i;
  230. for ( i = 0; i < count; i++ )
  231. {
  232. if ( current_scale == target_scale ) break;
  233. for ( unsigned j = 0; j < channels; j++ )
  234. {
  235. *sample++ *= current_scale;
  236. }
  237. update_scale();
  238. }
  239. if ( i < count ) audio_math::scale( sample, ( count - i ) * channels, sample, current_scale );
  240. }
  241. void flush_buffer( double latency = 0 )
  242. {
  243. while ( sample_buffer.get_duration() > latency )
  244. {
  245. audio_chunk * buffered_chunk = sample_buffer.get_item( 0 );
  246. process_chunk( buffered_chunk );
  247. audio_chunk * output_chunk = insert_chunk( buffered_chunk->get_data_size() );
  248. output_chunk->copy( *buffered_chunk );
  249. sample_buffer.remove_by_idx( 0 );
  250. }
  251. }
  252. };
  253. static dsp_factory_nopreset_t<dsp_r128> g_dsp_r128_factory;
  254. DECLARE_COMPONENT_VERSION("EBU R128 Normalizer", MY_VERSION,
  255. "EBU R128 Normalizer.\n"
  256. "\n"
  257. "Copyright (C) 2011-2017 Christopher Snowhill\n"
  258. "\n"
  259. "https://www.patreon.com/kode54""\n"
  260. "\n"
  261. "\n"
  262. "Portions copyright (c) 2011 Jan Kokemüller\n"
  263. "\n"
  264. "Permission is hereby granted, free of charge, to any person obtaining a copy\n"
  265. "of this software and associated documentation files (the \"Software\"), to deal\n"
  266. "in the Software without restriction, including without limitation the rights\n"
  267. "to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n"
  268. "copies of the Software, and to permit persons to whom the Software is\n"
  269. "furnished to do so, subject to the following conditions:\n"
  270. "\n"
  271. "The above copyright notice and this permission notice shall be included in\n"
  272. "all copies or substantial portions of the Software.\n"
  273. "\n"
  274. "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n"
  275. "IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n"
  276. "FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n"
  277. "AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n"
  278. "LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n"
  279. "OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n"
  280. "THE SOFTWARE."
  281. );
  282. VALIDATE_COMPONENT_FILENAME("foo_r128norm.dll");