Add support for external volume scripts with -w#258
Conversation
1c93147 to
be96915
Compare
|
It's great, thank you very much! |
This is useful, if the client should have a fixed volume and an external amplifier should be controlled.
|
@allmazz thanks for the suggestion. I added it. |
|
I have troubles with volume level < 25%, could you please take a look? Volume level is 25% or higher, works as expected: Then I set 24%, but in logs we can see 22%: 17%: 16% or lower: I use latest LMS as the server |
|
Thanks for this feature — controlling external amplifiers via LMS volume is a genuine gap. A few issues worth addressing before merge: Bug: volume mapping collapses below ~16% LMSThe The existing ALSA mixer path already has the correct constant: ldB = 20.0f * log10f((float)left / FIXED_ONE);
vol = (int)lroundf((ldB > -72.0f ? 72.0f + ldB : 0.0f) / 72.0f * 100.0f);This mirrors exactly what Code duplicationThe identical ~40-line block is copy-pasted into // output.c
void call_volume_script(unsigned left) {
char cmd[256];
float ldB;
int vol;
ldB = 20.0f * log10f((float)left / FIXED_ONE);
vol = (int)lroundf((ldB > -72.0f ? 72.0f + ldB : 0.0f) / 72.0f * 100.0f);
LOG_DEBUG("volume script left: %u ldB: %.1f vol: %u", left, ldB, vol);
#if defined(_WIN32) || defined(_WIN64)
snprintf(cmd, sizeof(cmd), "start /B %s %u", volume_script, vol);
#else
snprintf(cmd, sizeof(cmd), "%s %u &", volume_script, vol);
#endif
if (system(cmd) != 0) {
LOG_ERROR("external volume script failed: %s", cmd);
}
LOCK;
output.gainL = FIXED_ONE;
output.gainR = FIXED_ONE;
UNLOCK;
}Each if (volume_script) {
call_volume_script(left);
return;
}Async inconsistency
Happy to open a PR on top of this one if that's easier than reworking it yourself. |
|
@patapovich feel free to open a PR in my repo, so I merge it or copy my code and open a new PR, then I will close this. |
|
I would prefer to have separate PRs for the linear volume bug fix and the -w option. Collapsing the shared helper from the separate output_* files would be prefered to be including with the linear volume bug fix. Thanks. |
Adds a -w <script> option that invokes an executable script whenever LMS sends a volume command (AUDG packet). The script receives a single integer argument 0-100 mapped from the LMS dB range (-72..0 dB) using the same linear scale that the ALSA mixer path already uses. When -w is active the internal software gain is held at unity (FIXED_ONE) so the script has full control over output level. The shared helper call_volume_script() is placed in output.c (always compiled) to avoid duplicating the mapping arithmetic across the ALSA, PortAudio and PulseAudio backends. On POSIX the script is launched asynchronously via a shell "&" so the audio thread is not blocked; on Windows "start /B" is used instead. -w is mutually exclusive with -V (ALSA hardware volume control).
|
Love to see something like this be implemented. My setup use an amplifier that adjust volume by changing gain in the actual output stage. Is it possible to implement this with replay gain? I.e. does the server calculate gain based on replay gain metadata. Or is replay gain always done in SW on server? Edit: Ohh I see, Squeezelite have replay_gain information. Will this be included in the script volume value? Edit II: Lines 34 to 62 in 39fe3c8 s32_t gainL = output.current_replay_gain ? gain(output.gainL, output.current_replay_gain) : output.gainL; s32_t gainR = output.current_replay_gain ? gain(output.gainR, output.current_replay_gain) : output.gainR; Not sure if its enough to add similar code to the gain setting going to the script? Or if we also need a additional trigger when new track start? |
This is useful, if the client should have a fixed volume and an external amplifier should be controlled. This helps to prevent clipping and big volume differences when changing channel on the external amplifier.
Here a few cases:
Fixes #257