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

bl00mbox update:

- system volume per channel
- rms tracking per channel
parent ee750c33
Branches
Tags
1 merge request!677system menu: audio mixer
......@@ -129,6 +129,7 @@ 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;
......@@ -153,6 +154,37 @@ void bl00mbox_channel_disable(uint8_t chan){
ch->is_active = false;
}
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;
}
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;
}
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;
}
void bl00mbox_channel_set_sys_gain(uint8_t chan, int16_t volume){
if(chan >= (BL00MBOX_CHANNELS)) return;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
ch->sys_gain = volume;
}
int16_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;
}
void bl00mbox_channel_set_volume(uint8_t chan, uint16_t volume){
if(chan >= (BL00MBOX_CHANNELS)) return;
bl00mbox_channel_t * ch = bl00mbox_get_channel(chan);
......@@ -180,19 +212,22 @@ static bool bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * o
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);
// early exit when no sources or muted:
if((root == NULL) || (!chan->is_active) || (!vol)){
return false;
}
// turns out always is conditional too :D
bl00mbox_bud_list_t * always = chan->always_render;
while(always != NULL){
bl00mbox_audio_bud_render(always->bud);
always = always->next;
}
bl00mbox_channel_root_t * root = chan->root_list;
// early exit when no sources:
if((root == NULL) || (!chan->is_active)){
return false;
}
int32_t acc[full_buffer_len];
bool acc_init = false;
......@@ -235,14 +270,22 @@ static bool bl00mbox_audio_channel_render(bl00mbox_channel_t * chan, int16_t * o
acc[i] -= (chan->dc >> 12);
}
if(adding){
for(uint16_t i = 0; i < full_buffer_len; i++){
out[i] = radspa_add_sat(radspa_mult_shift(acc[i], chan->volume), out[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_mult_shift(acc[i], chan->volume);
out[i] = radspa_gain(acc[i], vol);
}
}
if(chan->compute_mean_square){
uint32_t decay = 1000000UL;
for(uint16_t i = 0; i < full_buffer_len; i++){
int32_t sq = acc[i];
sq *= sq;
chan->mean_square = (((uint64_t) chan->mean_square) * (UINT32_MAX-decay-1)) >> 32;
chan->mean_square += (((uint64_t) sq)*decay) >> 32;
}
}
return true;
......
......@@ -64,8 +64,11 @@ 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;
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
......@@ -81,6 +84,11 @@ 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_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);
void bl00mbox_channel_event(uint8_t chan);
uint8_t bl00mbox_channel_get_free_index();
void bl00mbox_channels_init();
......
......@@ -555,6 +555,15 @@ class SignalList:
raise AttributeError("signal does not exist")
_channel_init_callback = None
_rms_base = 3 - 10 * math.log(32767 * 32767, 10)
def set_channel_init_callback(callback):
global _channel_init_callback
_channel_init_callback = callback
class Channel:
def __init__(self, name=None):
if name == None:
......@@ -564,12 +573,16 @@ class Channel:
self._channel_num = sys_bl00mbox.channel_get_free_index()
self.name = name
elif type(name) == int:
if (int(name) < sys_bl00mbox.NUM_CHANNELS) and (int(name >= 0)):
self._channel_num = int(name)
num = int(name)
if num < sys_bl00mbox.NUM_CHANNELS and num >= 0:
self._channel_num = num
else:
self._channel_num = sys_bl00mbox.NUM_CHANNELS - 1 # garbage channel
else:
self._channel_num = sys_bl00mbox.NUM_CHANNELS - 1 # garbage channel
global _channel_init_callback
if _channel_init_callback is not None:
_channel_init_callback(self)
def __repr__(self):
ret = "[channel " + str(self.channel_num)
......@@ -580,8 +593,8 @@ class Channel:
ret += " (foreground)"
if self.background_mute_override:
ret += " (background mute override)"
ret += "\n volume: " + str(self.volume)
b = sys_bl00mbox.channel_buds_num(self.channel_num)
ret += "\n gain: " + str(self.gain_dB) + "dB"
b = self.num_plugins
ret += "\n plugins: " + str(b)
if len(self.plugins) != b:
ret += " (desync" + str(len(self.plugins)) + ")"
......@@ -591,6 +604,10 @@ class Channel:
def clear(self):
sys_bl00mbox.channel_clear(self.channel_num)
@property
def num_plugins(self):
return sys_bl00mbox.channel_buds_num(self.channel_num)
@property
def name(self):
if self._channel_num == 0:
......@@ -673,8 +690,49 @@ class Channel:
@volume.setter
def volume(self, value):
value = min(32767, max(-32767, value))
sys_bl00mbox.channel_set_volume(self.channel_num, value)
@property
def gain_dB(self):
ret = sys_bl00mbox.channel_get_volume(self.channel_num)
if ret == 0:
return -math.inf
else:
return 20 * math.log(abs(ret) / 32768, 10)
@gain_dB.setter
def gain_dB(self, value):
if value == -math.inf:
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
def compute_rms(self):
return sys_bl00mbox.channel_get_compute_mean_square(self.channel_num)
@compute_rms.setter
def compute_rms(self, value):
sys_bl00mbox.channel_set_compute_mean_square(self.channel_num, value)
@property
def rms_dB(self):
if self.compute_rms:
ret = sys_bl00mbox.channel_get_mean_square(self.channel_num)
if ret == 0:
return -math.inf
else:
mult = abs(sys_bl00mbox.channel_get_volume(self.channel_num)) / 32768
if mult == 0:
return -math.inf
ret *= mult * mult
return 10 * math.log(ret, 10) + _rms_base
else:
return None
@property
def mixer(self):
return ChannelMixer(self)
......@@ -706,3 +764,47 @@ class Channel:
sys_bl00mbox.channel_set_foreground(self.channel_num)
elif sys_bl00mbox.channel_get_foreground() == self.channel_num:
sys_bl00mbox.channel_set_foreground(0)
class SysChannel(Channel):
def __init__(self, index=0):
if index < sys_bl00mbox.NUM_CHANNELS and index >= 0:
self._channel_num = index
else:
raise Bl00mboxError(f"channel index {index} not found")
@property
def sys_gain_dB(self):
ret = sys_bl00mbox.channel_get_sys_gain(self.channel_num)
if ret == 0:
return -math.inf
else:
try:
return 20 * math.log(abs(ret) / 4096, 10)
except:
return -math.inf
@sys_gain_dB.setter
def sys_gain_dB(self, value):
if value == -math.inf:
value = 0
else:
value = int(4096 * (10 ** (value / 20)))
value = min(32767, max(0, value))
sys_bl00mbox.channel_set_sys_gain(self.channel_num, value)
@property
def sys_rms_dB(self):
if self.compute_rms:
ret = sys_bl00mbox.channel_get_mean_square(self.channel_num)
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
if mult == 0:
return -math.inf
ret *= mult * mult
return 10 * math.log(ret, 10) + _rms_base
else:
return None
......@@ -132,6 +132,42 @@ STATIC mp_obj_t mp_channel_get_volume(mp_obj_t chan) {
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_get_volume_obj,
mp_channel_get_volume);
STATIC mp_obj_t mp_channel_set_sys_gain(mp_obj_t chan, mp_obj_t vol) {
bl00mbox_channel_set_sys_gain(mp_obj_get_int(chan), mp_obj_get_int(vol));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_channel_set_sys_gain_obj,
mp_channel_set_sys_gain);
STATIC mp_obj_t mp_channel_get_sys_gain(mp_obj_t chan) {
return mp_obj_new_int(bl00mbox_channel_get_sys_gain(mp_obj_get_int(chan)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_get_sys_gain_obj,
mp_channel_get_sys_gain);
STATIC mp_obj_t mp_channel_set_compute_mean_square(mp_obj_t chan,
mp_obj_t vol) {
bl00mbox_channel_set_compute_mean_square(mp_obj_get_int(chan),
mp_obj_get_int(vol));
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(mp_channel_set_compute_mean_square_obj,
mp_channel_set_compute_mean_square);
STATIC mp_obj_t mp_channel_get_compute_mean_square(mp_obj_t chan) {
return mp_obj_new_bool(
bl00mbox_channel_get_compute_mean_square(mp_obj_get_int(chan)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_get_compute_mean_square_obj,
mp_channel_get_compute_mean_square);
STATIC mp_obj_t mp_channel_get_mean_square(mp_obj_t chan) {
return mp_obj_new_int(
bl00mbox_channel_get_mean_square(mp_obj_get_int(chan)));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_channel_get_mean_square_obj,
mp_channel_get_mean_square);
STATIC mp_obj_t mp_channel_set_name(mp_obj_t chan, mp_obj_t name) {
char *tmp = strdup(mp_obj_str_get_str(name));
bl00mbox_channel_set_name(mp_obj_get_int(chan), tmp);
......@@ -534,6 +570,16 @@ STATIC const mp_map_elem_t bl00mbox_globals_table[] = {
MP_ROM_PTR(&mp_channel_set_volume_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_get_volume),
MP_ROM_PTR(&mp_channel_get_volume_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_set_sys_gain),
MP_ROM_PTR(&mp_channel_set_sys_gain_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_get_sys_gain),
MP_ROM_PTR(&mp_channel_get_sys_gain_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_set_compute_mean_square),
MP_ROM_PTR(&mp_channel_set_compute_mean_square_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_get_compute_mean_square),
MP_ROM_PTR(&mp_channel_get_compute_mean_square_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_get_mean_square),
MP_ROM_PTR(&mp_channel_get_mean_square_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_set_name),
MP_ROM_PTR(&mp_channel_set_name_obj) },
{ MP_ROM_QSTR(MP_QSTR_channel_get_name),
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment