Home AMX User Forum AMX General Discussion
Options

Best way to handle slowing volume?

I'm controlling a Nexia tc Audio processor in a room. I've got two bargraphs on my touchpanel, one is display only and shows the audio level in the room. The other one is completely transparent and laid on top of the display level, and is the actual input device.

If I just set up a level event that sends the volume to the nexia every time a level event occurs, it sends way too many events and the nexia gets several seconds behind, it literally can't keep up with all the information i'm sending it. The obvious solution is to only send the level a few times a second.

I've figured out a way to do it, using a timeline, which seems a bit cumbersome, but I couldn't figure out how to check the status of a wait. Is this really the best way to accomplish this? Or is there a better way to do it that doesn't involve setting up a timeline?
define_constant
VolTL			=	3

define_variable
volatile long lVolTime[1]		=	200	

define_event //Main Page Events
//Volume Control

button_event[dvTP,17]
{
	push:
	{
		on[nVolumeActive]
	}
	release:                 //nVolumeActive basically means that level events dont get triggered because the panel dropped offline, only if you actually touch the volume bar
	{
		off[nVolumeActive]       
		if (nVolume<75)      //When you take your finger off, we send a final volume for where you ended up
		{
			send_string dvBiamp,"'SETL 1 OUTLVL 14 1 0 ',10"
			send_string dvBiamp,"'SETL 1 OUTLVL 14 2 0 ',10"
		}
		else
		{
			send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
			send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
		}
	}
}

level_event[dvTP,17]		//This is a level that you can't see layered on top of the visual one
{
	if(nVolumeActive)
	{
		nVolume=level.value	
		if (!timeline_active(VolTL))  //If you've sent the level within the last fifth of a second, don't do it again
		{		
			if (nVolume<75)
			{
				send_string dvBiamp,"'SETL 1 OUTLVL 14 1 0 ',10"
				send_string dvBiamp,"'SETL 1 OUTLVL 14 2 0 ',10"
			}
			else
			{
				send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
				send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
			}
			timeline_create (VolTL,lVolTime,1,timeline_relative,timeline_once)
		}		
		send_level dvTP,1,nVolume			//Show the volume on the touchpanel
	}
}

Comments

  • Options
    ericmedleyericmedley Posts: 4,177
    I cannot speak with any authority since I do not know the peice of gear.

    Having said that, it might be a good idea to send commands that volume ramp up and down as appposed to descrete volume commands. (Assuming the gear can do this)

    Most devices will ramp themselves up or down on their own. All you need do then is track the descrete volume feedback and send it to the fader. It will involve you putting some kind volume up or down buttons.

    Another thing you can do is track the volume fader data being sent when the user adjusts the fader on top, but don't send the data to the device until they releases their finger. That way you won't send a bunch of intermediate volume changes. The down side of this is that they can be moving the fader up but not hearing the volume change, so they keep going higher and higher. ONce they let go, they might get a rather sudden jump in the volume.

    Just a couple thoughts.

    I used to like the idea of the client adjusting the fader themselves but soon tired of the problems this sexy interface caused with slower gear. I eventually gave into the more quaint notion of just giving them a volume up and down button and leaving the fader as simple feedback. It is reliable and doesn't confuse the client.
  • Options
    yuriyuri Posts: 861
    nexia's accept level values and up/down commando's, so that could solve your problem.

    I just swamp the Nexia with volume information when a user uses the barpgraph to adjust to volume. It doesn't happen alot (maybe once or twice during a meeting).
    Sending the final volume on releasing the bargraph helps to make sure you are actually on the wanted volume.
  • Options
    drewdbdrewdb Posts: 14
    Just an idea.

    You could use the ramp commands by adding code to check what direction the user is going, Up or Down with a timer to check for a period of time that the user has stopped ramping the bargraph. Then you can send the Stop Ramp. If the user goes up/down/up/down and so on, it will just ramp up/down until they either "Release" or hold their finger in the one position. This would then be minimal commands being sent.
  • Options
    filpeefilpee Posts: 64
    I don't have any issues controlling the nexia via TCP. So not sure about your problem.
    Maybe you can reduce the range your ramping from. Instead of -100dB to +12 maybe try -50dB through 0dB

    Biggest issue I have with the nexia's is having only the last 10% of the volume bar being usefull (-100 to 0db ramping).

    I'd love to do some kind of logarithmic volume scale but not sure how to do that.
  • Options
    JeffJeff Posts: 374
    Up and Down Commandos, eh? Sounds intense . . . .

    I'd rather keep the bargraph than add + and - buttons. Changing which ramp command I send based on which direction the user is going doesn't really acknowledge where in the bargraph the person has selected.

    I mean, all of those suggestions will get the job done, but I don't see them being any more effective than what I wrote above. In fact, I think the trick with the timeline, which basically means it wont send the level more than once every 5 seconds, is more effective than everything except the individual volume buttons.

    Assuming I'd rather send discrete volume commands than try to guess ramping correctly, is there a better way in code to accomplish what I'm doing? The timeline just seems clunky, with the requirement for a declared constant and long.

    J
  • Options
    yuriyuri Posts: 861
    Jeff wrote: »
    Up and Down Commandos, eh? Sounds intense . . . .

    I'd rather keep the bargraph than add + and - buttons. Changing which ramp command I send based on which direction the user is going doesn't really acknowledge where in the bargraph the person has selected.

    I mean, all of those suggestions will get the job done, but I don't see them being any more effective than what I wrote above. In fact, I think the trick with the timeline, which basically means it wont send the level more than once every 5 seconds, is more effective than everything except the individual volume buttons.

    Assuming I'd rather send discrete volume commands than try to guess ramping correctly, is there a better way in code to accomplish what I'm doing? The timeline just seems clunky, with the requirement for a declared constant and long.

    J

    if you only send volume change every 5 seconds, the user will get confused. He ramps the volume bar up, and has to wait 5 seconds before he finds out if the volume is too loud or too soft...

    From the nexia manual:

    the FDRLVL command excepts the 'SET' commando, as well as INC/DEC
    You could use the INC/DEC commando's to raise the volume, and then process the incoming volume string to display your feedback :)
  • Options
    drewdbdrewdb Posts: 14
    One thing i have done before is have a variable like: VolumeIsUp. Set it to true on Push and false on Release. In the Mainline, have:

    Wait 2 (or minimum time to send strings)
    {
    If (VolumeIsUp && Volume <= MaxVolume)
    {
    Volume++;
    Send_String YourDevice, "String with Volume";
    {
    }

    Same for Volume Down.
    This will then only send the string with the wait time for the device when the user is pressing the button.
  • Options
    JeffJeff Posts: 374
    Sorry, I miswrote earlier. I'm sending the volume 5 times every second, not one time every 5 seconds.

    If I switch to using Inc/Dec to control the volume, what happens when a user just presses the volume bar someplace nowhere near where the volume is? Does it just ramp a little bit? Or does it ramp all the way up there?

    I'm intrigued by the mainline code variant, that could be fun to play with.

    J
  • Options
    filpeefilpee Posts: 64
    drewdb wrote: »
    One thing i have done before is have a variable like: VolumeIsUp. Set it to true on Push and false on Release. In the Mainline, have:

    Wait 2 (or minimum time to send strings)
    {
    If (VolumeIsUp && Volume <= MaxVolume)
    {
    Volume++;
    Send_String YourDevice, "String with Volume";
    {
    }

    Same for Volume Down.
    This will then only send the string with the wait time for the device when the user is pressing the button.

    In the spirit of not using mainline for much you could just do this with a hold event

    BUTTON_EVENT[DVTP,VOLUP]
    HOLD[2,REPEAT]:
    {
    If (VolumeIsUp && Volume <= MaxVolume)
    {
    Volume++;
    Send_String YourDevice, "String with Volume";
    {
    }
  • Options
    DHawthorneDHawthorne Posts: 4,584
    My considered opinion is that dragging a bargraph for volume control is only eye-candy and counter-intuitive to the way people are used to controlling their systems. Every factory remote in the world, has up/down buttons that you hold down to ramp the volume. So I make bargraphs display only, and give them up/down buttons too. I generally also give them presets they can use to store common listening volumes and go to them instantly (as long as the device has volume feedback). Doing it that way has resolved all manner of complications I no longer have to deal with :).
  • Options
    JeffJeff Posts: 374
    So something like this?
    define_event //Main Page Events
    //Volume Control
    
    button_event[dvTP,17]
    {
    	push:
    	{
    		on[nVolumeActive]
    	}
    	hold[2,repeat]:
    	{
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
    	}
    	release:
    	{
    		off[nVolumeActive]       
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
    	}
    }
    
    level_event[dvTP,17]		//This is a level that you can't see layered on top of the visual one
    {
    	if(nVolumeActive)
    	{
    		nVolume=level.value
    		send_level dvTP,1,nVolume
    	}
    }
    

    This takes care of sending the volume only five times a second once you've touched it and held for at least a 5th of a second, but it doesn't do anything the first time you touch it. Under this code, its entirely possible to just tap it once and have nothing at all get sent to the Biamp. If I put the send to the biamp under the Push operator, I wont have time to get nVolume from the level_event . . .

    Any idea on how to fix that one? Maybe another flag or something so that the level event itself sends the volume command to the biamp the first time its triggered since it has last been touched?

    J
  • Options
    JeffJeff Posts: 374
    DHawthorne wrote: »
    My considered opinion is that dragging a bargraph for volume control is only eye-candy and counter-intuitive to the way people are used to controlling their systems. Every factory remote in the world, has up/down buttons that you hold down to ramp the volume. So I make bargraphs display only, and give them up/down buttons too. I generally also give them presets they can use to store common listening volumes and go to them instantly (as long as the device has volume feedback). Doing it that way has resolved all manner of complications I no longer have to deal with :).

    I'm beginning to agree with you, but thats really not an option for me in this case. I'm not a very good graphic designer, and the guy who did this design has since left the company. I'd have to hire someone to redo the design to fit in additional volume up/down buttons, which I don't expect to happen. There's just not enough space where the volume bar is to add in up/down buttons right now, so it'd involve some significant redrawing.

    For future designs, however, I'll probably be going to buttons with a display level.

    J
  • Options
    yuriyuri Posts: 861
    Jeff wrote: »
    So something like this?
    define_event //Main Page Events
    //Volume Control
    
    button_event[dvTP,17]
    {
    	push:
    	{
    		on[nVolumeActive]
    	}
    	hold[2,repeat]:
    	{
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
    	}
    	release:
    	{
    		off[nVolumeActive]       
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
    	}
    }
    
    level_event[dvTP,17]		//This is a level that you can't see layered on top of the visual one
    {
    	if(nVolumeActive)
    	{
    		nVolume=level.value
    		send_level dvTP,1,nVolume
    	}
    }
    

    This takes care of sending the volume only five times a second once you've touched it and held for at least a 5th of a second, but it doesn't do anything the first time you touch it. Under this code, its entirely possible to just tap it once and have nothing at all get sent to the Biamp. If I put the send to the biamp under the Push operator, I wont have time to get nVolume from the level_event . . .

    Any idea on how to fix that one? Maybe another flag or something so that the level event itself sends the volume command to the biamp the first time its triggered since it has last been touched?

    J

    you can have the push operator fire an event, just add it there :p If someone taps the button, the volume gets sent. If someone holds the button, it only gets sent every 5th of a second :)
  • Options
    JeffJeff Posts: 374
    Yes, but where do I get the volume to send in the push operator? I obviously can't use level.value inside a button_event . . . .

    J
  • Options
    yuriyuri Posts: 861
    like this?
    push:
    	{
    		on[nVolumeActive]
                    send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
    	}
    	hold[2,repeat]:
    	{
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 1 ',itoa(nVolume*5),' ',10"
    		send_string dvBiamp,"'SETL 1 OUTLVL 14 2 ',itoa(nVolume*5),' ',10"
    	}
    



    :D
  • Options
    JeffJeff Posts: 374
    That send command sends nVolume*5 as the volume. Where is nVolume getting set?

    Its getting set the LAST time I touched the bar graph. So for example, I drag the bar graph all the way down to the bottom. I take my hand off. nVolume is now 0. Then I tap the bar graph about halfway up (lets pretend I tap exactly at 50). My understanding is things happen in this order

    1. Push Handler fires
    2. nVolumeActive is set to 1
    3. nVolume(0) is sent to the Biamp
    4. Level Event Fires
    5. nVolume is set to 50
    6. Release Handler fires
    7. nVolume(50) is sent to the Biamp

    Under that order, there's no reason to send in the push handler. Now that I look at it, though, that shouldn't be a problem, as long as the level event ACTUALLY fires inbetween the push and release handlers. Is that a fairly safe assumption?

    J
  • Options
    yuriyuri Posts: 861
    Jeff wrote: »
    That send command sends nVolume*5 as the volume. Where is nVolume getting set?

    Its getting set the LAST time I touched the bar graph. So for example, I drag the bar graph all the way down to the bottom. I take my hand off. nVolume is now 0. Then I tap the bar graph about halfway up (lets pretend I tap exactly at 50). My understanding is things happen in this order

    1. Push Handler fires
    2. nVolumeActive is set to 1
    3. nVolume(0) is sent to the Biamp
    4. Level Event Fires
    5. nVolume is set to 50
    6. Release Handler fires
    7. nVolume(50) is sent to the Biamp

    Under that order, there's no reason to send in the push handler. Now that I look at it, though, that shouldn't be a problem, as long as the level event ACTUALLY fires inbetween the push and release handlers. Is that a fairly safe assumption?

    J

    i guess it is :p
    like i said: i don't use 'slowing' of the volume, and all my nexias still work :)
  • Options
    JeffJeff Posts: 374
    I mean, it'd still work if you swamp it, but who wants to release the volume bar and 3 seconds later have it still be changing? Sure, you eventually end up on the level that the user last touched, but the user took their hand off when they heard what they want, not when they saw what they wanted.

    Thanks a ton guys, I'll try testing this out sometime this week.

    J
Sign In or Register to comment.