Best way for auto multiple processing

I have many regions.

Tell me please best way for auto processing for all of these regions by this steps:

  1. normalize to 0 dB;
  2. detect peaks by RMS and set envelope level for 0 dBFS.

Here need scripts? And maybe pass data to external application? I just don’t know correct way for it. This is possible?

“normalize to 0 dB” <= requires definition of which dB you mean; Ardour can trivially normalize to 0 dbFS (or any other dBFS level if you prefer). Select all regions (Ctrl-a), then right click on one of the and find Gain > Normalize in the context menus, or in the top level “Regions” menu.

RMS and dBFS don’t really mix. You either normalize so that the peak amplitude is 0 dBFS or you normalize so that the peak RMS reaches some level (not measured in dBFS but dB<other>)

test code

@paul I mean second case: custom RMS(?) energy level. I just want set “identical” levels for different regions. I do it by hand looking at the meter.
Probably, algorithm can be something like this (not tested for sound, pseudocode):

// preferences nrz = 1.0; // normalize "RMS" tolerance value // normalized frames (0 db max) frames = [ 0.0, 1.0, -0.222, 0.194, -0.166, 0.138, -0.111, 0.083, -0.055 ]; // internal defaults sum = 0.0; // sum of abs values mid = 0.5; // middle abs value bst = 1.0; // boost multiplier // calculate sum each frames as frm { sum += abs(frm); // can be heavily by RMS formula: pow(frm, 2) } // calculate middle and boost mid = sum / numberOfFrames; bst = nrz / 2 / mid; // apply boost each frames as frm { frm *= bst; }

This picture explain how it can works (see for short peak):

Huh )) code tag not works or cracked

Fixed it for you, apparently the CODE tag on the filtered HTML input that is used by default, doesn’t like whitespace lines in it, they probably turn into breaks or something similar and throws it off for some reason.


@seablade CODE tag missing indents )) very cracked ))

Ok. For algorithm above – this work I do it by hand looking at the meter. I want make it for many regions. By hand it very long time. I want add custom action for menu or make it otherwise. For fast and dirty: I can write C application for rewrite files of ardour project. But problem - this is not regions.

How I can make it with ardour lua? This is possible?

Another way:

Here is one random region XML data from project:

Where is reference to original file(id?) and data for offset/length frames?

position=“19548606” - first frame (offset in original file) for this region
length=“213504” - length of region (frames)
scale-amplitude=“1” - potential for change
source-0=“754132” - reference to original file id
master-source-0=“754132” - reference to original file id to?

@paul I just want advice how to do it correctly

@Deep ahh for what you are looking for try the PRE tag instead, most whitespace I think got stripped out of I would fix it for you.


Can you explain how the “middle abs value” is significant for audio?

Gain > Normalize can to normalize regions to a given peak dBFS and has the option to additionally not exceed a given RMS level. It can also be constrained for multiple-regions. In any case if you really need something different, since Ardour 5.4-399-gb2aaffa (earlier today) there are now Lua bindings to process raw region data and set the region-gain.

Select one or more audio region in the editor. then Menu > Window > Scripting In the dropdown select Snippets > Region Gain click “Run”
(You can also make it an action script and bind it to a button or keyboard shortcut…)

The script is There are various ways to optimize this e.g. using SSE accelerated compute_peak() from but that’s left as exercise for the reader :slight_smile:

@x42 explain: Each actor says short phrases. These phrases are very different in level. I must first align regions level of actor, and then align level of different actors. Yes, I know about compression and faders. But compressor smooths peaks, and fader I use for automation.

not exceed a given RMS level for each region or for all regions?

Oh… I made it today without ardour scripts (just CLI). Parse xml data of ardour project file, get source files for regions, read binary wav data frame by frame (start-length-channels) for any calculation, calculate it, rewrite value for “scale-amplitude” attribute of region tag. It works. ~3k regions. You will not believe what language I did it. OMG - php! I’m shocked myself…

It’s interesting that the average digital peak works for voice. If you cut all the silence from the regions it seems plausible though. Though RMS peak-hold should do the trick, too in this case.

Did you try the Region Normalize? I’d expect that leaving peak at 0dBFS, but constraining it to at most -20dBFS RMS (or thereabouts) would do the trick as well. For the final step tick the “Normalize each region using the peak of all regions” checkbox and use digital peak.

Anyway, it’s great that you managed to help yourself! Now try that with ProTools :slight_smile:
PHP is perfectly fine. I think it’s even the language where reading XML and iterating over elements needs the fewest lines of code. Then again perl would probably win a code golf for the whole thing - and neither code win a security or beauty test :slight_smile:

Yes. After cut silence it works correct.

Yes, I tried normalize to 0db. Incorrect between cries and whispers.

And -20db by RMS (“bottom”) will make “top” peak as great than 0db or not? I want soft limit for peaks. Yes, top as 0db, and bottom as -20 just for example.

Thanks for ProTools, but no )) I chose php as language for fast experiment. I lazy yesterday for use libxml with C.

The RMS normalization option was only added in Ardour 5.1 (in case you run an older version). It’s an additional constraint (logical AND).
If you have a sine-wave of -18dBFS and select to normalize to “0 dBFS peak” but at most “-12dBFS RMS” the normalization operation will apply 6dB of gain. The digital peak in this case will be -12dBFS as well (not 0).

As for the underlying maths:

O! Thanks for code!
Why n_chan (for audio) can be equal zero?

Ok. That’s not what I need.
I still try explain.
I’m bad explainer.

This is three test regions before processing:

1 region says: cheeke-cheeke-AAAA!-cheeke-cheeke
2 region says: po-chee-pee-pee-pee-bee
3 region says: AGRRRHHHHHHHH!!!

As you see it different levels, different energy.
This is regions after my test processing:

Sounds right. It keeps the same level for each region.
This is close of what I want.
I joke named it “intelligent leveler”.
I do not like my algorithm (magic numbers) but it makes what need:

$frames = $this->_source->getFrames(
$nrz = 0.75;
$sum = 0.0;
foreach ($frames as $frame) {
$sum += abs($frame);
$mid = $sum / sizeof($frames); // all channels in frames
$bst = $nrz / 10 / $mid;
$this->_regionXml[‘scale-amplitude’] = $bst;

Can you tell me what can be wrong here?

Or can I get same result from Ardour?

If you want test it I can share project data.

No, there is no built-in way to do exactly that. An average of the digital peak value is not a standard measure. It’s really medium related, so even while it may work well in your case we’ll have a hard time justifying this. I think it’s a good candidate for a script. Look at at region_gain.lua, if you remove the comments and “undo” it’s less than 20 lines and even similar to your code. Or if you really want to change the line 1469 in from rms += buf[i] * buf[i]; to rms += abs(buf[i]);, recompile Ardour, and RMS normalize to -22.5dBFS (your hardcoded 0.075).
While it may sound crazy, actually being able to hack the DAW was a major selling point for me doing post-production work: You can create the tool that you need for the project at hand. For movie postprod, which is usually a long process, it’s entirely worth it. I bet you’ll also find use-cases for your PHP script later doing some fancy batch modifications on the timeline: let’s swap scenes 3 and 4 shall we ?! :slight_smile:

As for n_chan > 0: I’m not entirely sure if it is still possible these days to obtain an AudioRegion with zero audio channels. But you can add/remove I/O ports, effectively turning an audio track into a midi-track post factum and there are also audio+midi tracks. That check probably just catches potential or historical edge case bugs.

Thank you!

Digital peak just for experiment, it so close of what I want. Just close. I will try it more.
No, 0.075 not hardcoded, it only for example. Ideally I want set something (like this value) from Ardour interface.
Thanks for yes, it can be modified.
No, I don’t want change standard ardour code (for upgrade without problem).

My php script? No… I think php is not good idea for audio processing.
Maybe for make something with xml structure - not bad.
But this is shit:

class Source

private $_sourceXml    = null;
private $_sourceFile   = null;
private $_sourceStream = null;
private $_dataOffset   = null;

public function __construct($sourceXml, $audioDirectory)
    $this->_sourceXml = $sourceXml;
    // check source audio file
    $sourceFile = $audioDirectory . '/' . $this->getAttrValue('name');
    if (!is_file($sourceFile)) {
        throw new Exception('Source file not exists: ' . $sourceFile);
    if (!is_readable($sourceFile)) {
        throw new Exception('Source file has not readable: ' . $sourceFile);
    $this->_sourceFile = $sourceFile;

public function getAttrValue($attrName)
    if (null === $this->_sourceXml[ $attrName ]) {
        throw new Exception(
            'Source entry not contain ' . $attrName . ' attribute'

    return $this->_sourceXml[ $attrName ]->__toString();

public function getSourceSize()
    return filesize($this->_sourceFile);

public function getFrames($start, $length, $channels)
    if (!$this->_sourceStream) {
    $frames = [];

        $this->_dataOffset + ($start * $channels * 4), // 4 (bytes) as 32 bit float
    for ($pos = 0; $pos < $length; $pos += 1) {
        for ($ch = 0; $ch < $channels; $ch += 1) {
            $frame    = unpack('f*', fread($this->_sourceStream, 4));
            $frames[] = $frame[1];

    return $frames;

private function _openSourceStream()
    $this->_sourceStream = @ fopen($this->_sourceFile, 'rb');
    if (!$this->_sourceStream) {
        throw new Exception(
            'Can\'t open source file: ' . $this->_sourceFile
    if ('RIFF' !== fread($this->_sourceStream, 4)) {
        throw new Exception(
            'This is not RIFF file: ' . $this->_sourceFile
    fseek($this->_sourceStream, 4, SEEK_CUR);
    if (
        'WAVE' !== fread($this->_sourceStream, 4) ||
        'fmt ' !== fread($this->_sourceStream, 4)
    ) {
        throw new Exception(
            'This is not WAVE file: ' . $this->_sourceFile
    $subChunk1Size = unpack('L*', fread($this->_sourceStream, 4));
    $subChunk1Size = $subChunk1Size[1];
    $audioFormat   = unpack('S*', fread($this->_sourceStream, 2));
    $audioFormat   = $audioFormat[1];
    if ($audioFormat !== 3) {
        throw new Exception(
            'Support only WAVE_FORMAT_IEEE_FLOAT Wave files'
    fseek($this->_sourceStream, $subChunk1Size - 2, SEEK_CUR);
    do {
        // nothing here, seek only
    } while('data' !== fread($this->_sourceStream, 4));
    $this->_dataOffset = ftell($this->_sourceStream);


Swap scenes impossible with Ardour lua?
I ask about it because I know little bit about Ardour features, and lua documentation (class reference) crack my brain ))