Add function vol2attn to return an attenuation for a given volume. Needed in alsa as well as in player.

This commit is contained in:
Mike Brady
2014-05-09 17:53:40 +01:00
parent d20f27f436
commit 34c52224df
2 changed files with 52 additions and 0 deletions
+49
View File
@@ -1,6 +1,7 @@
/*
* Utility routines. This file is part of Shairport.
* Copyright (c) James Laird 2013
* The volume to attenuation function vol2attn copyright (c) Mike Brady 2014
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
@@ -173,3 +174,51 @@ uint8_t *rsa_apply(uint8_t *input, int inlen, int *outlen, int mode) {
}
return out;
}
// Given a volume (0 to -30) and high and low attenuations available in the mixer in dB, return an attenuation depending on the volume and the function's transfer function
// See http://tangentsoft.net/audio/atten.html for data on good attenuators.
// We want a smooth attenuation function, like, for example, the ALPS RK27 Potentiometer transfer functions referred to at the link above.
double vol2attn(double vol, long max_db, long min_db) {
// We use a little coordinate geometry to build a transfer function from the volume passed in to the device's dynamic range.
// The x axis is the "volume in" which will be from -30 to 0. The y axis will be the "volume out" which will be from the bottom of the range to the top.
// We build the transfer function from one or more lines. We characterise each line with two numbers:
// the first is where on x the line starts when y=0 (from 0 to -30); the second is where on y the line stops when when x is -30.
// thus, if the line was characterised as {0,-30}, it would be an identity transfer.
// Assuming, for example, a dynamic range of lv=-70 to hv=0
// Typically we'll use three lines -- a three order transfer function
// First: {0,25} giving a gentle slope
// Second: {-17,-25-(lv+25)/2} giving a faster slope from y=0 at x=-17 to y=-50 at x=-30
// Third: {-23,lv} giving a fast slope from y=0 at x=-23 to y=-70 at x=-30
#define order 3
double vol_setting = max_db;
if ((vol<=0.0) && (vol>=-30.0)) {
long range_db = max_db-min_db; // this will be a positive nunmber
// debug(1,"Volume min %ddB, max %ddB, range %ddB.\n",min_db,max_db,range_db);
double first_slope = -2500.0; // this is the slope of the attenuation at the high end -- 25dB for the full rotation.
if (-range_db>first_slope)
first_slope = range_db;
double lines[order][2] = {{0,first_slope},{-17,first_slope-(range_db+first_slope)/2},{-23,-range_db}};
int i;
for (i=0;i<order;i++) {
if (vol<=lines[i][0]) {
double tvol = lines[i][1]*(vol-lines[i][0])/(-30-lines[i][0]);
// debug(1,"On line %d, end point of %f, input vol %f yields output vol %f.\n",i,lines[i][1],vol,tvol);
if (tvol<vol_setting)
vol_setting=tvol;
}
}
vol_setting+=max_db;
} else if (vol!=-144.0) {
debug(1,"Volume request value %f is out of range: should be from 0.0 to -30.0 or -144.0.\n",vol);
} else {
vol_setting = min_db; // for safety, return the lowest setting...
}
// debug(1,"returning an attenuation of %f.\n",vol_setting);
return vol_setting;
}
+3
View File
@@ -47,6 +47,9 @@ char *base64_enc(uint8_t *input, int length);
#define RSA_MODE_KEY (1)
uint8_t *rsa_apply(uint8_t *input, int inlen, int *outlen, int mode);
// given a volume (0 to -30) and high and low attenuations in dB*100 (e.g. 0 to -6000 for 0 to -60 dB), return an attenuation depending on the transfer function
double vol2attn(double vol, long max_db, long min_db);
extern shairport_cfg config;
void shairport_shutdown(int retval);