[opus] [PATCH] Add Functions to Create Ambisonic Multistream Encoder

Michael Graczyk mgraczyk at google.com
Wed May 25 02:33:53 UTC 2016


Alright, I've made the changes to the enum and flag usage.

I'm don't see the difference with respect to "disabling blocks of code",
since the compiler should completely elide the blocks that are conditioned
on a constant 0. If there were compiler errors in the experimental code
there could be a difference, but I'm hoping that is not the case on any
platform! Either way I changed them to #ifdef everywhere.



On Tue, May 24, 2016 at 8:26 AM, Jean-Marc Valin <jmvalin at jmvalin.ca> wrote:

> Hi Michael,
>
> On 05/24/2016 01:14 AM, Michael Graczyk wrote:
> > Thanks for pointing out the make differences. Do you mind if I add an
> > #ifndef, #define to the top of the file for the experiment flag? The
> > code becomes significantly more nasty with #ifdefs everywhere and it
> > would only get worse in subsequent patches.
>
> Unless it makes the code really bad, I'd rather use #ifdefs directly
> since we'll want to use it to disable blocks of code and mostly because
> everything else already uses that (it would be confusing).
>
> Thanks,
>
>         Jean-Marc
>
>
> > On May 23, 2016 21:28, "Jean-Marc Valin" <jmvalin at jmvalin.ca
> > <mailto:jmvalin at jmvalin.ca>> wrote:
> >
> >     On 05/23/2016 10:57 PM, Michael Graczyk wrote:
> >     > Since they correspond to mapping family values, I figured it would
> be
> >     > wise to make them match so that the correspondence would be clear.
> If
> >     > you would rather that correspondence not be explicit I will remove
> the
> >     > explicit assignments.
> >
> >     I'd rather have them be different, since they're not really the same
> >     thing. The idea is that we may have more than one family map to the
> same
> >     type (e.g. currently both families 0 and 255 map to TYPE_NONE).
> >
> >     One last thing I just noticed, please don't rely on
> >     ENABLE_EXPERIMENTAL_AMBISONICS actually being defined to zero when
> your
> >     patch is disabled. Some people don't use the autotools build (e.g.
> they
> >     use the plain Makefile or Visual Studio, or custom scripts), so your
> >     patch would break their build. Instead, please rely on #ifdef's.
> >
> >     Cheers,
> >
> >             Jean-Marc
> >
>



-- 

Thanks,
Michael Graczyk
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.xiph.org/pipermail/opus/attachments/20160524/a8328429/attachment.html>
-------------- next part --------------
From 71eac675fcff5659da30dd468797a3243615475c Mon Sep 17 00:00:00 2001
From: Michael Graczyk <michael at mgraczyk.com>
Date: Mon, 2 May 2016 21:42:18 -0700
Subject: [PATCH] Add experimental support for ambisonic encoding

The implementation currently only codes each channel independently with no
special allocation rules.
---
 configure.ac                   |  9 ++++++
 src/opus_multistream_encoder.c | 71 ++++++++++++++++++++++++++++++++----------
 2 files changed, 64 insertions(+), 16 deletions(-)

diff --git a/configure.ac b/configure.ac
index a67aa37..db1b10d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -736,6 +736,14 @@ AS_IF([test "$enable_fuzzing" = "yes"], [
   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])
@@ -820,6 +828,7 @@ AC_MSG_NOTICE([
       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}
diff --git a/src/opus_multistream_encoder.c b/src/opus_multistream_encoder.c
index 9e85773..f08789e 100644
--- a/src/opus_multistream_encoder.c
+++ b/src/opus_multistream_encoder.c
@@ -70,13 +70,21 @@ typedef void (*opus_copy_channel_in_func)(
   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;
    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 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b
    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 @@ opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_
    {
       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 @@ opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_
    return size;
 }
 
-
 static int opus_multistream_encoder_init_impl(
       OpusMSEncoder *st,
       opus_int32 Fs,
@@ -417,7 +431,7 @@ static int opus_multistream_encoder_init_impl(
       int coupled_streams,
       const unsigned char *mapping,
       int application,
-      int surround
+      MappingType mapping_type
 )
 {
    int coupled_size;
@@ -434,7 +448,7 @@ static int opus_multistream_encoder_init_impl(
    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 @@ static int opus_multistream_encoder_init_impl(
       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 opus_multistream_encoder_init(
       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 opus_multistream_surround_encoder_init(
       int application
 )
 {
+   int mapping_type;
    if ((channels>255) || (channels<1))
       return OPUS_BAD_ARG;
    st->lfe_stream = -1;
@@ -530,10 +547,32 @@ int opus_multistream_surround_encoder_init(
       *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 @@ static int opus_multistream_encode_native
    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 @@ static int opus_multistream_encode_native
    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 @@ static int opus_multistream_encode_native
       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 @@ static int opus_multistream_encode_native
          (*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 @@ static int opus_multistream_encode_native
          (*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 @@ static int opus_multistream_encode_native
          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 opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
    {
       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);
-- 
2.8.0.rc3.226.g39d4020



More information about the opus mailing list