ref: 3925668bbb536dbc6c244455276253527676ece3
parent: 914476c6531f63a69f66a1e8af20050a21bcdf21
author: Michael Graczyk <michael@mgraczyk.com>
date: Mon May 2 17:42:18 EDT 2016
Add experimental support for ambisonic encoding The implementation currently only codes each channel independently with no special allocation rules. Signed-off-by: Jean-Marc Valin <jmvalin@jmvalin.ca>
--- a/configure.ac
+++ b/configure.ac
@@ -748,6 +748,14 @@
AC_DEFINE([FUZZING], [1], [Fuzzing])
])
+AC_ARG_ENABLE([ambisonics],
+ [AS_HELP_STRING([--enable-ambisonics],[enable experimental ambisonic encoding and decoding support])],,
+ [enable_ambisonics=no])
+
+AS_IF([test "$enable_ambisonics" = "yes"], [
+ AC_DEFINE([ENABLE_EXPERIMENTAL_AMBISONICS], [1], [Ambisonics Support])
+])
+
AC_ARG_ENABLE([doc],
[AS_HELP_STRING([--disable-doc], [Do not build API documentation])],,
[enable_doc=yes])
@@ -832,6 +840,7 @@
Custom modes: .................. ${enable_custom_modes}
Assertion checking: ............ ${enable_assertions}
Fuzzing: ....................... ${enable_fuzzing}
+ Ambisonics support: .............${enable_ambisonics}
API documentation: ............. ${enable_doc}
Extra programs: ................ ${enable_extra_programs}
--- a/src/opus_multistream_encoder.c
+++ b/src/opus_multistream_encoder.c
@@ -70,6 +70,14 @@
int frame_size
);
+typedef enum {
+ MAPPING_TYPE_NONE,
+ MAPPING_TYPE_SURROUND,
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ MAPPING_TYPE_AMBISONICS,
+#endif
+} MappingType;
+
struct OpusMSEncoder {
ChannelLayout layout;
int arch;
@@ -76,7 +84,7 @@
int lfe_stream;
int application;
int variable_duration;
- int surround;
+ MappingType mapping_type;
opus_int32 bitrate_bps;
float subframe_mem[3];
/* Encoder states go here */
@@ -242,6 +250,7 @@
upsample = resampling_factor(rate);
frame_size = len*upsample;
+ /* LM = log2(frame_size / 120) */
for (LM=0;LM<celt_mode->maxLM;LM++)
if (celt_mode->shortMdctSize<<LM==frame_size)
break;
@@ -398,6 +407,12 @@
{
nb_streams=channels;
nb_coupled_streams=0;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ } else if (mapping_family==254)
+ {
+ nb_streams=channels;
+ nb_coupled_streams=0;
+#endif
} else
return 0;
size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
@@ -408,7 +423,6 @@
return size;
}
-
static int opus_multistream_encoder_init_impl(
OpusMSEncoder *st,
opus_int32 Fs,
@@ -417,7 +431,7 @@
int coupled_streams,
const unsigned char *mapping,
int application,
- int surround
+ MappingType mapping_type
)
{
int coupled_size;
@@ -434,7 +448,7 @@
st->layout.nb_streams = streams;
st->layout.nb_coupled_streams = coupled_streams;
st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
- if (!surround)
+ if (mapping_type != MAPPING_TYPE_SURROUND)
st->lfe_stream = -1;
st->bitrate_bps = OPUS_AUTO;
st->application = application;
@@ -463,12 +477,12 @@
if(ret!=OPUS_OK)return ret;
ptr += align(mono_size);
}
- if (surround)
+ if (mapping_type == MAPPING_TYPE_SURROUND)
{
OPUS_CLEAR(ms_get_preemph_mem(st), channels);
OPUS_CLEAR(ms_get_window_mem(st), channels*120);
}
- st->surround = surround;
+ st->mapping_type = mapping_type;
return OPUS_OK;
}
@@ -482,7 +496,9 @@
int application
)
{
- return opus_multistream_encoder_init_impl(st, Fs, channels, streams, coupled_streams, mapping, application, 0);
+ return opus_multistream_encoder_init_impl(st, Fs, channels, streams,
+ coupled_streams, mapping,
+ application, MAPPING_TYPE_NONE);
}
int opus_multistream_surround_encoder_init(
@@ -496,6 +512,7 @@
int application
)
{
+ int mapping_type;
if ((channels>255) || (channels<1))
return OPUS_BAD_ARG;
st->lfe_stream = -1;
@@ -530,10 +547,32 @@
*coupled_streams=0;
for(i=0;i<channels;i++)
mapping[i] = i;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ } else if (mapping_family==254)
+ {
+ int i;
+ *streams=channels;
+ *coupled_streams=0;
+ for(i=0;i<channels;i++)
+ mapping[i] = i;
+#endif
} else
return OPUS_UNIMPLEMENTED;
- return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, *coupled_streams,
- mapping, application, channels>2&&mapping_family==1);
+
+ if (channels>2 && mapping_family==1) {
+ mapping_type = MAPPING_TYPE_SURROUND;
+#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
+ } else if (mapping_family==254)
+ {
+ mapping_type = MAPPING_TYPE_AMBISONICS;
+#endif
+ } else
+ {
+ mapping_type = MAPPING_TYPE_NONE;
+ }
+ return opus_multistream_encoder_init_impl(st, Fs, channels, *streams,
+ *coupled_streams, mapping,
+ application, mapping_type);
}
OpusMSEncoder *opus_multistream_encoder_create(
@@ -730,7 +769,7 @@
opus_int32 smallest_packet;
ALLOC_STACK;
- if (st->surround)
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
preemph_mem = ms_get_preemph_mem(st);
mem = ms_get_window_mem(st);
@@ -784,7 +823,7 @@
mono_size = opus_encoder_get_size(1);
ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16);
- if (st->surround)
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in, st->arch);
}
@@ -813,7 +852,7 @@
else
ptr += align(mono_size);
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s]));
- if (st->surround)
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
opus_int32 equiv_rate;
equiv_rate = st->bitrate_bps;
@@ -859,7 +898,7 @@
(*copy_channel_in)(buf+1, 2,
pcm, st->layout.nb_channels, right, frame_size);
ptr += align(coupled_size);
- if (st->surround)
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
for (i=0;i<21;i++)
{
@@ -875,7 +914,7 @@
(*copy_channel_in)(buf, 1,
pcm, st->layout.nb_channels, chan, frame_size);
ptr += align(mono_size);
- if (st->surround)
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
for (i=0;i<21;i++)
bandLogE[i] = bandSMR[21*chan+i];
@@ -883,7 +922,7 @@
c1 = chan;
c2 = -1;
}
- if (st->surround)
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
/* number of bytes left (+Toc) */
curr_max = max_data_bytes - tot_size;
@@ -1183,7 +1222,7 @@
{
int s;
st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0;
- if (st->surround)
+ if (st->mapping_type == MAPPING_TYPE_SURROUND)
{
OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels);
OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120);