Skip to content
Snippets Groups Projects
Commit c5b0e0b2 authored by moon2's avatar moon2 :speech_balloon:
Browse files

blm: preamp

parent 1f827a46
Branches mixer2
No related tags found
1 merge request!682Draft: system mixer: nicer
Pipeline #12864 passed
......@@ -5,6 +5,7 @@ idf_component_register(
bl00mbox.c
bl00mbox_audio.c
bl00mbox_user.c
bl00mbox_preamp.c
bl00mbox_plugin_registry.c
bl00mbox_radspa_requirements.c
radspa/standard_plugin_lib/osc.c
......
......@@ -128,16 +128,11 @@ void bl00mbox_channel_set_name(uint8_t channel_index, char * new_name){
void bl00mbox_channels_init(){
for(uint8_t i = 0; i < BL00MBOX_CHANNELS; i++){
bl00mbox_channel_t * chan = bl00mbox_get_channel(i);
chan->volume = BL00MBOX_DEFAULT_CHANNEL_VOLUME;
chan->sys_gain = 4096;
chan->root_list = NULL;
chan->buds = NULL;
chan->connections = NULL;
memset(chan, 0, sizeof(*chan));
chan->gain = BL00MBOX_DEFAULT_CHANNEL_VOLUME;
chan->is_active = true;
chan->is_free = true;
chan->always_render = NULL;
chan->name = NULL;
chan->dc = 0;
bl00mbox_preamp_init(&chan->preamp, &chan->gain);
}
is_initialized = true;
}
......@@ -157,44 +152,43 @@ void bl00mbox_channel_disable(uint8_t chan){
void bl00mbox_channel_set_compute_mean_square(uint8_t chan, bool compute){
if(chan >= (BL00MBOX_CHANNELS)) return;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
ch->compute_mean_square = compute;
if(!compute) ch->mean_square = 0;
ch->preamp.compute_mean_square = compute;
}
bool bl00mbox_channel_get_compute_mean_square(uint8_t chan){
if(chan >= (BL00MBOX_CHANNELS)) return 0;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
return ch->compute_mean_square;
return ch->preamp.compute_mean_square;
}
uint32_t bl00mbox_channel_get_mean_square(uint8_t chan){
if(chan >= (BL00MBOX_CHANNELS)) return 0;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
return ch->mean_square;
return ch->preamp.mean_square;
}
void bl00mbox_channel_set_sys_gain(uint8_t chan, int16_t volume){
void bl00mbox_channel_set_sys_gain(uint8_t chan, int32_t gain){
if(chan >= (BL00MBOX_CHANNELS)) return;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
ch->sys_gain = volume;
ch->preamp.gain = gain;
}
int16_t bl00mbox_channel_get_sys_gain(uint8_t chan){
int32_t bl00mbox_channel_get_sys_gain(uint8_t chan){
if(chan >= (BL00MBOX_CHANNELS)) return 0;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
return ch->sys_gain;
return ch->preamp.gain;
}
void bl00mbox_channel_set_volume(uint8_t chan, uint16_t volume){
void bl00mbox_channel_set_volume(uint8_t chan, int32_t gain){
if(chan >= (BL00MBOX_CHANNELS)) return;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
ch->volume = volume < 32767 ? volume : 32767;
ch->gain = gain;
}
int16_t bl00mbox_channel_get_volume(uint8_t chan){
int32_t bl00mbox_channel_get_volume(uint8_t chan){
if(chan >= (BL00MBOX_CHANNELS)) return 0;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
return ch->volume;
return ch->gain;
}
void bl00mbox_audio_bud_render(bl00mbox_bud_t * bud){
......@@ -208,16 +202,16 @@ void bl00mbox_audio_bud_render(bl00mbox_bud_t * bud){
bud->is_being_rendered = false;
}
static bool bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * out, bool adding){
static bool bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int32_t * out, bool adding){
if(render_pass_id == chan->render_pass_id) return false;
chan->render_pass_id = render_pass_id;
bl00mbox_channel_root_t * root = chan->root_list;
int32_t vol = radspa_mult_shift(chan->volume, chan->sys_gain);
bool will_render = bl00mbox_preamp_will_render(&chan->preamp);
// early exit when no sources or muted:
if((root == NULL) || (!chan->is_active) || (!vol)){
if((root == NULL) || (!chan->is_active) || (!will_render)){
return false;
}
......@@ -258,37 +252,7 @@ static bool bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * o
}
root = root->next;
}
for(uint16_t i = 0; i < full_buffer_len; i++){
// flip around for rounding towards zero/mulsh boost
bool invert = chan->dc < 0;
if(invert) chan->dc = -chan->dc;
chan->dc = ((uint64_t) chan->dc * (((1<<12) - 1)<<20)) >> 32;
if(invert) chan->dc = -chan->dc;
chan->dc += acc[i];
acc[i] -= (chan->dc >> 12);
}
if(adding){
for(uint16_t i = 0; i < full_buffer_len; i++){
out[i] = radspa_add_sat(radspa_gain(acc[i], vol), out[i]);
}
} else {
for(uint16_t i = 0; i < full_buffer_len; i++){
out[i] = radspa_gain(acc[i], vol);
}
}
if(chan->compute_mean_square){
for(uint16_t i = 0; i < full_buffer_len; i++){
int32_t sq = acc[i];
sq = (sq * sq) - chan->mean_square;
// always round down with negative sq so that decay always works.
// bitshift instead of div does that for us nicely.
// cannot underflow as ((-a) >> 11) can never be less than -a.
chan->mean_square += sq >> 11;
}
}
bl00mbox_preamp_render(&chan->preamp, acc, out, full_buffer_len, adding);
return true;
}
......@@ -303,7 +267,7 @@ bool _bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len){
render_pass_id++; // fresh pass, all relevant sources must be recomputed
full_buffer_len = len/2;
bl00mbox_line_in_interlaced = rx;
int16_t acc[full_buffer_len];
int32_t acc[full_buffer_len];
bool acc_init = false;
// system channel always runs non-adding
acc_init = bl00mbox_audio_channel_render(&(channels[0]), acc, acc_init) || acc_init;
......@@ -323,8 +287,9 @@ bool _bl00mbox_audio_render(int16_t * rx, int16_t * tx, uint16_t len){
if(!acc_init) return false;
for(uint16_t i = 0; i < full_buffer_len; i++){
tx[2*i] = acc[i];
tx[2*i+1] = acc[i];
int16_t clipped = (acc[i] > 32767) ? 32767 : ((acc[i] < -32768) ? -32768 : acc[i]);
tx[2*i] = clipped;
tx[2*i+1] = clipped;
}
return true;
}
......
#include "bl00mbox_preamp.h"
void bl00mbox_preamp_init(bl00mbox_preamp_t * preamp, int32_t * ext_gain){
memset(preamp, 0, sizeof(* preamp));
preamp->gain = 32768;
preamp->ext_gain = ext_gain;
}
bool bl00mbox_preamp_will_render(bl00mbox_preamp_t * preamp){
return(!preamp->mute && preamp->gain && (!preamp->ext_gain || (*preamp->ext_gain)));
}
static inline int32_t apply_gain(int32_t input, int32_t gain){
// unity gain at 1<<22, max gain <60dB
return (((int64_t) (input << 10)) * gain) >> 32;
}
bool bl00mbox_preamp_render(bl00mbox_preamp_t * preamp, int32_t * input, int32_t * output,
uint16_t len, bool adding){
if(!bl00mbox_preamp_will_render(preamp)) return false;
int32_t gain = preamp->gain;
if(preamp->ext_gain){
gain *=* preamp->ext_gain;
gain >>= 8;
} else {
gain <<= 7;
}
if(preamp->remove_dc){
for(uint16_t i = 0; i < len; i++){
// flip around for rounding towards zero/mulsh boost
bool invert = preamp->dc < 0;
if(invert) preamp->dc = -preamp->dc;
preamp->dc = ((uint64_t) preamp->dc * (((1<<12) - 1)<<20)) >> 32;
if(invert) preamp->dc = -preamp->dc;
preamp->dc += input[i];
input[i] -= (preamp->dc >> 12);
}
}
if(preamp->compute_mean_square){
for(uint16_t i = 0; i < len; i++){
int32_t sq = input[i];
sq = (sq * sq) - preamp->mean_square;
// always round down with negative sq so that decay always works.
// bitshift instead of div does that for us nicely.
// cannot underflow as ((-a) >> 11) can never be less than -a.
preamp->mean_square += sq >> 11;
}
} else {
preamp->mean_square = 0;
}
if(gain != 1L<<22){
if(adding){
for(uint16_t i = 0; i < len; i++){
output[i] += apply_gain(input[i], gain);
}
} else {
for(uint16_t i = 0; i < len; i++){
output[i] = apply_gain(input[i], gain);
}
}
} else {
if(adding){
for(uint16_t i = 0; i < len; i++){
output[i] += input[i];
}
} else {
memcpy(output, input, len*sizeof(int32_t));
}
}
return true;
}
......@@ -14,6 +14,7 @@
#include <string.h>
#include "radspa.h"
#include "radspa_helpers.h"
#include "bl00mbox_preamp.h"
struct _bl00mbox_bud_t;
struct _bl00mbox_connection_source_t;
......@@ -64,12 +65,10 @@ typedef struct _bl00mbox_channel_root_t{
typedef struct{
bool is_active; // rendering can be skipped if false
bool is_free;
bool compute_mean_square;
uint32_t mean_square;
char * name;
int32_t volume;
int32_t sys_gain;
int32_t dc;
int32_t gain;
bl00mbox_preamp_t preamp;
struct _bl00mbox_channel_root_t * root_list; // list of all roots associated with channels
uint32_t render_pass_id; // may be used by host to determine whether recomputation is necessary
struct _bl00mbox_bud_t * buds; // linked list with all channel buds
......@@ -82,10 +81,10 @@ void bl00mbox_channel_enable(uint8_t chan);
void bl00mbox_channel_enable(uint8_t chan);
void bl00mbox_channel_disable(uint8_t chan);
void bl00mbox_channel_set_volume(uint8_t chan, uint16_t volume);
int16_t bl00mbox_channel_get_volume(uint8_t chan);
void bl00mbox_channel_set_sys_gain(uint8_t chan, int16_t volume);
int16_t bl00mbox_channel_get_sys_gain(uint8_t chan);
void bl00mbox_channel_set_volume(uint8_t chan, int32_t volume);
int32_t bl00mbox_channel_get_volume(uint8_t chan);
void bl00mbox_channel_set_sys_gain(uint8_t chan, int32_t volume);
int32_t bl00mbox_channel_get_sys_gain(uint8_t chan);
void bl00mbox_channel_set_compute_mean_square(uint8_t chan, bool compute);
bool bl00mbox_channel_get_compute_mean_square(uint8_t chan);
uint32_t bl00mbox_channel_get_mean_square(uint8_t chan);
......
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
typedef struct {
bool mute;
// unity gain at 1<<15
int32_t gain;
// if NULL this is ignored and only gain is applied, else unity at 1<<15
int32_t * ext_gain;
// whether or not to remove dc from the signal and its data storage
bool remove_dc;
int32_t dc;
// whether or not to compute rms of the signal and its data storage
bool compute_mean_square;
uint32_t mean_square;
} bl00mbox_preamp_t;
void bl00mbox_preamp_init(bl00mbox_preamp_t * preamp, int32_t * ext_gain);
bool bl00mbox_preamp_will_render(bl00mbox_preamp_t * preamp);
bool bl00mbox_preamp_render(bl00mbox_preamp_t * preamp, int32_t * input, int32_t * output,
uint16_t len, bool adding);
......@@ -707,7 +707,6 @@ class Channel:
value = 0
else:
value = int(32768 * (10 ** (value / 20)))
value = min(32767, max(0, value))
sys_bl00mbox.channel_set_volume(self.channel_num, value)
@property
......@@ -780,7 +779,7 @@ class SysChannel(Channel):
return -math.inf
else:
try:
return 20 * math.log(abs(ret) / 4096, 10)
return 20 * math.log(abs(ret) / 32768, 10)
except:
return -math.inf
......@@ -789,8 +788,7 @@ class SysChannel(Channel):
if value == -math.inf:
value = 0
else:
value = int(4096 * (10 ** (value / 20)))
value = min(32767, max(0, value))
value = int(32768 * (10 ** (value / 20)))
sys_bl00mbox.channel_set_sys_gain(self.channel_num, value)
@property
......@@ -800,8 +798,8 @@ class SysChannel(Channel):
if ret == 0:
return -math.inf
else:
mult = abs(sys_bl00mbox.channel_get_volume(self.channel_num)) / 32768
mult *= abs(sys_bl00mbox.channel_get_sys_gain(self.channel_num)) / 4096
mult = sys_bl00mbox.channel_get_volume(self.channel_num) / 32768
mult *= sys_bl00mbox.channel_get_sys_gain(self.channel_num) / 32768
if mult == 0:
return -math.inf
ret *= mult * mult
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment