audiodbmeter.c 3.3 KB

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