Best way for auto multiple processing

21 replies [Last post]
Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

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?

paul
paul's picture
User offline. Last seen 4 hours 57 min ago. Offline
Joined: 2006-03-16
Posts:

"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>)

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

test code

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

@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): https://s14.postimg.org/xmckj1a35/rms.png

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

Huh )) code tag not works or cracked

seablade
User offline. Last seen 3 hours 34 min ago. Offline
Joined: 2007-01-22
Posts:

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

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

@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?

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

Another way:

Here is one random region XML data from project: http://pastebin.com/dp3K7EQd

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

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?

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

@paul I just want advice how to do it correctly

seablade
User offline. Last seen 3 hours 34 min ago. Offline
Joined: 2007-01-22
Posts:

@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.

Seablade

x42
x42's picture
User offline. Last seen 7 hours 9 min ago. Offline
Joined: 2006-11-05
Posts:

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 https://github.com/Ardour/ardour/blob/master/scripts/s_region_gain.lua There are various ways to optimize this e.g. using SSE accelerated `compute_peak()` from http://manual.ardour.org/lua-scripting/class_reference/#ARDOUR:DSP but that's left as exercise for the reader :)

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

@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..

x42
x42's picture
User offline. Last seen 7 hours 9 min ago. Offline
Joined: 2006-11-05
Posts:

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 :)
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 :)

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

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.

x42
x42's picture
User offline. Last seen 7 hours 9 min ago. Offline
Joined: 2006-11-05
Posts:

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: https://github.com/Ardour/ardour/blob/master/libs/ardour/audioregion.cc#L1445

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

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: https://s22.postimg.org/7jtj9yh6p/regions_before.png

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: https://s3.postimg.org/m1fhuk07n/regions_after.png

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(
    $this->_start,
    $this->_length,
    $this->_channels
);
$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?

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

Or can I get same result from Ardour?

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

If you want test it I can share project data.

x42
x42's picture
User offline. Last seen 7 hours 9 min ago. Offline
Joined: 2006-11-05
Posts:

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 audioregion.cc 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 ?! :)

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.

Deep
User offline. Last seen 50 weeks 2 days ago. Offline
Joined: 2016-09-14
Posts:

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 https://github.com/Ardour/ardour/blob/master/scripts/s_region_gain.lua 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) {
            $this->_openSourceStream();
        }
        $frames = [];

        fseek(
            $this->_sourceStream,
            $this->_dataOffset + ($start * $channels * 4), // 4 (bytes) as 32 bit float
            SEEK_SET
        );
        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 ))

mhartzel
User offline. Last seen 55 min 10 sec ago. Offline
Joined: 2013-10-15
Posts:

This is all very interesting. Any chance of having an option to normalize regions to EBU R128 sometime in the future ? With this you could just chop speech with different volumes to individual regions and normalize loudness to R128. Maybe the open source libebur128 could be used for the measurement ?

This would speed up editing a radio program or podcast with speech and music a lot.

I guess RMS normalization gets you quite close and may be good enough in many cases ?

x42
x42's picture
User offline. Last seen 7 hours 9 min ago. Offline
Joined: 2006-11-05
Posts:

There's already a vamp plugin bundled with Ardour for EBU R128 normalization (used during export and for post-export and region analysis). For music it does not usually make sense to individually normalize to R128 so it has not been exposed. For a complete voice program on a single track. hmm maybe. I think you have a point: it's not significantly different from RMS normalization.