audiodbmeter.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #include "precompile.h"
  2. #include "audiodbmeter.h"
  3. #include "audiocontext.h"
  4. #include <math.h>
  5. #include <assert.h>
  6. #ifdef _WIN32
  7. #include <crtdbg.h>
  8. #else
  9. #endif // _WIN32
  10. #define DB_RANGE 60.0
  11. #define READ_IDX (STREAM_DIR_READ-1)
  12. #define WRITE_IDX (STREAM_DIR_WRITE-1)
  13. static const float const_1_div_32768_ = 1.0f / 32768.f; /* 16 bit multiplier */
  14. static float ClipZeroToOne(float z)
  15. {
  16. if (z > 1.0)
  17. return 1.0;
  18. else if (z < 0.0)
  19. return 0.0;
  20. else
  21. return z;
  22. }
  23. static float ToDB(float v, float range)
  24. {
  25. float db;
  26. if (v > 0)
  27. db = 20 * log10(fabs(v));
  28. else
  29. db = -999;
  30. return ClipZeroToOne((db + range) / range);
  31. }
  32. static apr_status_t read_frame(void *self, audioframe_t *frame)
  33. {
  34. audiodbmeter_t *audiometer = CONTAINING_RECORD(self, audiodbmeter_t, base);
  35. apr_status_t status;
  36. status = audiometer->base.downstream->vtbl->read_frame(audiometer->base.downstream, frame);
  37. if (status == APR_SUCCESS && frame->size > 0) {
  38. int i;
  39. int frames = frame->size / 2;
  40. short *sptr = (short*)frame->buffer;
  41. float peak = 0.0;
  42. float rms = 0.0;
  43. int old;
  44. for (i = 0; i < frames; ++i) {
  45. float v = *sptr * const_1_div_32768_;
  46. peak = (float)max(v, peak);
  47. rms += (float)(v * v);
  48. sptr++;
  49. }
  50. rms = sqrt(rms / frames);
  51. rms = ToDB(rms, DB_RANGE);
  52. peak = ToDB(peak, DB_RANGE);
  53. old = audiometer->stat[READ_IDX].rms;
  54. audiometer->stat[READ_IDX].rms = (old * 9 + (int)(100*rms)) / 10;
  55. old = audiometer->stat[READ_IDX].peak;
  56. audiometer->stat[READ_IDX].peak = (old * 9 + (int)(100*peak)) / 10;
  57. }
  58. return APR_SUCCESS;
  59. }
  60. static apr_status_t write_frame(void *self, const audioframe_t *frame)
  61. {
  62. audiodbmeter_t *audiometer = CONTAINING_RECORD(self, audiodbmeter_t, base);
  63. apr_status_t status;
  64. status = audiometer->base.downstream->vtbl->write_frame(audiometer->base.downstream, frame);
  65. if (status == APR_SUCCESS && frame->size > 0) {
  66. int i;
  67. int frames = frame->size / 2;
  68. const short *sptr = (const short *)frame->buffer;
  69. float peak = 0.0;
  70. float rms = 0.0;
  71. int old;
  72. for (i = 0; i < frames; ++i) {
  73. float v = *sptr * const_1_div_32768_;
  74. peak = (float)max(v, peak);
  75. rms += (float)(v * v);
  76. sptr++;
  77. }
  78. rms = sqrt(rms / frames);
  79. rms = ToDB(rms, DB_RANGE);
  80. peak = ToDB(peak, DB_RANGE);
  81. old = audiometer->stat[WRITE_IDX].rms;
  82. audiometer->stat[WRITE_IDX].rms = (old * 9 + (int)(100*rms)) / 10;
  83. old = audiometer->stat[WRITE_IDX].peak;
  84. audiometer->stat[WRITE_IDX].peak = (old * 9 + (int)(100*peak)) / 10;
  85. }
  86. return APR_SUCCESS;
  87. }
  88. static audiostream_vtbl_t g_stream_vtbl = {
  89. &read_frame,
  90. &write_frame,
  91. };
  92. apr_status_t audiodbmeter_create(apr_pool_t *pool, audioengine_t *engine, audiodbmeter_t **p_audiometer)
  93. {
  94. audiodbmeter_t *audiometer;
  95. audiometer = apr_palloc(pool, sizeof(audiodbmeter_t));
  96. memset(audiometer, 0, sizeof(audiodbmeter_t));
  97. assert(0 == READ_IDX);
  98. assert(1 == WRITE_IDX);
  99. audiostream_init(engine, &g_stream_vtbl, &audiometer->base);
  100. *p_audiometer = audiometer;
  101. return APR_SUCCESS;
  102. }
  103. apr_status_t audiodbmeter_destroy(audiodbmeter_t *audiometer)
  104. {
  105. return APR_SUCCESS;
  106. }
  107. apr_status_t audiodbmeter_get_peak_db(audiodbmeter_t *audiometer, int direction, int *pval)
  108. {
  109. int idx = direction - 1;
  110. *pval = audiometer->stat[idx].peak;
  111. return APR_SUCCESS;
  112. }
  113. apr_status_t audiodbmeter_get_rms_db(audiodbmeter_t *audiometer, int direction, int *pval)
  114. {
  115. int idx = direction - 1;
  116. *pval = audiometer->stat[idx].rms;
  117. return APR_SUCCESS;
  118. }