Skip to content

Commit

Permalink
Merge pull request #1 from media-io/dev/compute_adm_loudness
Browse files Browse the repository at this point in the history
Add new ADM Loudness analyser application
  • Loading branch information
MarcAntoine-Arnaud authored Oct 4, 2019
2 parents d9a42e7 + cc049e2 commit 9660356
Show file tree
Hide file tree
Showing 3 changed files with 245 additions and 0 deletions.
42 changes: 42 additions & 0 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,48 @@ AddOption(
help='Use this option to specify the path to qt library (is case of conflict between several versions for example).'
)

# Get ADM/EAR install path
AddOption(
'--adm',
dest='adm',
type='string',
nargs=1,
action='store',
default='/usr/local',
metavar='DIR',
help='Path to root of ITU-R ADM library.'
)
AddOption(
'--ear',
dest='ear',
type='string',
nargs=1,
action='store',
default='/usr/local',
metavar='DIR',
help='Path to root of EBU ADM Renderer library.'
)
AddOption(
'--bw64',
dest='bw64',
type='string',
nargs=1,
action='store',
default='/usr/local',
metavar='DIR',
help='Path to root of ITU-R BW64 headers.'
)
AddOption(
'--admrenderer',
dest='admrenderer',
type='string',
nargs=1,
action='store',
default='/usr/local',
metavar='DIR',
help='Path to root of ADM Audio Renderer.'
)

# Get ffmpeg install path
AddOption(
'--ffmpeg',
Expand Down
123 changes: 123 additions & 0 deletions app/AdmLoudnessAnalyser/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
#include <iostream>

#include <admrenderer/adm_helper.hpp>
#include <admrenderer/renderer.hpp>

#include <loudnessAnalyser/LoudnessAnalyser.hpp>

adm::LoudnessMetadata analyseLoudness(const std::unique_ptr<bw64::Bw64Reader>& bw64File, const admrenderer::Renderer& renderer, const bool displayResult) {
// Analyse loudness according to EBU R-128
Loudness::analyser::LoudnessLevels level = Loudness::analyser::LoudnessLevels::Loudness_EBU_R128();
Loudness::analyser::LoudnessAnalyser analyser(level);

// init
const size_t nbChannelsToAnalyse = renderer.getNbOutputChannels();
const size_t nbInputChannels = bw64File->channels();
const size_t sampleRate = bw64File->sampleRate();
analyser.initAndStart(nbChannelsToAnalyse, sampleRate);

// Create interlaced buffer
float readFileBuffer[admrenderer::BLOCK_SIZE * nbInputChannels] = {0.0,}; // nb of samples * nb input channels

while (!bw64File->eof()) {
// Read a data block
float admRenderBuffer[admrenderer::BLOCK_SIZE * nbChannelsToAnalyse] = {0.0,}; // nb of samples * nb output channels
const size_t nbFrames = bw64File->read(readFileBuffer, admrenderer::BLOCK_SIZE);
const size_t renderedSamples = renderer.processBlock(nbFrames, readFileBuffer, admRenderBuffer);


// Create planar buffer of float data
float** loudnessInputBuffer = new float*[nbChannelsToAnalyse];
for (size_t c = 0; c < nbChannelsToAnalyse; ++c) {
loudnessInputBuffer[c] = new float[nbFrames];
}

size_t channel_id = 0;
size_t frame_id = 0;
for (size_t s = 0; s < renderedSamples; ++s) {
channel_id = s % nbChannelsToAnalyse;
frame_id = s / nbChannelsToAnalyse;
loudnessInputBuffer[channel_id][frame_id] = admRenderBuffer[s];
}
analyser.processSamples(loudnessInputBuffer, nbFrames);

// free audio buffer
delete[] loudnessInputBuffer;
}
bw64File->seek(0);

if(displayResult) {
analyser.printPloudValues();
}

adm::LoudnessMetadata loudnessMetadata;
loudnessMetadata.set(adm::LoudnessMethod("ITU-R BS.1770"));
loudnessMetadata.set(adm::LoudnessRecType("EBU R128"));
loudnessMetadata.set(adm::IntegratedLoudness(analyser.getIntegratedLoudness()));
loudnessMetadata.set(adm::MaxTruePeak(analyser.getTruePeakValue()));
loudnessMetadata.set(adm::MaxMomentary(analyser.getMomentaryLoudness()));

if(analyser.isShortProgram()) {
loudnessMetadata.set(adm::LoudnessRange(analyser.getIntegratedRange()));
loudnessMetadata.set(adm::MaxShortTerm(analyser.getMaxShortTermLoudness()));
}
return loudnessMetadata;
}

void writetoFile(const std::unique_ptr<bw64::Bw64Reader>& inputFile,
const std::shared_ptr<adm::Document>& document,
const std::shared_ptr<bw64::ChnaChunk>& chnaChunk,
const std::string& outputFilePath) {
std::shared_ptr<bw64::AxmlChunk> axml = admrenderer::createAxmlChunk(document);
auto outputFile = bw64::writeFile(outputFilePath, inputFile->channels(), inputFile->sampleRate(), inputFile->bitDepth(), chnaChunk, axml);
std::vector<float> buffer(admrenderer::BLOCK_SIZE * inputFile->channels());
inputFile->seek(0);
while (!inputFile->eof()) {
auto readFrames = inputFile->read(&buffer[0], admrenderer::BLOCK_SIZE);
outputFile->write(&buffer[0], readFrames);
}
inputFile->seek(0);
}


int main(int argc, char const *argv[])
{
// std::cout << "Welcome to ADM Loundess Analyser!" << std::endl;
if (argc != 2 && argc != 3) {
std::cout << "Usage: " << argv[0] << " INPUT [OUTPUT]" << std::endl;
std::cout << " with INPUT BW64/ADM audio input file" << std::endl;
std::cout << " with OUTPUT BW64/ADM audio output file (optional)" << std::endl;
exit(1);
}

auto bw64File = bw64::readFile(argv[1]);
const std::string outputDirectory(".");
const std::string outputLayout("0+2+0");
admrenderer::Renderer renderer(bw64File, outputLayout);

auto admDocument = renderer.getDocument();
auto chnaChunk = renderer.getAdmChnaChunk();
auto audioProgrammes = renderer.getDocumentAudioProgrammes();
if(audioProgrammes.size()) {
for(auto audioProgramme : audioProgrammes) {
// std::cout << "### Render audio programme: " << admrenderer::toString(audioProgramme) << std::endl;
renderer.initAudioProgrammeRendering(audioProgramme);
const adm::LoudnessMetadata loudnessMetadata = analyseLoudness(bw64File, renderer, argc == 2);

// Update audio programme
admDocument->remove(audioProgramme);
audioProgramme->set(loudnessMetadata);
admDocument->add(audioProgramme);
}
} else {
std::cerr << "No ADM audio programme found." << std::endl;
exit(1);
}

if(argc == 3) {
const std::string outputFilePath(argv[2]);
// std::cout << "### Write to file: " << outputFilePath << std::endl;
writetoFile(bw64File, admDocument, chnaChunk, outputFilePath);
}
return 0;
}
80 changes: 80 additions & 0 deletions app/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -170,3 +170,83 @@ if 'loudnessAnalyserLibStatic' in locals() and \

else:
print('Warning: will not build media loudness analyser application.')

if 'loudnessAnalyserLibStatic' in locals() and \
'loudnessToolsLibStatic' in locals() and \
env['PLATFORM'] != 'win32': # Windows platform not supported yet.

### adm-loudness-analyser ###

adm_root = GetOption('adm')
adm_include = ''
adm_lib_path = ''
if adm_root:
adm_include = os.path.join( adm_root, 'include' )
adm_lib_path = os.path.join( adm_root, 'lib' )

ear_root = GetOption('ear')
ear_include = ''
ear_lib_path = ''
if ear_root:
ear_include = os.path.join( ear_root, 'include' )
ear_lib_path = os.path.join( ear_root, 'lib' )

bw64_include = GetOption('bw64')
if bw64_include is None:
bw64_include = ''

admrenderer_root = GetOption('admrenderer')
admrenderer_include = ''
admrenderer_lib_path = ''
if admrenderer_root:
admrenderer_include = os.path.join( admrenderer_root, 'include' )
admrenderer_lib_path = os.path.join( admrenderer_root, 'lib' )


# Check libs
admLoudnessEnv = env.Clone()

admLoudnessEnv.Append(
CPPPATH = [
adm_include,
ear_include,
bw64_include,
admrenderer_include,
],
LIBPATH = [
adm_lib_path,
ear_lib_path,
admrenderer_lib_path,
],
)

conf = Configure(admLoudnessEnv)

if adm_root and ear_root and admrenderer_root and \
conf.CheckCXXHeader('adm/adm.hpp') and \
conf.CheckCXXHeader('ear/ear.hpp') and \
conf.CheckCXXHeader("bw64/bw64.hpp") and \
conf.CheckCXXHeader('admrenderer/renderer.hpp'):

admLoudnessEnv = conf.Finish()

admLoudnessAnalyserProgram = admLoudnessEnv.Program(
'adm-loudness-analyser',
Glob( 'AdmLoudnessAnalyser/main.cpp' ),
LIBS = [
loudnessAnalyserLibStatic,
loudnessToolsLibStatic,
File(os.path.join( admrenderer_lib_path, 'libadmrenderer.a' )),
File(os.path.join( adm_lib_path, 'libadm.a' )),
File(os.path.join( ear_lib_path, 'libear.so' ))
]
)

env.Alias( 'install', env.Install( 'bin', admLoudnessAnalyserProgram ) )

else:
print('Warning: libadm, libear or libbw64 missing, will not build adm-loudness-analyser application')
conf.Finish()

else:
print('Warning: will not build ADM loudness analyser application.')

0 comments on commit 9660356

Please sign in to comment.