@Ronald_Record As mentioned to Greg, I’m looking to read the play state in addition to the volume. From what I saw in the new
get_zone_attributes.py the state should be handed out from
@Ronald_Record As mentioned to Greg, I’m looking to read the play state in addition to the volume. From what I saw in the new
Yes, there is a
state zone attribute that can be used to see if a zone is currently playing, paused, or stopped. I use this and a few other zone attributes in the newly created
To try out
get_zone_remaining do a
git pull in your cloned RoonCommandLine directory. This should retrieve both
api/get_zone_remaining.py. Copy those into
/usr/local/Roon/api/ and symlink to
/usr/local/bin/ as you did with
I’m approaching this fade feature incrementally. First, what is the current volume what are the output ranges in the (grouped) zone. Next, how much time remaining in a playing zone. Finally, implement some sort of fade/restore in the playing zone at some time remaining. But, there are a number of ways to do this and several gotchas. How did you do it on Spotify? How would you like it to work on Roon?
Cool. So it is exposed in roonapi, right? I must have been blind. i didn’t see it there…
Works like a charm. Thanks heaps!
Well, I am thinking of an overall toggle command: When playing fade out, when not playing, fade in.
Now, the fade out would do this: Save the current volume, then slowly reduce the volume to zero, pause play back and set the volume back to the saved state.
For fade in the reverse logic would be used.
I wrote an Applescript using the specific Spotofy API (Yeah, Spotify supports Applescript!)
tell application "Spotify" try set saved_vol to sound volume set fade_time to 120 set delta to saved_vol / fade_time if player state is playing then set act_vol to saved_vol repeat until act_vol < 0 if act_vol < 0.3 * saved_vol then set act_vol to act_vol - (0.5 * delta) else set act_vol to act_vol - delta end if delay 0.05 if act_vol > 0 then set sound volume to round act_vol end if end repeat pause set sound volume to saved_vol else set act_vol to 0 set sound volume to act_vol play repeat until act_vol > saved_vol if act_vol < 0.3 * saved_vol then set act_vol to act_vol + (0.5 * delta) else set act_vol to act_vol + delta end if delay 0.05 if act_vol < saved_vol then set sound volume to round act_vol else set sound volume to saved_vol end if end repeat end if on error -- no track is the current track my notify_msg("Error during \"Fade Spotify\"") beep end try end tell
This implements the logic described above
@hallo_leo very cool. I am alternately amazed and disappointed with what can be done with AppleScript. You might be able to do something similar with Roon in AppleScript if Roon were running on a Mac and configured to use the system audio output. But, idk if AppleScript talks to Roon and even if it does that is not a good solution since it does not address other audio outputs and devices.
I am working on a fading feature for RoonCommandLine but it is trickier than I thought it would be. Roon can play multiple songs in multiple zones, zones can be grouped with the same audio in all zones, each zone in a zone grouping has separate volume controls and ranges, multiple devices can be used to adjust volume by zone or output. And there is the problem of a non-computable time delay for every API call over a local network. It becomes fairly complex trying to cover all the use cases. But, I have a start and it sorta works but not yet to my satisfaction.
I should have something to test this weekend. I’ll let you know how it progresses.
That’s fantastic. You really want to take RoonCommandLine to the next level!
@hallo_leo I’ve posted a new release of RoonCommandLine with fading implemented. See RoonCommandLine 2.0.7 with Fading feature, bug fixes
On a Mac you can just clone the repository,
RoonCommandLine version 2.0.7 release 1 can be found at:
Thanks for this! Will check it out.
Just installed (and tweaked for me the install due to some homebrew troubles). Now I can execute
roon_fade – and I can see you have done lots of work for this. Thanks heaps!
However I’m too dumb to understand how I can fade in and out with it:
roon_fadeonly displays that fading is enabled and
roon -c playstill does a abrupt start.
What do I miss?
PS: Furthernore, do you mind me asking what the
roon_faded service is for? Why cannot the
roon_fade command do the fading itself? Of course it would block the command line while doing so, but for this the user could send the command to the background…
To enable fading, issue the command
roon_fade on. To disable,
roon_fade off. By default, fading is performed in the RoonCommandLine default zone and any other zones it may be grouped with. The default zone is whatever zone you last used in a RoonCommandLine command. You can specify which zone to use for fading with the
-z zone command line arguments. For example, to perform fading in the Roon zone named “Living Room” you would issue the command
roon_fade -z "Living Room" on. To disable fading in the Living Room zone,
roon_fade -z "Living Room" off.
The default action after fading out is to fade back in for the next track. In your Spotify fade you restore the volume back to its unfaded level without fading back in. To do this with my implementation, set
/usr/local/Roon/etc/pyroonconf. This can be accomplished with the command
roon_fade -I (that’s a capital ‘I’). To go back to fading in after fading out,
roon_fade -i (lowercase ‘i’).
man roon_fade for more command line usage of this command.
roon_fade could have just done the fading itself rather than spawn
roon_faded to do the work. I split fading out into a separate command as
roon_fade can also be used to do other tasks like set the fade duration, enable and disable fade in after fade out, force restore of original volume, and disable fading altogether. I decided to use a frontend,
roon_fade, for this multi-purpose UI and a backend,
roon_faded, as a daemon strictly dedicated to fading. The daemon has to do a lot of work in the background like monitoring zones to see if they are playing and if the time remaining is below a threshold. It sleeps a lot. The frontend can be used to alter fading parameters during fading so I don’t want it sleeping, I want it available at all times.
It could be architected differently. It’s just a choice I made. You may have good arguments to make for re-architecting fading in RoonCommandLine and I would be happy to hear any suggestions for how to do this better. It is still a work in progress.
Please continue to let me know what goes wrong, what you would prefer, what you suggest, what you do not understand how to do, and what goes right. I consider this feature to be experimental at this stage and a lot more complicated than i expected it to be or what it should be.
Aha, I think we envision in detail quite different things when we talk about “fading”. Here how I understand your description by now: You think of teh player having a “fading” mode. Once in this mode the player will in future at some point of time fade the music out – and this time is the end of the track, right? Please correct me if i got it wrong.
I am thinking of “fading” as something which happens right now when I issue the command: I want the music to fade out slowly (like for you), but starting right now. Here my use case is:
I listen to music. Then the phone rings or my wife/husband/son/mum/post woman/whoever knocks on the door and I would like to attend to them without music. So I want to switch the music off, but just pressing/issuing “pause” feels so abrupt and brutish! That’s the reason why I want a smooth fade-out, in say, 10 secs. (30 sec seems a bit long for my personal taste - and for the patience’s of the other person!)
After the interruption I want either to continue the music where I stopped it with a similar fade-in to the old volume level (I always had the idea of skipping back a bit “into the faded-out part” of the music, but have never implemented that) OR I want to start a new track with the current volume level.
Does this make sense?
Thanks for the details! Really appreciate it.
I can see that a
faded daemon makes sense – particular when you don’t want to fade now, but a some time in the future. Certainly more flexible, but also a lot more complex.
Thanks for the clarification of your desired use case. I can see that as a valid value add. At first glance, I think this would not be difficult. I will try to get this use case covered in my implementation of fading.
Would it suffice to simply be able to run a command like:
If so, what do you want the behavior to look like after an immediate fade? Pause or stop replay? Continue muted replay until another command is issued indicating fade back in?
Note that to mute Roon audio you can currently use
roon -c mute or
roon -c mute_all to mute audio in the default zone or all zones. To unmute, re-issue the same command. This is what I use when the phone rings but it is maybe not as graceful as a fade. I just discovered a bug with
mute_all but it still seems to work.
I’ll get right on it!
I’ve committed a first pass at “immediate mode” volume fading. I’m still working on it but wanted to give you a peek at where I’m going to get any feedback you may have. To grab the latest changes, do a
git pull in your cloned RoonCommandLine directory and copy
/usr/local/Roon/bin/roon_fade. Only this one file changed (other than corresponding changes to its man page) so it is only necessary to update the
Currently how I have implemented this is to add support for a
now argument - the command
roon_fade now fades volume immediately. After fading in this manner it then prompts to restore volume or stop playback and exit. Immediate fade also pauses playback then restores playback if you respond ‘y’ to restore volume.
Let me know what you think, this is very much still a work in progress.
Thanks @Ronald_Record. Just saw your update. Will pull your changes later. You are very quick.
By the way, was I correct that your use case is fading at the end of the track?
Yes, fading at the end of the track was what I tackled. I misunderstood your use case but hopefully now both our use cases are covered.
Yes, I am quick
This feature is isolated from the rest of RoonCommandLine fairly well so I am more comfortable pushing changes to fading in that regard. Also, I subscribe to the open source motto of “Release early and release often”. Finally, with this particular change - immediate fading, most of the work was just copying code from
roon_fade now command handles fading similar to how it is done in
roon_faded, disabling the daemon temporarily if it is running. So there is not a lot of “new” code in this change.
The fading works indeed. Thanks for this.
It feels correct when I am playing music and then issue
it does fade out and stops the music.
I am not so keen that it then asks for user input (I like usually command which do their thing and finish) to do something. Plus when i say no, it needs a long time to return (I guess it “fades in” the stopped music).
The other case, when I am not playing music, is a bit weird. I issue
roon_fade now and the first thing the command does is nothing (well, I guess it “fades out” the stopped music), then I have to say “y” and then, finally it starts playing with the fading.
Finally, the fade time in teh comamnd line argumet and in the config varaible
FADE_TIME does seem be in units of maybe 1/7 sec: E.g. setting FADE_TIME=100 gives me approx 15sec fade out or fade in.
After a very brief look at your
fade_ou function, I think, the factor for
outdiv might need to be modified to get the FADE_TIME units to full seconds? But this is probably system-depended. Maybe not too important…
For me a more natural behaviour is when
fade now works like a toggle:
If the music is playing, the command just fades out and stops the music (and set the volume back to the volume level at the beginning of the fade).
If the music is stopped or paused and you issue the command, it remembers the current volume level, then while starting t play it fades in from zero to the remembered volume level.
I think then there is no need for a separate
FADE_IN config variable…
Of course if somebody doesn’t like toggle commands, two separate commando
fade now-in and
fade now-out would do the trick too.
I will see whether I can wack something up over Xmas…
@hallo_leo good feedback, thanks for testing and for your suggestions. I agree, the default mode for immediate fading should be non-interactive and
roon_fade now should act like a toggle. This should be fairly easy to implement and test. I will have that ready today or tomorrow.
However, I would also like an interactive mode. I forgot which zone(s) I am fading in, which I am not, what the fade duration is, tell me what’s going on and where, then show me my options. Interactive mode should only be presented if requested. Implementing what I envision with this may take a few more days.
I will have to dig a little to figure out what is going on with the
FADE_TIME calculation. Thanks for the report. I have not noticed that on my system but will perform additional tests to see what’s going on. And take a look at
FADE_IN as well. I am sure I can simplify things a bit, especially in the immediate fade mode.
I got to thinking about your fading use case where the phone rings and you want the music to fade out. I thought this would be a good use case for voice control of Roon. Just say “Hey Siri, fade roon” and that triggers an iOS shortcut which executes
roon_fade now. But, this doesn’t work if the command is interactive and waiting for keyboard input sometimes. It needs to be non-interactive to automate with voice control.
Your feedback has been very helpful. Things are going to get hectic here so I am not sure when I will have all this tied together in a release. I’d like to get a new release out before my last minute Christmas shopping panic but probably should shop first and release later. Enjoy the holidays!
Agreed again. I have an observation about non-interactive use at the meoment. Will make a new topic about t.
Please do your shopping first! (I have to do mine as well…) There’s no urgency for this feature. As said maybe I can cobble something up in the Xmas-New Year break.
Same to you.