Export audio file volume dB levels in Linux
Asked Answered
M

2

5

I would like to be able to generate some sort of file that will store the volume levels of an audio file. I am pretty flexible about this but an example would be a csv that shows the volume every second. I don't need this number to be that precise.

Do you have any suggestions on how to approach this? I would appreciate it.

Murchison answered 28/4, 2013 at 16:0 Comment(0)
E
5

You may take the BASS library (free for non-commercial) and use BASS_ChannelGetLevel().

Here is the code to get levels and output it to STDOUT:

#include <cstddef>
#include <stdio.h>
#include <stdlib.h>

#include "bass.h"

int main(int argc, char **argv)
{
    BASS_Init(0 /* "NO SOUND" device */, 44100, 0, 0, NULL);
    if ( argc == 3 )
    {
        int block = atoi( argv[2] ); // take levels every argv[2] ms
        if ( block < 20 )
            block = 20;

        HSTREAM chan = BASS_StreamCreateFile(FALSE, argv[1], 0, 0, BASS_STREAM_DECODE);
        if ( chan )
        {
            // BASS_ChannelGetLevel takes 20ms from the channel
            QWORD len = BASS_ChannelSeconds2Bytes(chan, (float)block / (float)1000 - (float)0.02); 

            char data[len];
            DWORD level, left, right;

            while ( -1 != (level = BASS_ChannelGetLevel(chan) ) ) // takes 20ms
            {
                left=LOWORD(level); // the left level
                right=HIWORD(level); // the right level
                printf("%i, %i\n", left, right);
                BASS_ChannelGetData(chan, data, len); // get data away from the channel
            }
            BASS_StreamFree( chan );
        }
    }

    BASS_Free();
    return 0;
}

Extract bass.h and libbass.so from the bass24-linux.zip archive and build the cpp file with:

g++ levels.cpp -o levels -lbass

How to execute: levels filename milliseconds(20minimum)

./levels 1.mp3 5000 >levels.txt

Here is the levels.txt with levels taken every 5 sec (left channel, right channel):

1, 2
23235, 20363
22704, 20601
27203, 22476
10384, 12082
12059, 13387
9600, 10063
14590, 12261
16428, 14745
17569, 14723
29628, 27913
20799, 23554
24056, 20564
20344, 21242
21318, 22888
25389, 29050
27185, 23924
25469, 22540
28453, 29037
19669, 19797
16497, 16086
12081, 11843
20030, 20050
20512, 19537
19347, 14610
27673, 26563
26414, 24696
19775, 22869
24137, 25127
22093, 23184
26563, 24422
27718, 23791
24456, 26598
29353, 22647
562, 508

The level ranges linearly from 0 (silent) to 32768 (max).

Time for 6mb mp3 file, 100ms period:

# time ./levels 1.mp3 100 >levels.txt

real    0m0.981s
user    0m0.972s
sys     0m0.008s

About a second to produce 22Kb levels.txt file with 100ms period.

Erminia answered 2/5, 2013 at 12:15 Comment(11)
@user1322158 Feel free to contact me if you have a problem with it.Erminia
I put bass.h, levels.cpp, and libbass.so in their own directory and ran the g++ compile command but I got an error: /usr/bin/ld: cannot find -lbassChristiansen
I added -L . to tell g++ where to find the libbass.so. However, I still get "/usr/bin/ld: skipping incompatible ./libbass.so when searching for -lbass"Christiansen
Next I added -m32 to default to 32bit since I'm on a 64bit OS. However, now it complains /usr/include/features.h:323:26: fatal error: bits/predefs.h: No such file or directoryChristiansen
I dropped the 32bit libbass.so and used the version in the x64 folder instead. It compiled just fine. However, I went to run it and it says ./levels: error while loading shared libraries: libbass.so: cannot open shared object file: No such file or directoryChristiansen
You probably need to add -L./path/to/bass/lib to your linker optionsErminia
I did, like above - but I still get the error when I try to run it. I think it has something to do with LD_LIBRARY_PATH.Christiansen
try run export LD_LIBRARY_PATH="/path/to/bass/lib" before you run the applicationErminia
Worked, although I appended it instead of overwriting `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/lib"Christiansen
Is it possible to add a time-stamp value to note the time when the sample was taken?Christiansen
Why? You set a period. So you always know what time values from. If you get values for each 20ms so you have 0, 20, 40, 60,...Erminia
R
2

Pseudo code:

open input (audio) file
open output (data) file
for each one second chunk
   read samples for current chunk
   calculate RMS value (rms = sqrt(sum(x^2)/N))
   convert RMS value to dB (db = 20 * log10(rms))
   save dB value in output file
close input file
close output file
Rambo answered 28/4, 2013 at 16:24 Comment(6)
Thanks Paul for your time typing that out. Can you explain how I can open/read the audio data? Thank you.Murchison
There are various third party libraries for working with audio files - the choice will depend on your OS/platform/programming language and what audio file formats you need to work with.Rambo
I am working on a CentOS box, I was hoping to be able to do the creation of the file via shell but am willing to work in pretty much any language (assuming I don't have to learn too much), audio file format doesn't matter at all, I can convert to any format that is convenient.Murchison
OK - I would probably start by looking at libsoxRambo
Thank you for the suggestion...I currently have the following command sox file.wav -r 1 file.dat which outputs something like ; Sample Rate 10 ; Channels 2 0 0.00085449219 -0.0007019043 0.1 0.01348877 -0.011260986 0.2 0.015930176 -0.013214111 0.3 0.014923096 -0.012390137 Would you be willing to explain what is x and N (and if I am using the correct params for sox)? Thanks a ton.Murchison
sox -r is just giving you a dump of the sample values - you could read these into another program and then do the processing as outlined in my answer above, although I would suggest using libsox and just write a single program that does everything - this will be more efficient than converting the data to text with and then processing it with a second program.Rambo

© 2022 - 2024 — McMap. All rights reserved.