VIANC/pw_plugin/micpath.cc

102 lines
2.7 KiB
C++

#include "micpath.h"
#include <cstdio>
aec_stream::aec_stream(pw_loop* lp,ringbuffer* hp,ringbuffer* mic,
logger_record& ps, aec_params p):
pwstream(48000, 1, 1, lp, "aec-output",
pw_properties_new(PW_KEY_MEDIA_TYPE, "Audio",
PW_KEY_MEDIA_CATEGORY, "Source",
PW_KEY_MEDIA_ROLE, "DSP", NULL)),
hp_rb(hp), mic_rb(mic), pstrm(ps), params(p) {}
void aec_stream::on_process() {
pw_buffer* pwb;
if((pwb = pw_stream_dequeue_buffer(this->strm)) == nullptr) {
return;
}
auto* b = pwb->buffer;
float* dst = (float*)b->datas[0].data;
if(dst == nullptr) return;
auto n_frames = b->datas[0].maxsize / sizeof(float);
if(pwb->requested) {
n_frames = SPA_MIN(pwb->requested, n_frames);
}
size_t effective = 0;
switch(status) {
case INIT:
hp_mic_delta = hp_rb->dequeue_time - mic_rb->enqueue_time;
status = SKIP_EARLY;
remaining_samples = 48000*10;
[[fallthrough]];
case SKIP_EARLY:
effective = mic_rb->dequeue(dst, n_frames, true, false);
if(remaining_samples >= 48000 * 2 && remaining_samples - effective < 48000*2) {
std::puts("Please keep silent for the next few seconds");
}
if((remaining_samples-=effective) <= 0) {
status = SCAN_SILENT;
prm_mutex.lock();
remaining_samples = 48000;
}
break;
case SCAN_SILENT:
effective = mic_rb->dequeue(dst, n_frames, true, false);
for(size_t i = 0; i < effective; ++i) {
params.noise_power += dst[i] * dst[i];
}
if((remaining_samples-=effective) <= 0) {
status = SCAN_LOUD;
params.noise_power /= 48000 - remaining_samples;
remaining_samples = 48000;
pstrm.request_noise(true, .1);
}
break;
case SCAN_LOUD: {
effective = mic_rb->dequeue(dst, n_frames, true, false);
for(size_t i = 1; i <= effective; ++i) {
for(size_t j = 0; j < 8192; ++j) {
auto t = hp_rb->w_head_pos - 2*i - 2*j;
while(t < 0) {t += ringbuffer::bsize;}
if(t >= ringbuffer::bsize) {t -= ringbuffer::bsize;}
cov[j] += dst[effective - i] * hp_rb->buffer[t + 1];
}
}
if((remaining_samples-=effective) <= 0) {
pstrm.request_noise(false, 0.f);
status = INACTIVE;
params.echo_return_gain /= 48000 - remaining_samples;
params.echo_return_gain -= params.noise_power;
params.echo_return_gain *= 1/(.1*.1);
// Renormalize
params.valid = true;
prm_mutex.unlock();
} break; }
case INACTIVE:
effective = mic_rb->dequeue(dst, n_frames, true, false);
break;
}
b->datas[0].chunk->offset = 0;
b->datas[0].chunk->stride = sizeof(float);
b->datas[0].chunk->size = effective*sizeof(float);
pw_stream_queue_buffer(this->strm, pwb);
}
aec_params aec_stream::get_aec_params() {
prm_mutex.lock();
auto copy = params;
prm_mutex.unlock();
return copy;
}