-
Notifications
You must be signed in to change notification settings - Fork 656
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add --progressive-volume option. Increase volume slowly at low level,… #10
Add --progressive-volume option. Increase volume slowly at low level,… #10
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @ComlOnline @plietar 😇
I hope you don't mind me stepping up here. I've been following this project for a while and using it daily. I just thought you could use some help on the reviews.
@thekr1s
You have some formatting issues, try using rustfmt so that your code style matches the project's code style.
Also I don't really understand the idea here and its usefulness, maybe try to explain it with some examples and why you think this is better than the current implementation.
I like the idea of revising the volume control and adding some features so it fits better with the system volume, I just don't quite grasp your ideas here.
src/spirc.rs
Outdated
let mut incr:u32 = 0; | ||
for i in 0..d { | ||
v += incr; | ||
incr +=3; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be a good idea to move these values (3, 42) into properly named constants.
Maybe something like:
const PROGRESSIVE_VOLUME_STEP_LOW: u32 = 3
const PROGRESSIVE_VOLUME_STEP_HIGH: u32 = 42
src/spirc.rs
Outdated
} | ||
} | ||
|
||
// Clip the vulume to the max |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo: vulume should be volume
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @alin23, I'll process this comments. Note I have updated my initial comment on this pull request. Hope it clears up you questions
Hi all,
I was also thinking of this, not being a programmer myself but using it at
a daily basis.
And following the project for quite some time now.
This pull request seems to try to emulate some sort of logarithmic volume
scale.
I think it would be better to replace the linear scale with a logarithmic
(natural) scale.
I remember some discussion on this some time ago, but can't find it right
now.
2018-01-26 9:05 GMT+01:00 Alin Panaitiu <notifications@github.com>:
… ***@***.**** commented on this pull request.
Hi @ComlOnline <https://github.com/comlonline> @plietar
<https://github.com/plietar> 😇
I hope you don't mind me stepping up here. I've been following this
project for a while and using it daily. I just thought you could use some
help on the reviews.
@thekr1s <https://github.com/thekr1s>
You have some formatting issues, try using rustfmt so that your code style
matches the project's code style.
Also I don't really understand the idea here and its usefulness, maybe try
to explain it with some examples and why you think this is better than the
current implementation.
I like the idea of revising the volume control and adding some features so
it fits better with the system volume, I just don't quite grasp your ideas
here.
------------------------------
In src/spirc.rs
<#10 (comment)>
:
> @@ -122,6 +124,33 @@ fn initial_device_state(config: ConnectConfig, volume: u16) -> DeviceState {
})
}
+fn volume_to_mixer(volume: u16, progressive: bool) -> u16 {
+ if progressive {
+ // Some by trail determined volume calculation algorithm. Start increasing slowly,
+ // then after 50% increase in bigger steps.
+ let d = volume / (std::u16::MAX / 100);
+ let mut v:u32 = 0;
+ let mut incr:u32 = 0;
+ for i in 0..d {
+ v += incr;
+ incr +=3;
I think it would be a good idea to move these values (3, 42) into properly
named constants.
Maybe something like:
const PROGRESSIVE_VOLUME_STEP_LOW: u32 = 3const PROGRESSIVE_VOLUME_STEP_HIGH: u32 = 42
------------------------------
In src/spirc.rs
<#10 (comment)>
:
> + if progressive {
+ // Some by trail determined volume calculation algorithm. Start increasing slowly,
+ // then after 50% increase in bigger steps.
+ let d = volume / (std::u16::MAX / 100);
+ let mut v:u32 = 0;
+ let mut incr:u32 = 0;
+ for i in 0..d {
+ v += incr;
+ incr +=3;
+ if i > 50 {
+ // Increase faster to reach max volume
+ incr += 42;
+ }
+ }
+
+ // Clip the vulume to the max
Typo: *vulume* should be *volume*
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#10 (review)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AV69TaudmdFBqJ24mAIh08g83ANf9XWJks5tOYc5gaJpZM4RtmsH>
.
|
@thekr1s I see your point now. I don't decide anything here though. I just think you should find the root cause for the problem and if it is really because of librespot, implement it as a universal fix, not a hardcoded one that works only for RPi with HiFiBerry and OSMC. |
I am not the only one with this problem as can be concluded form this thread: |
I think if this bug still exists in this IOS app (gonna try and get my hands on an iPhone) it does need to be addressed. However I do agree with @cortegedusage if this were to be implemented a proper logarithmic volume control should be used as an option. I also think @alin23 is correct in saying we need to find the root cause I can understand wanting a temporary fix however I don't think it should be on the master branch for now. If an alternate branch is made with these changes called for example "progressive volume" would that work for you in the interim? Out of interest when librespot is at full volume is it too loud? (As in clipping and distorting). I have a pi3 on my desk I'll install OSMC over the weekend and have a play as well. |
@thekr1s ok, that makes sense now. I remember having the same problem some time ago while changing the volume from the iPhone. How about changing the IdeaInstead of a normalized_volume = volume / std::u16::MAX // To get a value between 0 and 1
volume = normalized_volume.powf(volume_scale_factor) * std::u16::MAX Some Examples--volume-scale-factor 2.0 Tips for the future (even if you don't like math)What you have implemented inside
...and you are using more than 50 cycles for something that can be done in a single line. You could have narrowed that whole for loop to something like: volume = if volume <= 50 {
n = volume
3 * ((n * (n + 1)) / 2)
} else {
n = volume - 50
(45 * n + 195) * ((n * (n + 1)) / 2)
} WolframAlpha gives you really nice formulas for things like that: 195 + 240 + 285 + ... + 2400 |
This patch, in whatever final form it takes, is very important to me too. I mainly control with the iOS app and pipe out to snapcast via pulseaudio. We also use a lot of white noise type tracks on spotify for sleeping, and the control on the low end of the volume spectrum is way too choppy. The default scale is awkward. @alin23 's approach seems reasonable too. |
@ComlOnline The maximum volume is OK. It is about the same as the maximum volume of Kodi. @alin23 I prototyped your --volume-scale-factor solution in a spreadsheet. Looks like it could work althoug the volume increases very slowly in the first 40%. I'll test it and see how it behaves. I'll do some experiments and get back to it. |
@thekr1s That does sound like a volume issue then. It sounds like the lack of volume in the first 40% may be an issue with the scale factor. If you have a look at this graph you can play around with the scale factor (slider on the right) and see what looks good. From what I understood @alin23 was meaning to pass this as a variable rather than hard code it in, so it would just be a matter of finding what works best for you. |
@ComlOnline Yes, I meant to pass the scale factor as a variable from the command line. There are all kinds of sound cards out there so letting the users fiddle with the volume scaling should make the problem solvable for everyone. @thekr1s About the optimization, applying a single formula instead of doing 100 additions in a for loop is at least 1 order of magnitude faster. Usually people don't just set volume to a number in one go. They raise the volume fast from a lower volume and that I am all for readability usually but what you are doing there is like writing a multiplication ( Anyway, seems like the scale factor implementation isn't too fast either (probably because of floating point operations), so applying a gauss sum might be the best choice. You can see here a benchmark: Gauss volume control benchmark And the results after running 3 tests
test tests::raise_volume_with_for_loop ... bench: 1,883 ns/iter (+/- 742)
test tests::raise_volume_with_formula ... bench: 186 ns/iter (+/- 38)
test tests::raise_volume_with_scale_factor ... bench: 1,499 ns/iter (+/- 257) For more flexibility, I think we can implement both ideas:
|
I'm not sure if this will be helpful, but it's worth a read anyway:
|
@LeonCB thanks for the quality material! Well that's what I was advocating for with the But now I find that the gaussian method should be available too because some systems have very weird volume configuration. We should also make the exponential curve default with a sensible factor. The 6.908 value found in the article is wild. Most of us don't listen to Spotify at 90dB to need that range. Also as you can see in this benchmark, using running 2 tests
test tests::raise_volume_with_integer_scale_factor ... bench: 304 ns/iter (+/- 62)
test tests::raise_volume_with_scale_factor ... bench: 1,513 ns/iter (+/- 373) So I think we should go with a factor of 4 as default. @thekr1s Let me know if you still want to finish this. If you want, I can take it from here and implement the ideas in a new PR. |
I'm happy to implement it. I'll work on it this week. If none of the above command line options are given, the exponential volume scale will be used with factor 1.0 (= lineair isn't it?)
|
@thekr1s sounds good! Only one thing, we should name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just so you know I moved the options table to a new Wiki you can add the option here when you're ready:
https://github.com/librespot-org/librespot/wiki/Options
I took a look in the XBMC source code. I made a volume calculation based on the code in XBMS and ends-up like below. I tested it, and sounds indeed quite like XBMC volume control. fn volume_to_mixer_xbmc(volume: u16) -> u16 {
} |
@thekr1s nice find! 🥇 As we can see, XBMC implements exactly the algorithm for the ideal curve explained in the article posted by @LeonCB
But if we already know our range (60dB) we can precompute some things and reduce the algorithm implementation to the following: const IDEAL_FACTOR: f64 = 6.908;
fn exponential_volume(volume: u16) -> u16 {
let normalized_volume = volume as f64 / std::u16::MAX as f64; // To get a value between 0 and 1
let new_volume = (normalized_volume * IDEAL_FACTOR).exp() / 1000.0;
(new_volume * std::u16::MAX as f64) as u16
} Which as you can see here, is pretty fast: running 5 tests
test tests::raise_volume_with_for_loop ... bench: 1,837 ns/iter (+/- 296)
test tests::raise_volume_with_formula ... bench: 185 ns/iter (+/- 32)
––> test tests::raise_volume_with_ideal_factor ... bench: 718 ns/iter (+/- 104)
test tests::raise_volume_with_integer_scale_factor ... bench: 298 ns/iter (+/- 105)
test tests::raise_volume_with_scale_factor ... bench: 1,410 ns/iter (+/- 176) If everyone agrees, we can chop down on the complexity of having 2 more obscure command line args, and make this implementation the default for everyone. @ComlOnline @thekr1s what would you vote for?
I vote for 1 |
I like it! I would just get a bunch of people to test it to make sure it sounds OK before we merge it but I see no reason not to do that. Could people vote and +1 for option 1 and -1 for option 2 on @alin23 post. @sashahilton00 @cortegedusage @LeonCB @maxx Could you spare a second and look at the above? Thanks |
Votes from Les Pays-Bas |
I'd vote for 1 given the choice, but given that we've been discussing making an 'easy to use' librespot daemon in a new repo, I wouldn't be against adding another command line argument for the library, as there will undoubtedly be those that prefer one over another for whatever reason. However, exponential is clearly better for most people, hence I'd vote for exponential by default, with a |
My vote is option 1. Exponential should be default. Maybe with an option to change the factor if 6.908 is to steep for some people. |
+1 for 1 |
So, conclusion? I seem to be the only one interested in maintaining backward compatibility for linear volume, and I'm not planning to use that myself, so why don't we just dump it. Are we happy with exponential volume as @alin23 proposes we implement it, with a runtime flag |
I think your correct in that it would be good to maintain it but I don't see a single situation where it could be useful. So just drop it and do as you and @alin23 have suggested with a default of 6.908 and have the run time flag. |
Fair enough. @alin23 are you ok to turn it into a PR? |
OK, I'll implement option 1. |
@thekr1s fair enough, leave it out. we can add it later if we need to. |
implement exponential volume control only
…s/librespot into progressive-voume-control
…s/librespot into progressive-voume-control
…s/librespot into progressive-voume-control
as agreed.. In the end only one file modified, little impact. |
LGTM, If anyone has any thoughts, please weigh in, otherwise I'll merge this tomorrow. |
Looks good to me too ^_^ |
Hey, @sashahilton00, @thekr1s . |
What do you mean? This new functionality is behind a flag... Edit: sorry, got my issue crossed! Your point stands. |
I was afraid of that. I will add an option to get the old volume control back. |
@thekr1s, It is all good. Things sometime happen. I understand that for some people this PR was necessary. :) Thank you in advance. |
Knew there was someone out there using linear volume still ;) Are you ok to create the PR or do you want me to? |
Never wrote a single line of rust :) |
I actually meant @thekr1s :) @thekr1s if you are creating the PR can you move the volume level logic into a function something like |
I'll create a PR and look into this |
I have created issue #187 for this |
… faster at higher level
I use a Raspberry pi with a hifiberry. I installed run OSMC (includes Kodi) on it and added librespot. The volume control of librespot is very dfferent from Kodi. In the first 5 percent of the volume level in librespot, the volume increases very fast to about the same level Kodi has at 50%. That is what I try to solve here.
I'm not a mathematic, so I implemented some 'by trial' algorithm.
Note: I did not know how to test the handle_volume_up() and handle_volume_down() functions in spirc.rs.