Waterfall Macro

Discuss DMXIS Python macro programming, and post any new macros here!
Post Reply
RichG
Posts: 178
Joined: Mon Nov 24, 2014 8:19 am

Waterfall Macro

Post by RichG » Thu Apr 11, 2019 6:31 am

I saw a concert where all the moving heads only were on during downward transitions. With all the moving heads sweeping downward at random this gave a neat effect light continuously cascading down creating a Waterfall of light. I took it upon myself to write a macro to achieve this. Select the Tilt and Dimmer channels for a moving head and run the macro. The macro sets the Dimmer value ON only during downward tilt transitions. Select as many Tilt/Dimmer pairs as you want. Just make sure your heads are set correctly... the macro assumes decreasing values correspond to downward tilting.

A few things to note about the Waterfall macro:
1. The macro works for any wave shape, although Saw Down is probably the most practical.
2. The macro takes into account value saturation (where it sticks at 100% or 0%)
3. Some movers are faster than others. The Dimmer may go ON as the head is tilting as fast as it can. There are adjustments available to fine tune the response so the Dimmer stays OFF long enough for the head to move into position.
4. After running the macro, the Dimmers will be out of sync with the Tilt. Click the Tap-Tempo in Show Buddy Active to reset the oscillators (or in DMXIS, save the preset, choose a different preset, then go back to the saved preset).

Code: Select all

#==============================================================================================
# DMXIS Macro
# Waterfall.py (c) RCG, 4/10/2019
# Turns Dimmer ON for downward transition, OFF for stationary
# and up transitions
# 
# Select fixtures in Tilt/Dimmer pairs.
# Dimmer is modified accordingly.
# Assumptions:
# 1. BPM and Speed are set slow enough for the fixtures to follow
# 2. Any fixture/channel inversions are set as desired
#==============================================================================================

#----------------------------------------------------------------------------------------------
# Custom Fine Tuning
# Modify these based on type of fixture.
# r:      Range of movement. This determines the On/Off point for the fixture.
#         Some waveshapes sit at 0% or 100% before they transition. For example, Saw Down with
#         a shape of 100.  This parameter controls the percent movement value when the light
#         turns on. When set to 0.95, the fixture light will go ON at 95% tilt, and OFF at 5%.
# mnshp:  Minimum Shape Value. This adjust the minimum ON duration for the fixture light.
# mnst_n: Minimum start point. Some fixtures move faster than others. For example, a scanner
#         with a mirror moves more quickly than a moving head. These parameters control time
#         to remain off while the fixture moves to the top of the waveform. The higher the
#         number, the longer the off time as the fixture transitions. If a fixture is
#         already sitting at the top of travel, then no delay is needed.
#         Notes for specific types:
#         Sine -     The higher the shape value, the more the sine will look like a Saw Down
#                    waveform. The fixture may not be able to follow the abrupt waveform upward
#                    for transition high shape values. This value compensates for slow upward
#                    transitions which require no delay vs. fast transitions requiring some
#                    delay.
#
#         Square -   The square wave relies on the fixture's finite transition time from top to
#                    bottom. The downward transition happens at the shape value, then goes back
#                    up at 1.
#
#         Triangle - The triangle type may linearly transition up and down, or may swoop up
#                    or down depending on the shape value.  High or low shape values can
#                    in prolonged stays at high or low values. Adjusting the 'r' value can
#                    ensure the light does not stay lit while the fixture is stationary.
#
#         Saw Up -   The saw up type transitions downward at the end of the waveform. It's like
#                    the square wave because it relies on the fixture speed to dictate the
#                    amount of ON time.
#
#         Saw Down - The saw down type is probably the most logical choice for this
#                    application. It follows the waveform downward, then quickly reverts
#                    back to the top point of travel. Since the upward transition happens
#                    at start of the waveform, a minimum start time should be set to avoid
#                    turning the light ON while the fixture is moving upward. The 'r' should
#                    be set to avoid turning the fixture ON while it is stationary.
#----------------------------------------------------------------------------------------------
print("===================================")

r      = 0.98 #-- 0..1 Range of ON movement
mnshp  = 0.05 #-- 0..1 Minimum Shape Value. Controls minimum ON time.    
mnst_1 = 0.10 #-- 0..1 Minimum Start Sine Type.
mnst_2 = 0.0  #-- 0..1 Minimum Start Square Wave Type.
mnst_3 = 0.10 #-- 0..1 Minimum Start Triangle Type.
mnst_4 = 0.0  #-- 0..1 Minimum Start Saw Up Type.
mnst_5 = 0.10 #-- 0..1 Minimum Start Saw Down Type.
    
#--------------------------------------------------
# Get the user selected channels 
#--------------------------------------------------
sel = GetAllSelCh(False)
nsel = len(sel)

#--------------------------------------------------
# Check user selection 
#--------------------------------------------------
if nsel < 2:
	Message("Select at least 2 channels")
elif nsel%2 > 0:
	Message("Select an even number of channels")
else:
	mx = 1.0  #-- maximum waveform value
	mn = 0.0  #-- minimum waveform value
	
	for i in range(0, nsel/2):
		tch = sel[i*2]     #-- Tilt Channel
		dch = sel[i*2+1]   #-- Dimmer Control Channel
		nm = GetChName(tch).lower()
		if nm == "tilt" or nm == "rotate":
			nm = GetChName(dch).lower()
			if nm == "dim" or nm == "dimmer":
				mag  = GetOscAmount(tch)          #-- Oscillation +/- per unit magnitude
				bias = float(GetChVal(tch))/255.0 #-- Bias point per unit value 0 = bottom of range 1 = top of range
				otyp = GetOscType(tch)            #-- Get Osc Type
				oshp = GetOscShape(tch)           #-- Get Osc Shape
				ochs = GetOscChase(tch)           #-- Get Osc Chase
				
				#-- OFF Osc Type -------------------------------------------------------------
				if otyp == 0:
					print ("Osc Typ is OFF for selected fixture %d. No changes made." % (i+1))			
				else:
				
				#-- Sine Osc Type -------------------------------------------------------------
					if otyp == 1:
						if oshp < (1 - mnst_1):
							mnstr = 0.0
						else:
							mnstr = oshp - (1 - mnst_1)

						sy = __builtins__.min( bias + r*mag, mx)
						fy = __builtins__.max( bias - r*mag, mn)

						x = (sy-bias)/mag
						#-- 15th order approximation of asin(x)
						asinx = 6.12683146168e-010+9.87783240580e-001*x-6.43155298791e-008*x*x+7.20086973441e-001*x*x*x+1.10581741541e-006*x*x*x*x-7.05868447545e+000*x*x*x*x*x-7.13154427362e-006*x*x*x*x*x*x+4.00656807560e+001*x*x*x*x*x*x*x+2.18726319233e-005*x*x*x*x*x*x*x*x-1.14049647532e+002*x*x*x*x*x*x*x*x*x-3.43685066853e-005*x*x*x*x*x*x*x*x*x*x+1.72788558895e+002*x*x*x*x*x*x*x*x*x*x*x+2.67183864481e-005*x*x*x*x*x*x*x*x*x*x*x*x-1.32449399902e+002*x*x*x*x*x*x*x*x*x*x*x*x*x-8.14116000307e-006*x*x*x*x*x*x*x*x*x*x*x*x*x*x+4.05067623852e+001*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x
	
						start = oshp*(0.5 - asinx/3.14159)
	
						x = (fy-bias)/mag
						#-- 15th order approximation of asin(x)
						asinx = 6.12683146168e-010+9.87783240580e-001*x-6.43155298791e-008*x*x+7.20086973441e-001*x*x*x+1.10581741541e-006*x*x*x*x-7.05868447545e+000*x*x*x*x*x-7.13154427362e-006*x*x*x*x*x*x+4.00656807560e+001*x*x*x*x*x*x*x+2.18726319233e-005*x*x*x*x*x*x*x*x-1.14049647532e+002*x*x*x*x*x*x*x*x*x-3.43685066853e-005*x*x*x*x*x*x*x*x*x*x+1.72788558895e+002*x*x*x*x*x*x*x*x*x*x*x+2.67183864481e-005*x*x*x*x*x*x*x*x*x*x*x*x-1.32449399902e+002*x*x*x*x*x*x*x*x*x*x*x*x*x-8.14116000307e-006*x*x*x*x*x*x*x*x*x*x*x*x*x*x+4.05067623852e+001*x*x*x*x*x*x*x*x*x*x*x*x*x*x*x
	
						fin = oshp*(0.5 - asinx/3.14159)
	
					#-- Square Wave Osc Type -------------------------------------------------------------
					elif otyp == 2:
						mnstr = mnst_2
						start = oshp
						fin   = oshp
						
					#-- Triangle Osc Type -------------------------------------------------------------
					elif otyp == 3:
						mnstr = mnst_3

						sy = __builtins__.min(bias + r*mag, mx)
						fy = __builtins__.max(bias - r*mag, mn)
						
						if oshp < 0.5:
							n   = 7 - 12*oshp
							start = 1 - (2**(-(n+1)/n))*( (sy-bias+mag)/mag )**(1/n)
							fin   = 1 - (2**(-(n+1)/n))*( (fy-bias+mag)/mag )**(1/n) 
						
						else:
							n   = 12*oshp - 5
							start = 0.5 + (2**(-(n+1)/n))*( (bias+mag-sy)/mag )**(1/n)
							fin   = 0.5 + (2**(-(n+1)/n))*( (bias+mag-fy)/mag )**(1/n)
	
					#-- Saw Up Osc Type -------------------------------------------------------------
					elif otyp == 4:
						mnstr = mnst_4
						start = 1
						fin   = 1
	
					#-- Saw Down Osc Type -------------------------------------------------------------
					elif otyp == 5:
						mnstr = mnst_5
						
						sy = __builtins__.min(bias + r*mag, mx)
						fy = __builtins__.max(bias - r*mag, mn)
						
						if oshp < 0.5:
							n   = 7 - 12*oshp
							start = 1 - ( (sy - bias + mag) / (2*mag) )**(1/n)
							fin   = 1 - ( (fy - bias + mag) / (2*mag) )**(1/n)
						
						else:
							n   = 12*oshp - 5
							start = ( (bias + mag - sy) / (2*mag) )**(1/n)
							fin   = ( (bias + mag - fy) / (2*mag) )**(1/n) 
						
					start = __builtins__.max(start, mnstr)
					shape = __builtins__.max(fin - start, mnshp)
					
					phase = ochs + 1 - start #-- Align start with descent point
					if phase > 1.0:
						phase -= 1.0
										
					print ("fx=%d mg= %5.3f bi=%5.3f str=%5.3f fin=%5.3f ph=%5.3f shp=%5.3f" % (i+1, mag, bias, start, fin, phase, shape)) 
					SetChVal(dch, 128)
					SetOscAmount(dch, 1)
					SetOscType(dch, 2)
					SetOscSpeed(dch, GetOscSpeed(tch))
					SetOscChase(dch, phase)
					SetOscShape(dch, shape)
			else:
				print ("Invalid Dimmer channel for selected fixture %d. No changes made." % (i+1))
		else:
			print ("Invalid Tilt channel for selected fixture %d. No changes made." % (i+1))
			

joel77
Posts: 34
Joined: Fri Jun 16, 2017 12:56 pm

Re: Waterfall Macro

Post by joel77 » Mon Mar 16, 2020 5:31 pm

Hi Rich,

I know it's been almost a year since you posted this macro, but I'm hoping you can help me.

I'm trying to use this macro with 4 Chauvet DJ Intimidator 260 movers. If I can get it to work I'd also use it with some 155 Duos.

I'm completely new to Python and know nothing about coding, so keep that in mind. LOL Oh, and I'm running DMXIS 1.6.9

I installed the macro according to instructions provided by Dave. I select the Tilt and Dimmer channels, select the Waterfall macro, but nothing happens. As you suggested, I saved it and selected another Preset, then went back to the Waterfall Preset, but still nothing moves. I know I'm doing something wrong, but I can't figure out what.

Also, you state in the instructions with this macro that the "r" or range of the tilt may need to be adjusted. Where exactly is that "r" in the code?
I see this line: -- r = 0.98 #-- 0..1 Range of ON movement -- but when I changed 0.98 to 0.90, nothing happened. But again, I have no idea what I'm doing!

Any help you could provide a newbie would be GREATLY appreciated. I'd love to make this work for me, I just don't know how to go about it.

Thank you, Rich!

RichG
Posts: 178
Joined: Mon Nov 24, 2014 8:19 am

Re: Waterfall Macro

Post by RichG » Tue Mar 17, 2020 5:42 am

Hi!

I'm glad someone is investigating this macro. Thanks for giving it a try! :)

Before using the Waterfall Macro, first set your movers up with some kind of movement. For example, select Pan and Tilt channels of your movers, then apply the Shapes|Circle Macro. Now that the movers are doing something, select the Tilt and Dimmer channels of the movers... Then run the Waterfall Macro.

Save the preset, then select a different one, then go back to the one you just saved.

The dimmer should be in sync with the downward motion of the tilt channels.

You can leave the 'r' value at .98 to start. The 'r' value is used a lot in the code to calculate a starting point on the y axis (sy) and a finishing point on the y axis (fy) like on lines 106 and 107 of the code.

joel77
Posts: 34
Joined: Fri Jun 16, 2017 12:56 pm

Re: Waterfall Macro

Post by joel77 » Fri Mar 20, 2020 4:39 pm

Thank you Rich!

I'm going to give that a try this weekend. I'll keep you posted.

Joel

joel77
Posts: 34
Joined: Fri Jun 16, 2017 12:56 pm

Re: Waterfall Macro

Post by joel77 » Sun Mar 22, 2020 7:40 pm

Hi Rich,

I have your WaterFall macro working! Thank you for the assistance. Much appreciated.

Now I have another issue. Maybe this is unique to the way I use DMXIS, but after running the preset with this macro, I can't get the dimmer channel to stop moving.

Keep in mind that I am an audio engineer first. I offer lighting to my clients (mostly bands), because most don't have their own, or not enough to do bigger shows. ie, I run both audio and lighting. The majority of the shows I work are smaller clubs/rooms and as a result I'm controlling both audio and lighting with a pair of iPads. For DMXIS, I'm using the TouchOSC app. Point being that I have to keep my lighting somewhat simple, as I need to be on top of what's going on with the audio. At the same time I want to offer a quality light show.

Over the last few years of using DMXIS I've come up with ways of running it that works for me. These may be unconventional or seem odd to some, but they work for me. One of those being that for most all of my presets, I have DIM, Shutter, Color, GOBO and other channels disabled (masked).

--- (I have faders which control the Dimmers of different groups of lights. Reason being, that I may want different types of lights to be brighter or dimmer, depending on the room, for example. I also have buttons that turn on/off various groups of lights. I REALLY dislike seeing a moving head light going through it's color/gobo wheels with the shutter open!) ---

So those presets are only controlling pan and tilt. Which, as I've now discovered, doesn't stop the strobing effect or reset the Dimmer. Now I need to find a way of resetting these if I want to be able to use strobes in my presets or use a macro like yours, that effects the Dimmer channel.

If you (or anyone) has any ideas, I'd love to hear them. Perhaps there are easy and obvious(to a lighting pro!) ways of accomplishing what I'm trying to do. If so, I'd love to hear them. If I'm completely off base, well, I can handle that as well!! LOL

Thank you in advance!

Joel

RichG
Posts: 178
Joined: Mon Nov 24, 2014 8:19 am

Re: Waterfall Macro

Post by RichG » Sat Mar 28, 2020 9:25 pm

Glad you got it working!

That does present an issue with the way you have the Dimmer masked. You have to somehow set the Dimmer back to 'normal'. Maybe you could have a Preset called 'Reset' that puts the Dimmer back to a non-pulsing mode... and then send two TouchOsc commands in a row. The first would call the Reset, then the second would call the actual desired Preset?

If there is some other light output control channel on your movers that aren't masked (maybe shutter?), then you could change line 87 of the macro to match that name. For example, change from this

if nm == "dim" or nm == "dimmer":

to this

if nm == "shutter":

In fact, shutter control is probably better than dimmer control for this macro.

Post Reply