From 34c52224dfe6832a33183f4345e35305015df7b3 Mon Sep 17 00:00:00 2001 From: Mike Brady Date: Fri, 9 May 2014 17:53:40 +0100 Subject: [PATCH] Add function vol2attn to return an attenuation for a given volume. Needed in alsa as well as in player. --- common.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ common.h | 3 +++ 2 files changed, 52 insertions(+) diff --git a/common.c b/common.c index f87e102d..66dc829c 100644 --- a/common.c +++ b/common.c @@ -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