shithub: aacenc

Download patch

ref: 12d7414f7ece191783e54d92beb46e0e182202f6
parent: e0066b4725069ce120acde8d584ade9bc2d3d0cf
author: Krzysztof Nikiel <knik@users.sourceforge.net>
date: Mon Oct 30 09:25:49 EDT 2017

initial implementation of Intensity Stereo coding

--- a/frontend/main.c
+++ b/frontend/main.c
@@ -94,6 +94,7 @@
     HELP_IO,
     HELP_MP4,
     HELP_ADVANCED,
+    OPT_JOINT
 };
 
 typedef struct {
@@ -183,7 +184,9 @@
 static help_t help_advanced[] = {
     {"--tns  \tEnable coding of TNS, temporal noise shaping.\n"},
     {"--no-tns\tDisable coding of TNS, temporal noise shaping.\n"},
-    {"--no-midside\tDon\'t use mid/side coding.\n"},
+    {"--joint 0\tDisable joint stereo coding.\n"},
+    {"--joint 1\tUse mid/side coding.\n"},
+    {"--joint 2\tUse intensity stereo coding.\n"},
     {"--mpeg-vers X\tForce AAC MPEG version, X can be 2 or 4\n"},
     {"--shortctl X\tEnforce block type (0 = both (default); 1 = no short; 2 = no\n"
     "\t\tlong).\n"},
@@ -421,7 +424,7 @@
     faacEncConfigurationPtr myFormat;
     unsigned int mpegVersion = MPEG2;
     unsigned int objectType = LOW;
-    static int useMidSide = 1;
+    static int jointmode = JOINT_IS;
     static int useTns = 0;
     enum container_format container = NO_CONTAINER;
     enum stream_format stream = ADTS_STREAM;
@@ -505,7 +508,7 @@
             {"help-mp4", 0, 0, HELP_MP4},
             {"help-advanced", 0, 0, HELP_ADVANCED},
             {"raw", 0, 0, 'r'},
-            {"no-midside", 0, &useMidSide, 0},
+            {"joint", required_argument, 0, OPT_JOINT},
             {"cutoff", 1, 0, 'c'},
             {"quality", 1, 0, 'q'},
             {"pcmraw", 0, 0, 'P'},
@@ -749,6 +752,9 @@
             help(c);
             return 1;
             break;
+        case OPT_JOINT:
+            jointmode = atoi(optarg);
+            break;
         case '?':
         default:
             help('?');
@@ -885,7 +891,7 @@
     }
     if (infile->channels >= 6)
         myFormat->useLfe = 1;
-    myFormat->allowMidside = useMidSide;
+    myFormat->jointmode = jointmode;
     if (quantqual > 0)
     {
         myFormat->quantqual = quantqual;
@@ -968,8 +974,15 @@
     fprintf(stderr, "(MPEG-%d)", (mpegVersion == MPEG4) ? 4 : 2);
     if (myFormat->useTns)
         fprintf(stderr, " + TNS");
-    if (myFormat->allowMidside)
+
+    switch(myFormat->jointmode) {
+    case JOINT_MS:
         fprintf(stderr, " + M/S");
+        break;
+    case JOINT_IS:
+        fprintf(stderr, " + IS");
+        break;
+    }
     fprintf(stderr, "\n");
 
     fprintf(stderr, "Container format: ");
--- a/include/faaccfg.h
+++ b/include/faaccfg.h
@@ -22,7 +22,7 @@
 #ifndef _FAACCFG_H_
 #define _FAACCFG_H_
 
-#define FAAC_CFG_VERSION 104
+#define FAAC_CFG_VERSION 105
 
 /* MPEG ID's */
 #define MPEG2 1
@@ -51,6 +51,8 @@
     ADTS_STREAM = 1,
 };
 
+enum {JOINT_NONE = 0, JOINT_MS, JOINT_IS};
+
 #pragma pack(push, 1)
 typedef struct faacEncConfiguration
 {
@@ -69,8 +71,8 @@
     /* AAC object type */
     unsigned int aacObjectType;
 
-    /* Allow mid/side coding */
-    unsigned int allowMidside;
+    /* Joint coding mode */
+    unsigned int jointmode;
 
     /* Use one of the channels as LFE channel */
     unsigned int useLfe;
--- a/libfaac/Makefile.am
+++ b/libfaac/Makefile.am
@@ -1,5 +1,5 @@
-common_SOURCES = bitstream.c fft.c frame.c midside.c blockswitch.c util.c channels.c filtbank.c tns.c quantize.c huff2.c huffdata.c
-common_INCLUDES = channels.h filtbank.h blockswitch.h coder.h frame.h midside.h tns.h bitstream.h fft.h util.h quantize.h version.h huffdata.h huff2.h
+common_SOURCES = bitstream.c fft.c frame.c blockswitch.c util.c channels.c filtbank.c tns.c quantize.c huff2.c huffdata.c stereo.c
+common_INCLUDES = channels.h filtbank.h blockswitch.h coder.h frame.h tns.h bitstream.h fft.h util.h quantize.h version.h huffdata.h huff2.h stereo.h
 common_LIBADD = -lm
 common_CFLAGS = -fvisibility=hidden
 if CPUSSE
--- a/libfaac/frame.c
+++ b/libfaac/frame.c
@@ -25,23 +25,18 @@
 
 #include "frame.h"
 #include "coder.h"
-#include "midside.h"
 #include "channels.h"
 #include "bitstream.h"
 #include "filtbank.h"
 #include "util.h"
 #include "tns.h"
-#include "version.h"
+#include "stereo.h"
 
-#if FAAC_RELEASE
-static char *libfaacName = FAAC_VERSION;
-#else
-static char *libfaacName = FAAC_VERSION ".1 (" __DATE__ ") UNSTABLE";
-#endif
+static char *libfaacName = PACKAGE_VERSION;
 static char *libCopyright =
-  "FAAC - Freeware Advanced Audio Coder (http://www.audiocoding.com/)\n"
+  "FAAC - Freeware Advanced Audio Coder (http://faac.sourceforge.net/)\n"
   " Copyright (C) 1999,2000,2001  Menno Bakker\n"
-  " Copyright (C) 2002,2003  Krzysztof Nikiel\n"
+  " Copyright (C) 2002,2003,2017  Krzysztof Nikiel\n"
   "This software is based on the ISO MPEG-4 reference source code.\n";
 
 static const psymodellist_t psymodellist[] = {
@@ -117,7 +112,7 @@
     int i;
     int maxqual = hEncoder->config.outputFormat ? MAXQUALADTS : MAXQUAL;
 
-    hEncoder->config.allowMidside = config->allowMidside;
+    hEncoder->config.jointmode = config->jointmode;
     hEncoder->config.useLfe = config->useLfe;
     hEncoder->config.useTns = config->useTns;
     hEncoder->config.aacObjectType = config->aacObjectType;
@@ -256,7 +251,7 @@
     hEncoder->config.copyright = libCopyright;
     hEncoder->config.mpegVersion = MPEG4;
     hEncoder->config.aacObjectType = LOW;
-    hEncoder->config.allowMidside = 1;
+    hEncoder->config.jointmode = JOINT_IS;
     hEncoder->config.useLfe = 1;
     hEncoder->config.useTns = 0;
     hEncoder->config.bitRate = 64000;
@@ -368,7 +363,7 @@
     unsigned int numChannels = hEncoder->numChannels;
     unsigned int useLfe = hEncoder->config.useLfe;
     unsigned int useTns = hEncoder->config.useTns;
-    unsigned int allowMidside = hEncoder->config.allowMidside;
+    unsigned int jointmode = hEncoder->config.jointmode;
     unsigned int bandWidth = hEncoder->config.bandWidth;
     unsigned int shortctl = hEncoder->config.shortctl;
     int maxqual = hEncoder->config.outputFormat ? MAXQUALADTS : MAXQUAL;
@@ -564,12 +559,8 @@
 		}
 	}
 
-    if (allowMidside)
-        MSEncode(coderInfo, channelInfo, hEncoder->freqBuff, numChannels,
-                 (double)hEncoder->aacquantCfg.quality/DEFQUAL);
-    else
-        MSEncode(coderInfo, channelInfo, hEncoder->freqBuff, numChannels,
-                 0.0);
+    AACstereo(coderInfo, channelInfo, hEncoder->freqBuff, numChannels,
+              (double)hEncoder->aacquantCfg.quality/DEFQUAL, jointmode);
 
 #ifdef DRM
     /* loop the quantization until the desired bit-rate is reached */
--- a/libfaac/huff2.c
+++ b/libfaac/huff2.c
@@ -95,9 +95,9 @@
     switch (bnum)
     {
 #ifdef DRM
-    case ZERO_HCB:
-    case INTENSITY_HCB:
-    case INTENSITY_HCB2:
+    case HCB_ZERO:
+    case HCB_INTENSITY:
+    case HCB_INTENSITY2:
         for(ofs = 0; ofs < len; ofs += 4)
         {
             coder->s[datacnt].data = 0;
@@ -241,7 +241,7 @@
             bits += blen;
         }
         break;
-    case ESC_HCB:
+    case HCB_ESC:
         for(ofs = 0; ofs < len; ofs += 2)
         {
             int x0, x1;
@@ -397,7 +397,7 @@
 
     if (maxq < 1)
     {
-        bookmin = ZERO_HCB;
+        bookmin = HCB_ZERO;
         lenmin = 0;
     }
     else if (maxq < 2)
@@ -422,7 +422,7 @@
     }
     else
     {
-        bookmin = ESC_HCB;
+        bookmin = HCB_ESC;
     }
 
 #ifdef DRM
@@ -431,7 +431,7 @@
     if (vcb11)
         bookmin = vcb11;
 #else
-    if (bookmin > ZERO_HCB)
+    if (bookmin > HCB_ZERO)
         huffcode(qs, len, bookmin, coder);
 #endif
     coder->book[coder->bandcnt] = bookmin;
@@ -522,7 +522,7 @@
     {
         int book = coder->book[cnt];
 
-        if ((book == INTENSITY_HCB) || (book== INTENSITY_HCB2))
+        if ((book == HCB_INTENSITY) || (book== HCB_INTENSITY2))
         {
             diff = coder->sf[cnt] - lastis;
             if (diff > 60)
--- a/libfaac/huff2.h
+++ b/libfaac/huff2.h
@@ -20,10 +20,11 @@
 #include "bitstream.h"
 
 enum {
-    ZERO_HCB = 0,
-    ESC_HCB = 11,
-    INTENSITY_HCB = 15,
-    INTENSITY_HCB2 = 14,
+    HCB_ZERO = 0,
+    HCB_ESC = 11,
+    HCB_INTENSITY2 = 14,
+    HCB_INTENSITY = 15,
+    HCB_NONE
 };
 
 int huffbook(CoderInfo *coderInfo,
--- a/libfaac/midside.c
+++ /dev/null
@@ -1,213 +1,0 @@
-/*
- * FAAC - Freeware Advanced Audio Coder
- * Copyright (C) 2003 Krzysztof Nikiel
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- */
-
-#include <math.h>
-#include "channels.h"
-#include "util.h"
-
-
-static void midside(CoderInfo *coder, ChannelInfo *channel,
-                    double *sl0, double *sr0, int *mscnt,
-                    int wstart, int wend,
-                    double thrmid, double thrside
-                   )
-{
-    int sfb;
-    int win;
-
-    for (sfb = 0; sfb < coder->sfbn; sfb++)
-    {
-        int ms = 0;
-        int l, start, end;
-        double sum, diff;
-        double enrgs, enrgd, enrgl, enrgr;
-
-        if (sfb < 1)
-            goto setms;
-
-        start = coder->sfb_offset[sfb];
-        end = coder->sfb_offset[sfb + 1];
-
-        enrgs = enrgd = enrgl = enrgr = 0.0;
-        for (win = wstart; win < wend; win++)
-        {
-            double *sl = sl0 + win * BLOCK_LEN_SHORT;
-            double *sr = sr0 + win * BLOCK_LEN_SHORT;
-
-            for (l = start; l < end; l++)
-            {
-                double lx = sl[l];
-                double rx = sr[l];
-
-                sum = 0.5 * (lx + rx);
-                diff = 0.5 * (lx - rx);
-
-                enrgs += sum * sum;
-                enrgd += diff * diff;
-                enrgl += lx * lx;
-                enrgr += rx * rx;
-            }
-        }
-
-        if ((min(enrgl, enrgr) * thrmid) >= max(enrgs, enrgd))
-        {
-            enum {PH_NONE, PH_IN, PH_OUT};
-            int phase = PH_NONE;
-
-            if ((enrgs * thrmid * 2.0) >= (enrgl + enrgr))
-            {
-                ms = 1;
-                phase = PH_IN;
-            }
-            else if ((enrgd * thrmid * 2.0) >= (enrgl + enrgr))
-            {
-                ms = 1;
-                phase = PH_OUT;
-            }
-
-            if (ms)
-            {
-                for (win = wstart; win < wend; win++)
-                {
-                    double *sl = sl0 + win * BLOCK_LEN_SHORT;
-                    double *sr = sr0 + win * BLOCK_LEN_SHORT;
-                    for (l = start; l < end; l++)
-                    {
-                        if (phase == PH_IN)
-                        {
-                            sum = sl[l] + sr[l];
-                            diff = 0;
-                        }
-                        else
-                        {
-                            sum = 0;
-                            diff = sl[l] - sr[l];
-                        }
-
-                        sl[l] = 0.5 * sum;
-                        sr[l] = 0.5 * diff;
-                    }
-                }
-            }
-        }
-
-        if (min(enrgl, enrgr) <= (thrside * max(enrgl, enrgr)))
-        {
-            for (win = wstart; win < wend; win++)
-            {
-                double *sl = sl0 + win * BLOCK_LEN_SHORT;
-                double *sr = sr0 + win * BLOCK_LEN_SHORT;
-                for (l = start; l < end; l++)
-                {
-                    if (enrgl < enrgr)
-                        sl[l] = 0.0;
-                    else
-                        sr[l] = 0.0;
-                }
-            }
-        }
-
-    setms:
-        channel->msInfo.ms_used[*mscnt] = ms;
-        (*mscnt)++;
-    }
-}
-
-
-void MSEncode(CoderInfo *coder,
-              ChannelInfo *channel,
-              double *s[MAX_CHANNELS],
-              int maxchan,
-              double quality)
-{
-    int chn;
-    int usems;
-    static const double thr075 = 1.09 /* ~0.75dB */ - 1.0;
-    static const double thrmax = 1.25 /* ~2dB */ - 1.0;
-    static const double sidemin = 0.1; /* -20dB */
-    static const double sidemax = 0.3; /* ~-10.5dB */
-    double thrmid, thrside;
-
-    if (quality > 0.01)
-    {
-        usems = 1;
-        thrmid = thr075 / quality;
-        if (thrmid > thrmax)
-            thrmid = thrmax;
-
-        thrside = sidemin / quality;
-        if (thrside > sidemax)
-            thrside = sidemax;
-    }
-    else
-    {
-        usems = 0;
-        thrmid = 0.0;
-        thrside = 0.0;
-    }
-    thrmid += 1.0;
-
-    // convert into energy
-    thrmid *= thrmid;
-    thrside *= thrside;
-
-    for (chn = 0; chn < maxchan; chn++)
-    {
-        int rch;
-        int cnt;
-        int group;
-        int mscnt = 0;
-        int start = 0;
-
-        if (!channel[chn].present)
-            continue;
-        if (!((channel[chn].cpe) && (channel[chn].ch_is_left)))
-            continue;
-
-        rch = channel[chn].paired_ch;
-
-        channel[chn].msInfo.is_present = 0;
-        channel[rch].msInfo.is_present = 0;
-
-        if (!usems)
-            continue;
-
-        if (coder[chn].block_type != coder[rch].block_type)
-            continue;
-        if (coder[chn].groups.n != coder[rch].groups.n)
-            continue;
-        for (cnt = 0; cnt < coder[chn].groups.n; cnt++)
-            if (coder[chn].groups.len[cnt] != coder[rch].groups.len[cnt])
-                goto skip;
-
-        channel[chn].common_window = 1;
-        channel[chn].msInfo.is_present = 1;
-        channel[rch].msInfo.is_present = 1;
-
-        for (group = 0; group < coder->groups.n; group++)
-        {
-            int end = start + coder->groups.len[group];
-            midside(coder + chn, channel + chn, s[chn], s[rch], &mscnt,
-                    start, end, thrmid, thrside);
-            start = end;
-        }
-        skip:;
-    }
-}
--- a/libfaac/midside.h
+++ /dev/null
@@ -1,39 +1,0 @@
-/*
- * FAAC - Freeware Advanced Audio Coder
- * Copyright (C) 2003 Krzysztof Nikiel
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
-
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * $Id: midside.h,v 1.1 2003/06/26 19:40:23 knik Exp $
- */
-
-#ifndef _MIDSIDE_H
-#define _MIDSIDE_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#include "coder.h"
-
-
-void MSEncode(CoderInfo *coderInfo, ChannelInfo *channelInfo, double *spectrum[MAX_CHANNELS],
-              unsigned int numberOfChannels, double quality);
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* _MIDSIDE_H */
--- a/libfaac/quantize.c
+++ b/libfaac/quantize.c
@@ -179,6 +179,17 @@
       const double *xr;
       int win;
 
+      if (coderInfo->book[coderInfo->bandcnt] != HCB_NONE)
+      {
+#if 0
+          int book = coderInfo->book[coderInfo->bandcnt];
+          if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2))
+              printf("book[%d]:%d\n",coderInfo->bandcnt, book);
+#endif
+          coderInfo->bandcnt++;
+          continue;
+      }
+
       start = coderInfo->sfb_offset[sb];
       end = coderInfo->sfb_offset[sb+1];
 
@@ -198,8 +209,12 @@
 
       if ((rmsx < NOISEFLOOR) || (!bandqual[sb]))
       {
-          coderInfo->book[coderInfo->bandcnt] = ZERO_HCB;
+#if 0
+          coderInfo->book[coderInfo->bandcnt] = HCB_ZERO;
           coderInfo->sf[coderInfo->bandcnt++] = 0;
+#else
+          coderInfo->book[coderInfo->bandcnt++] = HCB_ZERO;
+#endif
           continue;
       }
 
@@ -258,7 +273,7 @@
           xr += BLOCK_LEN_SHORT;
       }
       huffbook(coderInfo, xitab, gsize * end);
-      coderInfo->sf[coderInfo->bandcnt++] = SF_OFFSET - sfac;
+      coderInfo->sf[coderInfo->bandcnt++] += SF_OFFSET - sfac;
     }
 }
 
@@ -269,8 +284,10 @@
     double *gxr;
 
     coder->global_gain = 0;
+#if 0
     for (cnt = 0; cnt < coder->sfbn; cnt++)
-        coder->sf[cnt] = 0;
+        coder->sf[cnt] = SF_OFFSET;
+#endif
 
     coder->bandcnt = 0;
     coder->datacnt = 0;
@@ -299,7 +316,7 @@
             int book = coder->book[cnt];
             if (!book)
                 continue;
-            if ((book != INTENSITY_HCB) && (book != INTENSITY_HCB2))
+            if ((book != HCB_INTENSITY) && (book != HCB_INTENSITY2))
             {
                 coder->global_gain = coder->sf[cnt];
                 break;
@@ -312,7 +329,7 @@
         for (cnt = 0; cnt < coder->bandcnt; cnt++)
         {
             int book = coder->book[cnt];
-            if ((book == INTENSITY_HCB) || (book == INTENSITY_HCB2))
+            if ((book == HCB_INTENSITY) || (book == HCB_INTENSITY2))
             {
                 int diff = coder->sf[cnt] - lastis;
 
--- /dev/null
+++ b/libfaac/stereo.c
@@ -1,0 +1,366 @@
+/****************************************************************************
+    Intensity Stereo
+
+    Copyright (C) 2017 Krzysztof Nikiel
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+****************************************************************************/
+
+#include <math.h>
+#include "stereo.h"
+#include "huff2.h"
+
+
+static void stereo(CoderInfo *cl, CoderInfo *cr,
+                   double *sl0, double *sr0, int *sfcnt,
+                   int wstart, int wend, double phthr
+                  )
+{
+    int sfb;
+    int win;
+
+    if (!phthr)
+        return;
+
+    phthr = 1.0 / phthr;
+
+    for (sfb = 0; sfb < cl->sfbn; sfb++)
+    {
+        int l, start, end;
+        double sum, diff;
+        double enrgs, enrgd, enrgl, enrgr;
+        int hcb = HCB_NONE;
+        const double step = 10/1.50515;
+        double ethr;
+        double vfix, efix;
+
+#if 1
+        if (sfb < 1)
+        {
+            (*sfcnt)++;
+            continue;
+        }
+#endif
+
+        start = cl->sfb_offset[sfb];
+        end = cl->sfb_offset[sfb + 1];
+
+        enrgs = enrgd = enrgl = enrgr = 0.0;
+        for (win = wstart; win < wend; win++)
+        {
+            double *sl = sl0 + win * BLOCK_LEN_SHORT;
+            double *sr = sr0 + win * BLOCK_LEN_SHORT;
+
+            for (l = start; l < end; l++)
+            {
+                double lx = sl[l];
+                double rx = sr[l];
+
+                sum = lx + rx;
+                diff = lx - rx;
+
+                enrgs += sum * sum;
+                enrgd += diff * diff;
+                enrgl += lx * lx;
+                enrgr += rx * rx;
+            }
+        }
+
+        ethr = sqrt(enrgl) + sqrt(enrgr);
+        ethr *= ethr;
+        ethr *= phthr;
+        efix = enrgl + enrgr;
+        if (enrgs >= ethr)
+        {
+            hcb = HCB_INTENSITY;
+            vfix = sqrt(efix / enrgs);
+        }
+        else if (enrgd >= ethr)
+        {
+            hcb = HCB_INTENSITY2;
+            vfix = sqrt(efix / enrgd);
+        }
+
+        if (hcb != HCB_NONE)
+        {
+            int sf = lrint(log10(enrgl / efix) * step);
+            int pan = lrint(log10(enrgr/efix) * step) - sf;
+
+            if (pan > 30)
+            {
+                cl->book[*sfcnt] = HCB_ZERO;
+                (*sfcnt)++;
+                continue;
+            }
+            if (pan < -30)
+            {
+                cr->book[*sfcnt] = HCB_ZERO;
+                (*sfcnt)++;
+                continue;
+            }
+            cl->sf[*sfcnt] = sf;
+            cr->sf[*sfcnt] = -pan;
+            cr->book[*sfcnt] = hcb;
+
+            for (win = wstart; win < wend; win++)
+            {
+                double *sl = sl0 + win * BLOCK_LEN_SHORT;
+                double *sr = sr0 + win * BLOCK_LEN_SHORT;
+                for (l = start; l < end; l++)
+                {
+                    if (hcb == HCB_INTENSITY)
+                        sum = sl[l] + sr[l];
+                    else
+                        sum = sl[l] - sr[l];
+
+                    sl[l] = sum * vfix;
+                }
+            }
+        }
+        (*sfcnt)++;
+    }
+}
+
+static void midside(CoderInfo *coder, ChannelInfo *channel,
+                    double *sl0, double *sr0, int *sfcnt,
+                    int wstart, int wend,
+                    double thrmid, double thrside
+                   )
+{
+    int sfb;
+    int win;
+
+    for (sfb = 0; sfb < coder->sfbn; sfb++)
+    {
+        int ms = 0;
+        int l, start, end;
+        double sum, diff;
+        double enrgs, enrgd, enrgl, enrgr;
+
+        if (sfb < 1)
+            goto setms;
+
+        start = coder->sfb_offset[sfb];
+        end = coder->sfb_offset[sfb + 1];
+
+        enrgs = enrgd = enrgl = enrgr = 0.0;
+        for (win = wstart; win < wend; win++)
+        {
+            double *sl = sl0 + win * BLOCK_LEN_SHORT;
+            double *sr = sr0 + win * BLOCK_LEN_SHORT;
+
+            for (l = start; l < end; l++)
+            {
+                double lx = sl[l];
+                double rx = sr[l];
+
+                sum = 0.5 * (lx + rx);
+                diff = 0.5 * (lx - rx);
+
+                enrgs += sum * sum;
+                enrgd += diff * diff;
+                enrgl += lx * lx;
+                enrgr += rx * rx;
+            }
+        }
+
+        if ((min(enrgl, enrgr) * thrmid) >= max(enrgs, enrgd))
+        {
+            enum {PH_NONE, PH_IN, PH_OUT};
+            int phase = PH_NONE;
+
+            if ((enrgs * thrmid * 2.0) >= (enrgl + enrgr))
+            {
+                ms = 1;
+                phase = PH_IN;
+            }
+            else if ((enrgd * thrmid * 2.0) >= (enrgl + enrgr))
+            {
+                ms = 1;
+                phase = PH_OUT;
+            }
+
+            if (ms)
+            {
+                for (win = wstart; win < wend; win++)
+                {
+                    double *sl = sl0 + win * BLOCK_LEN_SHORT;
+                    double *sr = sr0 + win * BLOCK_LEN_SHORT;
+                    for (l = start; l < end; l++)
+                    {
+                        if (phase == PH_IN)
+                        {
+                            sum = sl[l] + sr[l];
+                            diff = 0;
+                        }
+                        else
+                        {
+                            sum = 0;
+                            diff = sl[l] - sr[l];
+                        }
+
+                        sl[l] = 0.5 * sum;
+                        sr[l] = 0.5 * diff;
+                    }
+                }
+            }
+        }
+
+        if (min(enrgl, enrgr) <= (thrside * max(enrgl, enrgr)))
+        {
+            for (win = wstart; win < wend; win++)
+            {
+                double *sl = sl0 + win * BLOCK_LEN_SHORT;
+                double *sr = sr0 + win * BLOCK_LEN_SHORT;
+                for (l = start; l < end; l++)
+                {
+                    if (enrgl < enrgr)
+                        sl[l] = 0.0;
+                    else
+                        sr[l] = 0.0;
+                }
+            }
+        }
+
+    setms:
+        channel->msInfo.ms_used[*sfcnt] = ms;
+        (*sfcnt)++;
+    }
+}
+
+
+void AACstereo(CoderInfo *coder,
+               ChannelInfo *channel,
+               double *s[MAX_CHANNELS],
+               int maxchan,
+               double quality,
+               int mode
+              )
+{
+    int chn;
+    static const double thr075 = 1.09 /* ~0.75dB */ - 1.0;
+    static const double thrmax = 1.25 /* ~2dB */ - 1.0;
+    static const double sidemin = 0.1; /* -20dB */
+    static const double sidemax = 0.3; /* ~-10.5dB */
+    static const double isthrmax = sqrt(2) - 1.0;
+    double thrmid, thrside;
+    double isthr;
+
+    thrmid = 1.0;
+    thrside = 0.0;
+    isthr = 1.0;
+
+    switch (mode)
+    {
+    case JOINT_MS:
+        thrmid = thr075 / quality;
+        if (thrmid > thrmax)
+            thrmid = thrmax;
+
+        thrside = sidemin / quality;
+        if (thrside > sidemax)
+            thrside = sidemax;
+
+        thrmid += 1.0;
+        break;
+    case JOINT_IS:
+        isthr = 0.18 / (quality * quality);
+        if (isthr > isthrmax)
+            isthr = isthrmax;
+
+        isthr += 1.0;
+        break;
+    }
+
+    // convert into energy
+    thrmid *= thrmid;
+    thrside *= thrside;
+    isthr *= isthr;
+
+    for (chn = 0; chn < maxchan; chn++)
+    {
+        int group;
+        int bookcnt = 0;
+        CoderInfo *cp = coder + chn;
+
+        if (!channel[chn].present)
+            continue;
+
+        for (group = 0; group < cp->groups.n; group++)
+        {
+            int band;
+            for (band = 0; band < cp->sfbn; band++)
+            {
+                cp->book[bookcnt] = HCB_NONE;
+                cp->sf[bookcnt] = 0;
+                bookcnt++;
+            }
+        }
+    }
+    for (chn = 0; chn < maxchan; chn++)
+    {
+        int rch;
+        int cnt;
+        int group;
+        int sfcnt = 0;
+        int start = 0;
+
+        if (!channel[chn].present)
+            continue;
+        if (!((channel[chn].cpe) && (channel[chn].ch_is_left)))
+            continue;
+
+        rch = channel[chn].paired_ch;
+
+        channel[chn].common_window = 0;
+        channel[chn].msInfo.is_present = 0;
+        channel[rch].msInfo.is_present = 0;
+
+        if (coder[chn].block_type != coder[rch].block_type)
+            continue;
+        if (coder[chn].groups.n != coder[rch].groups.n)
+            continue;
+
+        channel[chn].common_window = 1;
+        for (cnt = 0; cnt < coder[chn].groups.n; cnt++)
+            if (coder[chn].groups.len[cnt] != coder[rch].groups.len[cnt])
+            {
+                channel[chn].common_window = 0;
+                goto skip;
+            }
+
+        if (mode == JOINT_MS)
+        {
+            channel[chn].common_window = 1;
+            channel[chn].msInfo.is_present = 1;
+            channel[rch].msInfo.is_present = 1;
+        }
+
+        for (group = 0; group < coder->groups.n; group++)
+        {
+            int end = start + coder->groups.len[group];
+            switch(mode) {
+            case JOINT_MS:
+                midside(coder + chn, channel + chn, s[chn], s[rch], &sfcnt,
+                        start, end, thrmid, thrside);
+                break;
+            case JOINT_IS:
+                stereo(coder + chn, coder + rch, s[chn], s[rch], &sfcnt, start, end, isthr);
+                break;
+            }
+            start = end;
+        }
+        skip:;
+    }
+}
--- /dev/null
+++ b/libfaac/stereo.h
@@ -1,0 +1,29 @@
+/****************************************************************************
+    Intensity Stereo
+
+    Copyright (C) 2017 Krzysztof Nikiel
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+****************************************************************************/
+
+#include "channels.h"
+#include "util.h"
+
+void AACstereo(CoderInfo *coder,
+               ChannelInfo *channel,
+               double *s[MAX_CHANNELS],
+               int maxchan,
+               double quality,
+               int mode
+              );
--- a/libfaac/version.h
+++ /dev/null
@@ -1,8 +1,0 @@
-#ifndef _VERSION_H_
-#define _VERSION_H_
-
-#define FAAC_RELEASE 1
-
-#define FAAC_VERSION PACKAGE_VERSION
-
-#endif