1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright (c) 2012-2017 VideoStitch SAS
// Copyright (c) 2018 stitchEm
//
// Ambisonic decoder coefficients parser
#include "libvideostitch/ambDecoderDef.hpp"
#include "libvideostitch/ambisonic.hpp"
#include "libvideostitch/logging.hpp"
#include "libvideostitch/parse.hpp"
#include "parse/json.hpp"
#include <sstream>
namespace VideoStitch {
namespace Audio {
AmbisonicDecoderDef::AmbisonicDecoderDef(const Ptv::Value& value)
: _order(getStringFromAmbisonicOrder(AmbisonicOrder::FIRST_ORDER)), _isValid(false) {
setCoef(value);
}
void AmbisonicDecoderDef::setCoef(const Ptv::Value& value) {
// Make sure value is an object.
if (!Parse::checkType("AmbisonicDecoderDef", value, Ptv::Value::OBJECT)) {
_isValid = false;
return;
}
if (Parse::populateString("AmbisonicDecoderDef", value, "order", _order, true) == Parse::PopulateResult_Ok &&
getAmbisonicOrderFromString(_order) != AmbisonicOrder::UNKNOWN) {
Logger::get(Logger::Warning) << "[ambisonic-decoder] Order " << _order << " not managed. Try a first order"
<< std::endl;
_order = getStringFromAmbisonicOrder(AmbisonicOrder::FIRST_ORDER);
}
if (value.has("coefficients") && value.has("coefficients")->has(getStringFromChannelLayout(STEREO))) {
const Ptv::Value* stereoCoef = value.has("coefficients")->has(getStringFromChannelLayout(STEREO));
parseFirstOrderCoef(stereoCoef, STEREO, SPEAKER_FRONT_LEFT);
parseFirstOrderCoef(stereoCoef, STEREO, SPEAKER_FRONT_RIGHT);
_isValid = true;
}
if (value.has("coefficients") && value.has("coefficients")->has(getStringFromChannelLayout(_5POINT1))) {
const Ptv::Value* fivePoint1 = value.has("coefficients")->has(getStringFromChannelLayout(_5POINT1));
parseFirstOrderCoef(fivePoint1, _5POINT1, SPEAKER_FRONT_LEFT);
parseFirstOrderCoef(fivePoint1, _5POINT1, SPEAKER_FRONT_RIGHT);
parseFirstOrderCoef(fivePoint1, _5POINT1, SPEAKER_LOW_FREQUENCY);
parseFirstOrderCoef(fivePoint1, _5POINT1, SPEAKER_FRONT_CENTER);
parseFirstOrderCoef(fivePoint1, _5POINT1, SPEAKER_SIDE_LEFT);
parseFirstOrderCoef(fivePoint1, _5POINT1, SPEAKER_SIDE_RIGHT);
_isValid = true;
}
// TODO: add other supported layouts 7.1 and quad stereo
}
AmbisonicDecoderDef::~AmbisonicDecoderDef() {}
const ambCoefTable_t& AmbisonicDecoderDef::getCoefficients() const { return _coefs; }
PotentialValue<channelCoefTable_t> AmbisonicDecoderDef::getCoefficientsByLayout(ChannelLayout layout) const {
if (_coefs.find(layout) == _coefs.end()) {
std::stringstream ss;
ss << "[ambisonic-decoder-coef] Layout " << getStringFromChannelLayout(layout) << "Not managed";
return Status(Origin::AudioPipelineConfiguration, ErrType::InvalidConfiguration, ss.str());
}
return _coefs.at(layout);
}
void AmbisonicDecoderDef::parseFirstOrderCoef(const Ptv::Value* v, ChannelLayout layout, ChannelMap out) {
if (v->has(getStringFromChannelType(out))) {
const Ptv::Value* coef = v->has(getStringFromChannelType(out));
for (int64_t c = SPEAKER_AMB_W; c <= SPEAKER_AMB_Z; c = c << 1) {
if (coef->has(getStringFromChannelType((ChannelMap)c))) {
_coefs[layout][out][(ChannelMap)c] = coef->has(getStringFromChannelType((ChannelMap)c))->asDouble();
}
}
}
}
Ptv::Value* AmbisonicDecoderDef::serialize() const {
std::unique_ptr<Ptv::Value> res(Ptv::Value::emptyObject());
res->push("order", new Parse::JsonValue(_order));
// Serialize coefficients
Ptv::Value* tableCoefs = Ptv::Value::emptyObject();
for (auto& tablePerLayout : _coefs) {
Ptv::Value* tableLayout = Ptv::Value::emptyObject();
for (auto& tablePerOutChannel : tablePerLayout.second) {
Ptv::Value* tableOutChannel = Ptv::Value::emptyObject();
for (auto& tablePerAmbChannel : tablePerOutChannel.second) {
tableOutChannel->push(getStringFromChannelType(tablePerAmbChannel.first),
new Parse::JsonValue(tablePerAmbChannel.second));
}
tableLayout->push(getStringFromChannelType(tablePerOutChannel.first), tableOutChannel);
}
tableCoefs->push(getStringFromChannelLayout(tablePerLayout.first), tableLayout);
}
res->push("coefficients", tableCoefs);
return res.release();
}
AmbisonicDecoderDef* AmbisonicDecoderDef::clone() {
AmbisonicDecoderDef* result = new AmbisonicDecoderDef(_coefs, _order);
return result;
}
AmbisonicDecoderDef::AmbisonicDecoderDef(const ambCoefTable_t& coefs, const std::string& order)
: _coefs(coefs), _order(order), _isValid(true) {}
} // namespace Audio
} // namespace VideoStitch