Outsource the audio energy calculation
This commit is contained in:
parent
22d9059ad5
commit
347f1944b7
@ -2,7 +2,7 @@
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include "FilterThreshold.h"
|
||||
#include "../../logger.h"
|
||||
#include "../processing/AudioVolume.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace tc::audio;
|
||||
@ -17,41 +17,9 @@ bool ThresholdFilter::initialize(std::string &, float val, size_t margin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* technique based on http://www.vttoth.com/CMS/index.php/technical-notes/68 */
|
||||
inline float merge_ab(float a, float b, float n) {
|
||||
/*
|
||||
* Form: A,B := [0;n]
|
||||
* IF A <= n/2 AND B <= N/2
|
||||
* Z = (2 * A * B) / n
|
||||
* ELSE
|
||||
* Z = 2(A + B) - (2/n) * A * B - n
|
||||
*
|
||||
* For a range from 0 to 2: Z = 2(A + B) - AB - 2
|
||||
*/
|
||||
|
||||
auto half_n = n / 2;
|
||||
auto inv_half_n = 1 / half_n;
|
||||
|
||||
if(a < half_n && b < half_n) {
|
||||
return inv_half_n * a * b;
|
||||
}
|
||||
|
||||
return 2 * (a + b) - inv_half_n * a * b - n;
|
||||
}
|
||||
|
||||
bool ThresholdFilter::process(const void *_buffer) {
|
||||
float value = -1;
|
||||
auto analyze_callback = this->on_analyze;
|
||||
|
||||
for(size_t channel = 0; channel < this->_channels; channel++) {
|
||||
auto percentage = this->analyze(_buffer, channel);
|
||||
|
||||
if(channel == 0) {
|
||||
value = (float) percentage;
|
||||
} else {
|
||||
value = merge_ab(value, (float) percentage, 100);
|
||||
}
|
||||
}
|
||||
auto analyze_callback = this->on_analyze;
|
||||
float value = audio::audio_buffer_level((const float*) _buffer, this->_channels, this->_frame_size);
|
||||
|
||||
auto last_level = this->_current_level;
|
||||
float smooth;
|
||||
@ -75,27 +43,4 @@ bool ThresholdFilter::process(const void *_buffer) {
|
||||
}
|
||||
|
||||
return (this->_margin_processed_samples += this->_frame_size) < this->_margin_samples;
|
||||
}
|
||||
|
||||
|
||||
long double ThresholdFilter::analyze(const void *_buffer, size_t channel) {
|
||||
/* equation taken from the web client */
|
||||
auto buffer = (float*) _buffer;
|
||||
|
||||
long double value = 0;
|
||||
auto sample = this->_frame_size;
|
||||
|
||||
while(sample-- > 0) {
|
||||
/* to be like the web client */
|
||||
const auto num = floorl(*buffer * 127) / 127.f;
|
||||
value += num * num;
|
||||
buffer += this->_channels;
|
||||
}
|
||||
|
||||
long double rms = sqrtl(value / (long double) this->_frame_size);
|
||||
auto db = (long double) 20 * (log(rms) / log(10));
|
||||
db = max((long double) -192, min(db, (long double) 0));
|
||||
|
||||
auto percentage = (float) (100 + (db * 1.92f));
|
||||
return max(0.f, min(percentage, 100.f));
|
||||
}
|
@ -14,20 +14,18 @@ namespace tc::audio::filter {
|
||||
bool initialize(std::string& /* error */, float /* threshold */, size_t /* margin frames */);
|
||||
bool process(const void* /* buffer */) override;
|
||||
|
||||
long double analyze(const void* /* buffer */, size_t /* channel */);
|
||||
|
||||
inline void set_threshold(float value) { this->_threshold = value; }
|
||||
[[nodiscard]] inline float threshold() const { return this->_threshold; }
|
||||
|
||||
/* in seconds */
|
||||
inline float margin_release_time() { return (float) this->_margin_samples / (float) this->_sample_rate; }
|
||||
[[nodiscard]] inline float margin_release_time() { return (float) this->_margin_samples / (float) this->_sample_rate; }
|
||||
inline void set_margin_release_time(float value) { this->_margin_samples = (size_t) ceil((float) this->_sample_rate * value); }
|
||||
|
||||
inline void attack_smooth(float value) { this->_attack_smooth = value; }
|
||||
[[nodiscard]] inline float attack_smooth() const { return this->_attack_smooth; }
|
||||
inline void attack_smooth(float value) { this->_attack_smooth = value; }
|
||||
|
||||
inline void release_smooth(float value) { this->_release_smooth = value; }
|
||||
[[nodiscard]] inline float release_smooth() const { return this->_release_smooth; }
|
||||
inline void release_smooth(float value) { this->_release_smooth = value; }
|
||||
|
||||
std::function<void(float)> on_analyze;
|
||||
private:
|
||||
|
71
native/serverconnection/src/audio/processing/AudioVolume.cpp
Normal file
71
native/serverconnection/src/audio/processing/AudioVolume.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
//
|
||||
// Created by WolverinDEV on 28/03/2021.
|
||||
//
|
||||
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
#include "AudioVolume.h"
|
||||
|
||||
using namespace tc;
|
||||
|
||||
/* technique based on http://www.vttoth.com/CMS/index.php/technical-notes/68 */
|
||||
inline float merge_ab(float a, float b, float n) {
|
||||
/*
|
||||
* Form: A,B := [0;n]
|
||||
* IF A <= n/2 AND B <= N/2
|
||||
* Z = (2 * A * B) / n
|
||||
* ELSE
|
||||
* Z = 2(A + B) - (2/n) * A * B - n
|
||||
*
|
||||
* For a range from 0 to 2: Z = 2(A + B) - AB - 2
|
||||
*/
|
||||
|
||||
auto half_n = n / 2;
|
||||
auto inv_half_n = 1 / half_n;
|
||||
|
||||
if(a < half_n && b < half_n) {
|
||||
return inv_half_n * a * b;
|
||||
}
|
||||
|
||||
return 2 * (a + b) - inv_half_n * a * b - n;
|
||||
}
|
||||
|
||||
constexpr static auto kMaxChannelCount{32};
|
||||
float audio::audio_buffer_level(const float *buffer, size_t channel_count, size_t sample_count) {
|
||||
/*
|
||||
* TODO: May more like this:
|
||||
* https://source.chromium.org/chromium/chromium/src/+/master:third_party/webrtc/modules/audio_processing/rms_level.cc;l=30;drc=c6366b7101f99520b9203a884665e3d069523a6b;bpv=1;bpt=1
|
||||
*/
|
||||
|
||||
if(channel_count > kMaxChannelCount) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long double square_buffer[kMaxChannelCount];
|
||||
|
||||
auto buffer_ptr = buffer;
|
||||
for(size_t sample{0}; sample < sample_count; sample++) {
|
||||
for(size_t channel{0}; channel < channel_count; channel++) {
|
||||
auto value = *buffer_ptr++;
|
||||
square_buffer[channel] += value * value;
|
||||
}
|
||||
}
|
||||
|
||||
float result{0};
|
||||
for(size_t channel{0}; channel < channel_count; channel++) {
|
||||
long double rms = sqrtl(square_buffer[channel] / (long double) sample_count);
|
||||
auto db = (long double) 20 * (log(rms) / log(10));
|
||||
db = std::max((long double) -192, std::min(db, (long double) 0));
|
||||
|
||||
auto percentage = (float) (100 + (db * 1.92f));
|
||||
|
||||
auto channel_value = std::clamp(percentage, 0.f, 100.f);
|
||||
if(channel == 0) {
|
||||
result = channel_value;
|
||||
} else {
|
||||
result = merge_ab(result, channel_value, 100);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
11
native/serverconnection/src/audio/processing/AudioVolume.h
Normal file
11
native/serverconnection/src/audio/processing/AudioVolume.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
namespace tc::audio {
|
||||
/**
|
||||
* @param buffer
|
||||
* @param channel_count
|
||||
* @param sample_count
|
||||
* @return The audio energy in [0;100]
|
||||
*/
|
||||
float audio_buffer_level(const float *buffer /* buffer */, size_t /* channel count */, size_t /* sample count */);
|
||||
}
|
Loading…
Reference in New Issue
Block a user