Scripts for volume

609 views
Skip to first unread message

sam evans

unread,
Dec 1, 2017, 10:39:46 AM12/1/17
to QLab
Hi,

does anyone have a script (or a better idea) for controlling the volume of qlab to react to ambient noise around an installation? 

I'm currently developing an installation where audience members (one at a time) would lie down on a bed, watch a video and listen to a soundscape. There will be no technician monitoring the installation which is where it becomes tricky. The installation will be in museums/theatre foyers and i will program Qlab to run all day (SFX, LX and Video) on a loop. The ambient noise around the installation cant be controlled. one way to overcome this (in my head) would be to use the built in microphone (or connect a mic to the soundcard) and set a trigger so that when the ambient noise in the room rises above a pre determined dB level the level outputting from Qlab raises to account for this. Likewise, when the sound level drops back down the script tells Qlab to drop the level - but thats as far as ive got....

any advice/help/suggestions would be greatly appreciated.

Sam

micpool

unread,
Dec 1, 2017, 10:58:36 AM12/1/17
to QLab
The main problem you will have with any systerm that isn’t a properly designed ambient noise compensation system is that it will respond to your program as well as ambient noise. You need the level compensation to filter out your program material from what is picked up by the ambient monitoring microphone before applying the correction

Because of this a dedicated hardware ANC unit is the best option.

Mic

Rich Walsh

unread,
Dec 1, 2017, 6:41:16 PM12/1/17
to ql...@googlegroups.com
Ignoring the feedback issue Mic highlights, you could do something like this In principal:

/cue/duck/level/0/0 #/cue/mic/liveAverageLevel/1 0 -60#

This would inverse map the level of a Mic Cue called “mic” onto the level of a cue called “duck” – but it would be almost totally unusable! It’s more fun to map the mic level to pitch…

Scripts can’t do this sort of thing very well, but OSC variables can – just give the Network Cue a duration.

Rich

micpool

unread,
Dec 1, 2017, 7:34:38 PM12/1/17
to QLab
Shouldn’t that be the other way round. -60 0 so the cue you are adusting gets louder as the ambient mic level meters higher, so you can hear it above the ambient?

Before DSP, NOALA units (Noise operated automatic level adjusment) used to work by measuring the level and adjusting the amp gain prior to a paging announcement. It would then switch off for the duration of the announcement.

So you could use the OSC query method prior to each playback to get some idea of the ambient level and set the level for,the duration of the next playback.

Sound people that belong to institutes call this ‘gap ambient level measurement,. You can too!

One problem migh be that someone might have coughed loudly near the measurement mic when the OSC query fired, giving an inappropriate reading.

You might get round this by firing off 100 OSC query cues over,say 10:seconds and storing the level readings from the mic cue in a notes field, or a notes,field per,cue

You could then use a script to average the 100 levels, either using a simple log average or, if you belong to an institute, an immensely complex equation and set the level with the result of,
this.

If you are really mathmatically inclined you could calculate a proper Loudness measurement, or you could cheat by just putting some pea soupey reverb on the measurement microphone to smear the readings a bit

You probably want to restrict the level change to plus or minus 10 dB from your nominal level.

If you site the measurement mic away from your playback speakers its just possible you might be able to get a usable result while the audio is playing

I might have a go at this if I find a spare half hour tomorrow.

Mic


Friday, December 1, 2017 at 11:41:16 PM UTC, Rich Walsh wrote:
> Ignoring the feedback issue Mic highlights, you could do something like this In principal:
>
> /cue/duck/level/0/0 #/cue/mic/liveAverageLevel/1 0 -60#
>
> This would inverse map the level of a Mic Cue called “mic” onto the level of a cue called “duck” – but it would be almost totally unusable! It’s more fun to map the mic level to pitch…
>
> Scripts can’t do this sort of thing very well, but OSC variables can – just give the Network Cue a duration.
>
> Rich
>

Rich Walsh

unread,
Dec 2, 2017, 3:58:01 PM12/2/17
to ql...@googlegroups.com
Yes, sorry: I think I was too busy making sure it did something to check it was doing the right thing…

Rich

micpool

unread,
Dec 3, 2017, 9:22:35 AM12/3/17
to QLab
Well, that was an interesting question to look at in detail, I've found out many things I didn't know before. I'll summarise those first and then show a working version of a workspace that will set the volume of an audio cue (In the gap before it is played) by taking a couple of hundred of measurements of the ambient level, converting them to a dB value and applying them to the master level of an audio cue.

Meters and Levels:
The meters on QLab cues work in relation to plug in real audio level metering on the cue outputs, and OSC queries  as follows .  When the meter is at the point where the fader rests at 0dB (i.e just before it turns red that is 0dB RMS on that  cue output channel and that produces a maximum level in an OSC query e.g.in  /cue/SPLMIC/liveAverageLevel/1 0 100 it will return a level of 100.

As you increase the level the metering will turn red and extend into the area above a fader at 0dB. This will still return the maximum value set for the OSC query and will increase the sound level on the output.

I haven't fully investigated this next bit but it isn't necessarily what you might expect.  When you go beyond the level at which an RMS meter on the cue output is at 0dB i.e into the red zone, what happens next is audio dependent (which is understandable), but also dependent on the connected interface (which I don't fully understand.) For instance on a Roland Octacapture , a sine wave metering above 0dB distorts immediately, but if the same cue output is patched to headphones through the internal output it will go up to +10 before distorting. 

In this application though the important thing is that when the meter reaches the point where a slider at 0dB sits that is the maximum level (100) as far as the OSC query liveAverageLevel is concerned (The minimum is the absence of audio and will be 0).

This 0 to 100 scale is linear. What this means is that changing the min and max values in the query to -60 and 0 will NOT result in a dB value that you can set a fader with. You need to be able to do some complex maths on the value returned by the OSC query to get it into a usable log form so that the value measured e.g.-25dB can be used to set a slider in a different cue to -25dB. We can't do math  within an OSC query so we need to store the result of the query somewhere where we can get at it later so a script can do the math.

OSC Queries
You can do a lot more string manipulation in OSC queries than is immediately obvious. The most important thing is you can change the result of a query to text by enclosing the query in quotes. You can also, within these quotes, make multiple queries. In the example workspace attached I am using:

/cue/SPL/notes "#/cue/SPL/notes##/cue/SPLMIC/liveAverageLevel/1 0 1#:"

Which is setting the notes field of cue "SPL" to it's existing contents & the new contents & ":"

What this means is that in a single OSC cue with a query you can construct complex text in a notes field, which you can then use in calculations in a script cue. In the  example workspace  the OSC cue has a duration of 10 seconds. Meaning that for those 10 seconds it is constantly adding values to the notes field separated by colons. On my machine it can record about 200 osc query results in 10secs.

Example workspace
This workspace  listens to a microphone (or a test signal for testing) and samples its output level a couple of hundred times in 10 secs. It then converts an average of those 200 values to a dB value that can be used to set a fader on a cue prior to it being played. If you can site the measurement mic so that the audio playback does not make a significant difference to the level at the measuring mic you could run it continuously and have it update the fader level of the playing cue every 10 secs.

Here's the workspace:



You will notice I am using 0 to 1 for my min and max values. This makes things very easy because any value to be converted to a ratio is referenced to 0dB=1 so the maths is simplified. You can think of the OSC query as being a voltmeter where 0dB on the channel meter corresponds to 1V.

Here's the script:

set setlevelcue to "1" --cue to set master level of

tell application id "com.figure53.QLab.4" to tell front workspace

set thevalues to notes of cue "SPL" as text

set olddelimiter to AppleScript's text item delimiters

set AppleScript's text item delimiters to ":"

set thecount to (count of text items of thevalues) - 1

set theaccumulator to 0.0

repeat with n from 1 to thecount

set theaccumulator to theaccumulator + (text item n of thevalues as number)

end repeat

set theaccumulator to theaccumulator / thecount

set thelog to my log10(theaccumulator)

set thedecibel to 20 * (thelog)

set the notes of cue "REC" to thedecibel

set notes of cue "CALC" to thecount

--insert any extra maths to modify level setting (min. max etc) here

cue setlevelcue setLevel row 0 column 0 db thedecibel

set AppleScript's text item delimiters to olddelimiter

end tell


on log10(thenumber)

set natural_log to (do shell script ("echo 'l(" & (thenumber as string) & ")' | bc -l")) as real

set natural_log_of_10 to (do shell script ("echo 'l(10)' | bc -l")) as real

set common_log to natural_log / natural_log_of_10

return common_log

end log10


We set the cue number  we are going to change the master level of at the top of the script so it's easy to find.

We set a variable called the values to the contents of the notes field to get the large number of recorded results from the OSC queries.

We change the text delimiters to ":" so that each recorded result becomes a separate text item

We sum all the records and divide by the number of records to get an average of the level over 10 secs. (There are probably more complex methods of doing this but in practical experiments this works well enough)

We then need to calculate 20*(log10(the average level)

Applescript is somewhat deficient in the Maths department  so we have to use  a shell script to do this calculation at the system level. This is the function at the bottom of the script.

We now have a usable level which is used to set the master slider level of the cue number set at the top of the script.

We also write some of the results to the notes cues of other cues for monitoring

I think that's a reasonably clear explanation. Anything you don't understand, or if you think any of my explanation is misleading or scientifically inaccurate then give us a shout.

The workspace has 2 sets of cues. The top 1 uses a mic cue for a real SPL reading.

The bottom set substitutes a 1KHz sine wave for the mic so that you can check it's working correctly. Be careful of  your ears and your speakers when testing!


Mic

On Friday, December 1, 2017 at 3:39:46 PM UTC, sam evans wrote:
NOALA.zip

Rich Walsh

unread,
Dec 6, 2017, 7:06:52 AM12/6/17
to ql...@googlegroups.com
This is very neat.

If you use space as your delimiter instead of : you can save a few lines of code by getting words of thevalues – without having to change TIDs.

In fact – although I can’t say I understand it – you can get the average real quick:

set theccumulator to (do shell script "echo " & notes of cue "SPL" & " | awk '{s+=$1}END{print s/NR}' RS=\" \" ")

That’s with a space; you could change it back to :.

I think awk can even do logs…

Rich

Rich Walsh

unread,
Dec 6, 2017, 8:40:06 AM12/6/17
to ql...@googlegroups.com
In fact, you can replace 11 lines plus the handler with:

set thedecibel to (do shell script "echo " & notes of cue "SPL" & " | awk '{s+=$1}END{print 20*log(s/NR)/log(10)}' RS=\" \" ")

Or, if using : still:

set thedecibel to (do shell script "echo " & notes of cue "SPL" & " | awk '{s+=$1}END{print 20*log(s/(NR-1))/log(10)}' RS=\":\" ")

You don’t get quite as many decimal places, but there’s probably some awk setting I’ve not looked into…

I think “words of thevalues” may even work using : as the delimiter, without using TIDs – and without the extra blank one at the end.

Rich
Message has been deleted

micpool

unread,
Dec 6, 2017, 9:39:50 AM12/6/17
to QLab
Thanks Rich

I think I’m going to write this up on The Cook Book as a project to do gap ambient level control on a preshow sequence with music and announcements as I can do a workspace which replays audience chatter recordings so that it can be used for testing and experiment before trying it with a live audience.

I’ll present the program  the long winded way first, as I like any code on the Cook Book to be readily understandable and adaptable by people with rudimentary programming ability. 

However, these awk methods are  so brilliant and, in the simple example we have to resort to UNIX stuff to do some of the maths anyway. Its a good project to present this level of  optimised coding, and that could  be part 2 of the tutorial. 

If I may, I’ll send you a draft when it’s done If you were able to do a short commentary or annotation on the awk stuff that would be brilliant.

One question about delimiters. How long to they persist when set? I’ve read you can’t assume what they are set to  and it’s good practice to set them back where they were, but does that still apply in the QLab script context? Can a script cue assume they are set to space so you can use words of ?

Thanks again for your help and interest.

Mic

Rich Walsh

unread,
Dec 6, 2017, 10:03:25 AM12/6/17
to ql...@googlegroups.com
On 6 Dec 2017, at 14:39, micpool <m...@micpool.com> wrote:

Thanks Rich

I think I’m going to write this up on The Cook Book as a project to do gap ambient level control on a preshow sequence with music and announcements as I can do a workspace which replays audience chatter recordings so that it can be used for testing and experiment before trying it with a live audience.

I’ll present the program  the long winded way first, as I like any code on the Cook Book to be readily understandable and adaptable by people with rudimentary programming ability.

I also try to make everything I “publish” (eg: my template) over-verbose so it’s easy to follow – although sometimes a quick answer on the forum doesn’t get to go sesquipedalian… I try to optimise the number of steps, but not the number of characters typed – henceAllTheVeryLongVariableNames. It’s nice to be able to understand something yourself nearly a decade later! 

However, these awk methods are  so brilliant and, in the simple example we have to resort to UNIX stuff to do some of the maths anyway. Its a good project to present this level of  optimised coding, and that could  be part 2 of the tutorial. 

If I may, I’ll send you a draft when it’s done If you were able to do a short commentary or annotation on the awk stuff that would be brilliant.

All from Google today: s is a variable that uses a defined operator to sum column 1 of the input; END marks the end of the “program” (I think); print outputs the result, via a couple of mathematical operations; NR is a defined variable of the number of lines; RS sets the delimiter between lines. I think.

One question about delimiters. How long to they persist when set? I’ve read you can’t assume what they are set to  and it’s good practice to set them back where they were, but does that still apply in the QLab script context? Can a script cue assume they are set to space so you can use words of ?

My basic understanding is that AppleScript’s text item delimiters are a property of the script runner, not the script – so they aren’t reset when recompiling and persist in Script Editor until you quit. Don’t know what that means for QLab… I have a Script Menu script (based on Apple’s bundled ones) that inserts a block to get/set/reset TIDs each time I use them and just automatically reset them each time I change them so I never get caught out.


If you change the text item delimiters property in Script Editor, it remains changed until you restore its previous value or until you quit Script Editor and launch it again. If you change text item delimiters in a script application, it remains changed in that application until you restore its previous value or until the script application quits; however, the delimiters are not changed in Script Editor or in other script applications you run.

“Words” is an element of text objects that relies on International settings (not AppleScript’s text item delimiters) – https://developer.apple.com/library/content/documentation/AppleScript/Conceptual/AppleScriptLangGuide/conceptual/ASLR_fundamentals.html#//apple_ref/doc/uid/TP40000983-CH218-BAJBDEJI:

A continuous series of characters, with word elements parsed according to the word-break rules set in the International preference pane.

“Text items” depends on TIDs, lots of other handy things like “paragraphs” don’t.

Rich

Rich Walsh

unread,
Dec 6, 2017, 12:00:45 PM12/6/17
to ql...@googlegroups.com
I was pondering this on my way to do something else and I think there’s a mistake: you need the latter form of the awk string whether using space or : , as either way you’ll get one more line in the sum than there are numbers…

Not sure how I missed that earlier. Worth a thorough check that the results are as expected!

Rich

micpool

unread,
Dec 18, 2017, 12:22:55 PM12/18/17
to QLab
Reply all
Reply to author
Forward
0 new messages