ref: 125aebf1fcdcb5cb042fa6a46e7415b6ec227adf
parent: 71b835a6126b922bd62ba448ad0d2bb13562ca2c
author: Krzysztof Nikiel <knik@users.sourceforge.net>
date: Sun Aug 13 07:56:33 EDT 2017
renamed: psych -> blockswitch
--- a/libfaac/Makefile.am
+++ b/libfaac/Makefile.am
@@ -1,5 +1,5 @@
-common_SOURCES = aacquant.c bitstream.c fft.c frame.c midside.c psychkni.c util.c backpred.c channels.c filtbank.c huffman.c ltp.c tns.c
-common_INCLUDES = aacquant.h channels.h filtbank.h hufftab.h psych.h backpred.h coder.h frame.h midside.h tns.h bitstream.h fft.h huffman.h ltp.h util.h
+common_SOURCES = aacquant.c bitstream.c fft.c frame.c midside.c blockswitch.c util.c backpred.c channels.c filtbank.c huffman.c ltp.c tns.c
+common_INCLUDES = aacquant.h channels.h filtbank.h hufftab.h blockswitch.h backpred.h coder.h frame.h midside.h tns.h bitstream.h fft.h huffman.h ltp.h util.h
common_LIBADD = -lm
common_CFLAGS = -fvisibility=hidden
--- /dev/null
+++ b/libfaac/blockswitch.c
@@ -1,0 +1,452 @@
+/*
+ * FAAC - Freeware Advanced Audio Coder
+ * Copyright (C) 2002 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: psychkni.c,v 1.19 2012/03/01 18:34:17 knik Exp $
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "blockswitch.h"
+#include "coder.h"
+#include "fft.h"
+#include "util.h"
+#include <faac.h>
+
+typedef float psyfloat;
+
+typedef struct
+{
+ /* bandwidth */
+ int bandS;
+ int lastband;
+
+ /* band volumes */
+ psyfloat *engPrev[8];
+ psyfloat *eng[8];
+ psyfloat *engNext[8];
+ psyfloat *engNext2[8];
+}
+psydata_t;
+
+
+static void Hann(GlobalPsyInfo * gpsyInfo, double *inSamples, int size)
+{
+ int i;
+
+ /* Applying Hann window */
+ if (size == BLOCK_LEN_LONG * 2)
+ {
+ for (i = 0; i < size; i++)
+ inSamples[i] *= gpsyInfo->hannWindow[i];
+ }
+ else
+ {
+ for (i = 0; i < size; i++)
+ inSamples[i] *= gpsyInfo->hannWindowS[i];
+ }
+}
+
+static void PsyCheckShort(PsyInfo * psyInfo)
+{
+ enum {PREVS = 2, NEXTS = 2};
+ psydata_t *psydata = psyInfo->data;
+ int lastband = psydata->lastband;
+ int firstband = 1;
+ int sfb, win;
+ psyfloat *lasteng;
+
+ psyInfo->block_type = ONLY_LONG_WINDOW;
+
+ lasteng = NULL;
+ for (win = 0; win < PREVS + 8 + NEXTS; win++)
+ {
+ psyfloat *eng;
+
+ if (win < PREVS)
+ eng = psydata->engPrev[win + 8 - PREVS];
+ else if (win < (PREVS + 8))
+ eng = psydata->eng[win - PREVS];
+ else
+ eng = psydata->engNext[win - PREVS - 8];
+
+ if (lasteng)
+ {
+ double toteng = 0.0;
+ double volchg = 0.0;
+
+ for (sfb = firstband; sfb < lastband; sfb++)
+ {
+ toteng += (eng[sfb] < lasteng[sfb]) ? eng[sfb] : lasteng[sfb];
+ volchg += fabs(eng[sfb] - lasteng[sfb]);
+ }
+
+ if ((volchg / toteng) > 1.5)
+ {
+ psyInfo->block_type = ONLY_SHORT_WINDOW;
+ break;
+ }
+ }
+ lasteng = eng;
+ }
+
+#if 0
+ {
+ static int cnt = 0;
+ static int total = 0, shorts = 0;
+
+ if (!(cnt++ & 0x3f))
+ {
+ total++;
+ if (psyInfo->block_type == ONLY_SHORT_WINDOW)
+ shorts++;
+
+ printf("shorts: %d %%\n", 100*shorts/total);
+ }
+ }
+#endif
+}
+
+static void PsyInit(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, unsigned int numChannels,
+ unsigned int sampleRate, int *cb_width_long, int num_cb_long,
+ int *cb_width_short, int num_cb_short)
+{
+ unsigned int channel;
+ int i, j, size;
+
+ gpsyInfo->hannWindow =
+ (double *) AllocMemory(2 * BLOCK_LEN_LONG * sizeof(double));
+ gpsyInfo->hannWindowS =
+ (double *) AllocMemory(2 * BLOCK_LEN_SHORT * sizeof(double));
+
+ for (i = 0; i < BLOCK_LEN_LONG * 2; i++)
+ gpsyInfo->hannWindow[i] = 0.5 * (1 - cos(2.0 * M_PI * (i + 0.5) /
+ (BLOCK_LEN_LONG * 2)));
+ for (i = 0; i < BLOCK_LEN_SHORT * 2; i++)
+ gpsyInfo->hannWindowS[i] = 0.5 * (1 - cos(2.0 * M_PI * (i + 0.5) /
+ (BLOCK_LEN_SHORT * 2)));
+ gpsyInfo->sampleRate = (double) sampleRate;
+
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ psydata_t *psydata = AllocMemory(sizeof(psydata_t));
+ psyInfo[channel].data = psydata;
+ }
+
+ size = BLOCK_LEN_LONG;
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ psyInfo[channel].size = size;
+
+ psyInfo[channel].prevSamples =
+ (double *) AllocMemory(size * sizeof(double));
+ memset(psyInfo[channel].prevSamples, 0, size * sizeof(double));
+ }
+
+ size = BLOCK_LEN_SHORT;
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ psydata_t *psydata = psyInfo[channel].data;
+
+ psyInfo[channel].sizeS = size;
+
+ for (j = 0; j < 8; j++)
+ {
+ psydata->engPrev[j] =
+ (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
+ memset(psydata->engPrev[j], 0, NSFB_SHORT * sizeof(psyfloat));
+ psydata->eng[j] =
+ (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
+ memset(psydata->eng[j], 0, NSFB_SHORT * sizeof(psyfloat));
+ psydata->engNext[j] =
+ (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
+ memset(psydata->engNext[j], 0, NSFB_SHORT * sizeof(psyfloat));
+ psydata->engNext2[j] =
+ (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
+ memset(psydata->engNext2[j], 0, NSFB_SHORT * sizeof(psyfloat));
+ }
+ }
+}
+
+static void PsyEnd(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, unsigned int numChannels)
+{
+ unsigned int channel;
+ int j;
+
+ if (gpsyInfo->hannWindow)
+ FreeMemory(gpsyInfo->hannWindow);
+ if (gpsyInfo->hannWindowS)
+ FreeMemory(gpsyInfo->hannWindowS);
+
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ if (psyInfo[channel].prevSamples)
+ FreeMemory(psyInfo[channel].prevSamples);
+ }
+
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ psydata_t *psydata = psyInfo[channel].data;
+
+ for (j = 0; j < 8; j++)
+ {
+ if (psydata->engPrev[j])
+ FreeMemory(psydata->engPrev[j]);
+ if (psydata->eng[j])
+ FreeMemory(psydata->eng[j]);
+ if (psydata->engNext[j])
+ FreeMemory(psydata->engNext[j]);
+ if (psydata->engNext2[j])
+ FreeMemory(psydata->engNext2[j]);
+ }
+ }
+
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ if (psyInfo[channel].data)
+ FreeMemory(psyInfo[channel].data);
+ }
+}
+
+/* Do psychoacoustical analysis */
+static void PsyCalculate(ChannelInfo * channelInfo, GlobalPsyInfo * gpsyInfo,
+ PsyInfo * psyInfo, int *cb_width_long, int
+ num_cb_long, int *cb_width_short,
+ int num_cb_short, unsigned int numChannels)
+{
+ unsigned int channel;
+
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ if (channelInfo[channel].present)
+ {
+
+ if (channelInfo[channel].cpe &&
+ channelInfo[channel].ch_is_left)
+ { /* CPE */
+
+ int leftChan = channel;
+ int rightChan = channelInfo[channel].paired_ch;
+
+ PsyCheckShort(&psyInfo[leftChan]);
+ PsyCheckShort(&psyInfo[rightChan]);
+ }
+ else if (!channelInfo[channel].cpe &&
+ channelInfo[channel].lfe)
+ { /* LFE */
+ // Only set block type and it should be OK
+ psyInfo[channel].block_type = ONLY_LONG_WINDOW;
+ }
+ else if (!channelInfo[channel].cpe)
+ { /* SCE */
+ PsyCheckShort(&psyInfo[channel]);
+ }
+ }
+ }
+}
+
+// imported from filtbank.c
+static void mdct( FFT_Tables *fft_tables, double *data, int N )
+{
+ double *xi, *xr;
+ double tempr, tempi, c, s, cold, cfreq, sfreq; /* temps for pre and post twiddle */
+ double freq = 2.0 * M_PI / N;
+ double cosfreq8, sinfreq8;
+ int i, n;
+
+ xi = (double*)AllocMemory((N >> 2)*sizeof(double));
+ xr = (double*)AllocMemory((N >> 2)*sizeof(double));
+
+ /* prepare for recurrence relation in pre-twiddle */
+ cfreq = cos (freq);
+ sfreq = sin (freq);
+ cosfreq8 = cos (freq * 0.125);
+ sinfreq8 = sin (freq * 0.125);
+ c = cosfreq8;
+ s = sinfreq8;
+
+ for (i = 0; i < (N >> 2); i++) {
+ /* calculate real and imaginary parts of g(n) or G(p) */
+ n = 2 * i;
+
+ if (n < (N >> 2))
+ tempr = data [(N>>2) + (N>>1) - 1 - n] + data [N - (N>>2) + n];
+ else
+ tempr = data [(N>>2) + (N>>1) - 1 - n] - data [-(N>>2) + n];
+
+ if (n < (N >> 2))
+ tempi = data [(N>>2) + n] - data [(N>>2) - 1 - n];
+ else
+ tempi = data [(N>>2) + n] + data [N + (N>>2) - 1 - n];
+
+ /* calculate pre-twiddled FFT input */
+ xr[i] = tempr * c + tempi * s;
+ xi[i] = tempi * c - tempr * s;
+
+ /* use recurrence to prepare cosine and sine for next value of i */
+ cold = c;
+ c = c * cfreq - s * sfreq;
+ s = s * cfreq + cold * sfreq;
+ }
+
+ /* Perform in-place complex FFT of length N/4 */
+ switch (N) {
+ case BLOCK_LEN_SHORT * 2:
+ fft( fft_tables, xr, xi, 6);
+ break;
+ case BLOCK_LEN_LONG * 2:
+ fft( fft_tables, xr, xi, 9);
+ }
+
+ /* prepare for recurrence relations in post-twiddle */
+ c = cosfreq8;
+ s = sinfreq8;
+
+ /* post-twiddle FFT output and then get output data */
+ for (i = 0; i < (N >> 2); i++) {
+ /* get post-twiddled FFT output */
+ tempr = 2. * (xr[i] * c + xi[i] * s);
+ tempi = 2. * (xi[i] * c - xr[i] * s);
+
+ /* fill in output values */
+ data [2 * i] = -tempr; /* first half even */
+ data [(N >> 1) - 1 - 2 * i] = tempi; /* first half odd */
+ data [(N >> 1) + 2 * i] = -tempi; /* second half even */
+ data [N - 1 - 2 * i] = tempr; /* second half odd */
+
+ /* use recurrence to prepare cosine and sine for next value of i */
+ cold = c;
+ c = c * cfreq - s * sfreq;
+ s = s * cfreq + cold * sfreq;
+ }
+
+ if (xr) FreeMemory(xr);
+ if (xi) FreeMemory(xi);
+}
+
+
+static void PsyBufferUpdate( FFT_Tables *fft_tables, GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo,
+ double *newSamples, unsigned int bandwidth,
+ int *cb_width_short, int num_cb_short)
+{
+ int win;
+ double transBuff[2 * BLOCK_LEN_LONG];
+ double transBuffS[2 * BLOCK_LEN_SHORT];
+ psydata_t *psydata = psyInfo->data;
+ psyfloat *tmp;
+ int sfb;
+
+ psydata->bandS = psyInfo->sizeS * bandwidth * 2 / gpsyInfo->sampleRate;
+
+ memcpy(transBuff, psyInfo->prevSamples, psyInfo->size * sizeof(double));
+ memcpy(transBuff + psyInfo->size, newSamples, psyInfo->size * sizeof(double));
+
+ for (win = 0; win < 8; win++)
+ {
+ int first = 0;
+ int last = 0;
+
+ memcpy(transBuffS, transBuff + (win * BLOCK_LEN_SHORT) + (BLOCK_LEN_LONG - BLOCK_LEN_SHORT) / 2,
+ 2 * psyInfo->sizeS * sizeof(double));
+
+ Hann(gpsyInfo, transBuffS, 2 * psyInfo->sizeS);
+ mdct( fft_tables, transBuffS, 2 * psyInfo->sizeS);
+
+ // shift bufs
+ tmp = psydata->engPrev[win];
+ psydata->engPrev[win] = psydata->eng[win];
+ psydata->eng[win] = psydata->engNext[win];
+ psydata->engNext[win] = psydata->engNext2[win];
+ psydata->engNext2[win] = tmp;
+
+ for (sfb = 0; sfb < num_cb_short; sfb++)
+ {
+ double e;
+ int l;
+
+ first = last;
+ last = first + cb_width_short[sfb];
+
+ if (first < 1)
+ first = 1;
+
+ if (first >= psydata->bandS) // band out of range
+ break;
+
+ e = 0.0;
+ for (l = first; l < last; l++)
+ e += transBuffS[l] * transBuffS[l];
+
+ psydata->engNext2[win][sfb] = e;
+ }
+ psydata->lastband = sfb;
+ for (; sfb < num_cb_short; sfb++)
+ {
+ psydata->engNext2[win][sfb] = 0;
+ }
+ }
+
+ memcpy(psyInfo->prevSamples, newSamples, psyInfo->size * sizeof(double));
+}
+
+static void BlockSwitch(CoderInfo * coderInfo, PsyInfo * psyInfo, unsigned int numChannels)
+{
+ unsigned int channel;
+ int desire = ONLY_LONG_WINDOW;
+
+ /* Use the same block type for all channels
+ If there is 1 channel that wants a short block,
+ use a short block on all channels.
+ */
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ if (psyInfo[channel].block_type == ONLY_SHORT_WINDOW)
+ desire = ONLY_SHORT_WINDOW;
+ }
+
+ for (channel = 0; channel < numChannels; channel++)
+ {
+ int lasttype = coderInfo[channel].block_type;
+
+ if (desire == ONLY_SHORT_WINDOW
+ || coderInfo[channel].desired_block_type == ONLY_SHORT_WINDOW)
+ {
+ if (lasttype == ONLY_LONG_WINDOW || lasttype == SHORT_LONG_WINDOW)
+ coderInfo[channel].block_type = LONG_SHORT_WINDOW;
+ else
+ coderInfo[channel].block_type = ONLY_SHORT_WINDOW;
+ }
+ else
+ {
+ if (lasttype == ONLY_SHORT_WINDOW || lasttype == LONG_SHORT_WINDOW)
+ coderInfo[channel].block_type = SHORT_LONG_WINDOW;
+ else
+ coderInfo[channel].block_type = ONLY_LONG_WINDOW;
+ }
+ coderInfo[channel].desired_block_type = desire;
+ }
+}
+
+psymodel_t psymodel2 =
+{
+ PsyInit,
+ PsyEnd,
+ PsyCalculate,
+ PsyBufferUpdate,
+ BlockSwitch
+};
--- /dev/null
+++ b/libfaac/blockswitch.h
@@ -1,0 +1,84 @@
+/*
+ * FAAC - Freeware Advanced Audio Coder
+ * Copyright (C) 2001 Menno Bakker
+ *
+ * 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: psych.h,v 1.15 2009/06/05 16:32:15 menno Exp $
+ */
+
+#ifndef PSYCH_H
+#define PSYCH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#include "coder.h"
+#include "channels.h"
+#include "fft.h"
+
+typedef struct {
+ int size;
+ int sizeS;
+
+ /* Previous input samples */
+ double *prevSamples;
+
+ int block_type;
+
+ void *data;
+} PsyInfo;
+
+typedef struct {
+ double sampleRate;
+
+ /* Hann window */
+ double *hannWindow;
+ double *hannWindowS;
+
+ void *data;
+} GlobalPsyInfo;
+
+typedef struct
+{
+void (*PsyInit) (GlobalPsyInfo *gpsyInfo, PsyInfo *psyInfo,
+ unsigned int numChannels, unsigned int sampleRate,
+ int *cb_width_long, int num_cb_long,
+ int *cb_width_short, int num_cb_short);
+void (*PsyEnd) (GlobalPsyInfo *gpsyInfo, PsyInfo *psyInfo,
+ unsigned int numChannels);
+void (*PsyCalculate) (ChannelInfo *channelInfo, GlobalPsyInfo *gpsyInfo,
+ PsyInfo *psyInfo, int *cb_width_long, int num_cb_long,
+ int *cb_width_short, int num_cb_short,
+ unsigned int numChannels);
+void (*PsyBufferUpdate) ( FFT_Tables *fft_tables, GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo,
+ double *newSamples, unsigned int bandwidth,
+ int *cb_width_short, int num_cb_short);
+void (*BlockSwitch) (CoderInfo *coderInfo, PsyInfo *psyInfo,
+ unsigned int numChannels);
+} psymodel_t;
+
+extern psymodel_t psymodel2;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* PSYCH_H */
\ No newline at end of file
--- a/libfaac/frame.c
+++ b/libfaac/frame.c
@@ -41,7 +41,6 @@
#include "aacquant.h"
#include "util.h"
#include "huffman.h"
-#include "psych.h"
#include "tns.h"
#include "ltp.h"
#include "backpred.h"
--- a/libfaac/frame.h
+++ b/libfaac/frame.h
@@ -48,7 +48,7 @@
#include "coder.h"
#include "channels.h"
-#include "psych.h"
+#include "blockswitch.h"
#include "aacquant.h"
#include "fft.h"
--- a/libfaac/psych.h
+++ /dev/null
@@ -1,84 +1,0 @@
-/*
- * FAAC - Freeware Advanced Audio Coder
- * Copyright (C) 2001 Menno Bakker
- *
- * 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: psych.h,v 1.15 2009/06/05 16:32:15 menno Exp $
- */
-
-#ifndef PSYCH_H
-#define PSYCH_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-#ifndef M_PI
-#define M_PI 3.14159265358979323846
-#endif
-
-#include "coder.h"
-#include "channels.h"
-#include "fft.h"
-
-typedef struct {
- int size;
- int sizeS;
-
- /* Previous input samples */
- double *prevSamples;
-
- int block_type;
-
- void *data;
-} PsyInfo;
-
-typedef struct {
- double sampleRate;
-
- /* Hann window */
- double *hannWindow;
- double *hannWindowS;
-
- void *data;
-} GlobalPsyInfo;
-
-typedef struct
-{
-void (*PsyInit) (GlobalPsyInfo *gpsyInfo, PsyInfo *psyInfo,
- unsigned int numChannels, unsigned int sampleRate,
- int *cb_width_long, int num_cb_long,
- int *cb_width_short, int num_cb_short);
-void (*PsyEnd) (GlobalPsyInfo *gpsyInfo, PsyInfo *psyInfo,
- unsigned int numChannels);
-void (*PsyCalculate) (ChannelInfo *channelInfo, GlobalPsyInfo *gpsyInfo,
- PsyInfo *psyInfo, int *cb_width_long, int num_cb_long,
- int *cb_width_short, int num_cb_short,
- unsigned int numChannels);
-void (*PsyBufferUpdate) ( FFT_Tables *fft_tables, GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo,
- double *newSamples, unsigned int bandwidth,
- int *cb_width_short, int num_cb_short);
-void (*BlockSwitch) (CoderInfo *coderInfo, PsyInfo *psyInfo,
- unsigned int numChannels);
-} psymodel_t;
-
-extern psymodel_t psymodel2;
-
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* PSYCH_H */
\ No newline at end of file
--- a/libfaac/psychkni.c
+++ /dev/null
@@ -1,452 +1,0 @@
-/*
- * FAAC - Freeware Advanced Audio Coder
- * Copyright (C) 2002 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: psychkni.c,v 1.19 2012/03/01 18:34:17 knik Exp $
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-
-#include "psych.h"
-#include "coder.h"
-#include "fft.h"
-#include "util.h"
-#include <faac.h>
-
-typedef float psyfloat;
-
-typedef struct
-{
- /* bandwidth */
- int bandS;
- int lastband;
-
- /* band volumes */
- psyfloat *engPrev[8];
- psyfloat *eng[8];
- psyfloat *engNext[8];
- psyfloat *engNext2[8];
-}
-psydata_t;
-
-
-static void Hann(GlobalPsyInfo * gpsyInfo, double *inSamples, int size)
-{
- int i;
-
- /* Applying Hann window */
- if (size == BLOCK_LEN_LONG * 2)
- {
- for (i = 0; i < size; i++)
- inSamples[i] *= gpsyInfo->hannWindow[i];
- }
- else
- {
- for (i = 0; i < size; i++)
- inSamples[i] *= gpsyInfo->hannWindowS[i];
- }
-}
-
-static void PsyCheckShort(PsyInfo * psyInfo)
-{
- enum {PREVS = 2, NEXTS = 2};
- psydata_t *psydata = psyInfo->data;
- int lastband = psydata->lastband;
- int firstband = 1;
- int sfb, win;
- psyfloat *lasteng;
-
- psyInfo->block_type = ONLY_LONG_WINDOW;
-
- lasteng = NULL;
- for (win = 0; win < PREVS + 8 + NEXTS; win++)
- {
- psyfloat *eng;
-
- if (win < PREVS)
- eng = psydata->engPrev[win + 8 - PREVS];
- else if (win < (PREVS + 8))
- eng = psydata->eng[win - PREVS];
- else
- eng = psydata->engNext[win - PREVS - 8];
-
- if (lasteng)
- {
- double toteng = 0.0;
- double volchg = 0.0;
-
- for (sfb = firstband; sfb < lastband; sfb++)
- {
- toteng += (eng[sfb] < lasteng[sfb]) ? eng[sfb] : lasteng[sfb];
- volchg += fabs(eng[sfb] - lasteng[sfb]);
- }
-
- if ((volchg / toteng) > 1.5)
- {
- psyInfo->block_type = ONLY_SHORT_WINDOW;
- break;
- }
- }
- lasteng = eng;
- }
-
-#if 0
- {
- static int cnt = 0;
- static int total = 0, shorts = 0;
-
- if (!(cnt++ & 0x3f))
- {
- total++;
- if (psyInfo->block_type == ONLY_SHORT_WINDOW)
- shorts++;
-
- printf("shorts: %d %%\n", 100*shorts/total);
- }
- }
-#endif
-}
-
-static void PsyInit(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, unsigned int numChannels,
- unsigned int sampleRate, int *cb_width_long, int num_cb_long,
- int *cb_width_short, int num_cb_short)
-{
- unsigned int channel;
- int i, j, size;
-
- gpsyInfo->hannWindow =
- (double *) AllocMemory(2 * BLOCK_LEN_LONG * sizeof(double));
- gpsyInfo->hannWindowS =
- (double *) AllocMemory(2 * BLOCK_LEN_SHORT * sizeof(double));
-
- for (i = 0; i < BLOCK_LEN_LONG * 2; i++)
- gpsyInfo->hannWindow[i] = 0.5 * (1 - cos(2.0 * M_PI * (i + 0.5) /
- (BLOCK_LEN_LONG * 2)));
- for (i = 0; i < BLOCK_LEN_SHORT * 2; i++)
- gpsyInfo->hannWindowS[i] = 0.5 * (1 - cos(2.0 * M_PI * (i + 0.5) /
- (BLOCK_LEN_SHORT * 2)));
- gpsyInfo->sampleRate = (double) sampleRate;
-
- for (channel = 0; channel < numChannels; channel++)
- {
- psydata_t *psydata = AllocMemory(sizeof(psydata_t));
- psyInfo[channel].data = psydata;
- }
-
- size = BLOCK_LEN_LONG;
- for (channel = 0; channel < numChannels; channel++)
- {
- psyInfo[channel].size = size;
-
- psyInfo[channel].prevSamples =
- (double *) AllocMemory(size * sizeof(double));
- memset(psyInfo[channel].prevSamples, 0, size * sizeof(double));
- }
-
- size = BLOCK_LEN_SHORT;
- for (channel = 0; channel < numChannels; channel++)
- {
- psydata_t *psydata = psyInfo[channel].data;
-
- psyInfo[channel].sizeS = size;
-
- for (j = 0; j < 8; j++)
- {
- psydata->engPrev[j] =
- (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
- memset(psydata->engPrev[j], 0, NSFB_SHORT * sizeof(psyfloat));
- psydata->eng[j] =
- (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
- memset(psydata->eng[j], 0, NSFB_SHORT * sizeof(psyfloat));
- psydata->engNext[j] =
- (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
- memset(psydata->engNext[j], 0, NSFB_SHORT * sizeof(psyfloat));
- psydata->engNext2[j] =
- (psyfloat *) AllocMemory(NSFB_SHORT * sizeof(psyfloat));
- memset(psydata->engNext2[j], 0, NSFB_SHORT * sizeof(psyfloat));
- }
- }
-}
-
-static void PsyEnd(GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo, unsigned int numChannels)
-{
- unsigned int channel;
- int j;
-
- if (gpsyInfo->hannWindow)
- FreeMemory(gpsyInfo->hannWindow);
- if (gpsyInfo->hannWindowS)
- FreeMemory(gpsyInfo->hannWindowS);
-
- for (channel = 0; channel < numChannels; channel++)
- {
- if (psyInfo[channel].prevSamples)
- FreeMemory(psyInfo[channel].prevSamples);
- }
-
- for (channel = 0; channel < numChannels; channel++)
- {
- psydata_t *psydata = psyInfo[channel].data;
-
- for (j = 0; j < 8; j++)
- {
- if (psydata->engPrev[j])
- FreeMemory(psydata->engPrev[j]);
- if (psydata->eng[j])
- FreeMemory(psydata->eng[j]);
- if (psydata->engNext[j])
- FreeMemory(psydata->engNext[j]);
- if (psydata->engNext2[j])
- FreeMemory(psydata->engNext2[j]);
- }
- }
-
- for (channel = 0; channel < numChannels; channel++)
- {
- if (psyInfo[channel].data)
- FreeMemory(psyInfo[channel].data);
- }
-}
-
-/* Do psychoacoustical analysis */
-static void PsyCalculate(ChannelInfo * channelInfo, GlobalPsyInfo * gpsyInfo,
- PsyInfo * psyInfo, int *cb_width_long, int
- num_cb_long, int *cb_width_short,
- int num_cb_short, unsigned int numChannels)
-{
- unsigned int channel;
-
- for (channel = 0; channel < numChannels; channel++)
- {
- if (channelInfo[channel].present)
- {
-
- if (channelInfo[channel].cpe &&
- channelInfo[channel].ch_is_left)
- { /* CPE */
-
- int leftChan = channel;
- int rightChan = channelInfo[channel].paired_ch;
-
- PsyCheckShort(&psyInfo[leftChan]);
- PsyCheckShort(&psyInfo[rightChan]);
- }
- else if (!channelInfo[channel].cpe &&
- channelInfo[channel].lfe)
- { /* LFE */
- // Only set block type and it should be OK
- psyInfo[channel].block_type = ONLY_LONG_WINDOW;
- }
- else if (!channelInfo[channel].cpe)
- { /* SCE */
- PsyCheckShort(&psyInfo[channel]);
- }
- }
- }
-}
-
-// imported from filtbank.c
-static void mdct( FFT_Tables *fft_tables, double *data, int N )
-{
- double *xi, *xr;
- double tempr, tempi, c, s, cold, cfreq, sfreq; /* temps for pre and post twiddle */
- double freq = 2.0 * M_PI / N;
- double cosfreq8, sinfreq8;
- int i, n;
-
- xi = (double*)AllocMemory((N >> 2)*sizeof(double));
- xr = (double*)AllocMemory((N >> 2)*sizeof(double));
-
- /* prepare for recurrence relation in pre-twiddle */
- cfreq = cos (freq);
- sfreq = sin (freq);
- cosfreq8 = cos (freq * 0.125);
- sinfreq8 = sin (freq * 0.125);
- c = cosfreq8;
- s = sinfreq8;
-
- for (i = 0; i < (N >> 2); i++) {
- /* calculate real and imaginary parts of g(n) or G(p) */
- n = 2 * i;
-
- if (n < (N >> 2))
- tempr = data [(N>>2) + (N>>1) - 1 - n] + data [N - (N>>2) + n];
- else
- tempr = data [(N>>2) + (N>>1) - 1 - n] - data [-(N>>2) + n];
-
- if (n < (N >> 2))
- tempi = data [(N>>2) + n] - data [(N>>2) - 1 - n];
- else
- tempi = data [(N>>2) + n] + data [N + (N>>2) - 1 - n];
-
- /* calculate pre-twiddled FFT input */
- xr[i] = tempr * c + tempi * s;
- xi[i] = tempi * c - tempr * s;
-
- /* use recurrence to prepare cosine and sine for next value of i */
- cold = c;
- c = c * cfreq - s * sfreq;
- s = s * cfreq + cold * sfreq;
- }
-
- /* Perform in-place complex FFT of length N/4 */
- switch (N) {
- case BLOCK_LEN_SHORT * 2:
- fft( fft_tables, xr, xi, 6);
- break;
- case BLOCK_LEN_LONG * 2:
- fft( fft_tables, xr, xi, 9);
- }
-
- /* prepare for recurrence relations in post-twiddle */
- c = cosfreq8;
- s = sinfreq8;
-
- /* post-twiddle FFT output and then get output data */
- for (i = 0; i < (N >> 2); i++) {
- /* get post-twiddled FFT output */
- tempr = 2. * (xr[i] * c + xi[i] * s);
- tempi = 2. * (xi[i] * c - xr[i] * s);
-
- /* fill in output values */
- data [2 * i] = -tempr; /* first half even */
- data [(N >> 1) - 1 - 2 * i] = tempi; /* first half odd */
- data [(N >> 1) + 2 * i] = -tempi; /* second half even */
- data [N - 1 - 2 * i] = tempr; /* second half odd */
-
- /* use recurrence to prepare cosine and sine for next value of i */
- cold = c;
- c = c * cfreq - s * sfreq;
- s = s * cfreq + cold * sfreq;
- }
-
- if (xr) FreeMemory(xr);
- if (xi) FreeMemory(xi);
-}
-
-
-static void PsyBufferUpdate( FFT_Tables *fft_tables, GlobalPsyInfo * gpsyInfo, PsyInfo * psyInfo,
- double *newSamples, unsigned int bandwidth,
- int *cb_width_short, int num_cb_short)
-{
- int win;
- double transBuff[2 * BLOCK_LEN_LONG];
- double transBuffS[2 * BLOCK_LEN_SHORT];
- psydata_t *psydata = psyInfo->data;
- psyfloat *tmp;
- int sfb;
-
- psydata->bandS = psyInfo->sizeS * bandwidth * 2 / gpsyInfo->sampleRate;
-
- memcpy(transBuff, psyInfo->prevSamples, psyInfo->size * sizeof(double));
- memcpy(transBuff + psyInfo->size, newSamples, psyInfo->size * sizeof(double));
-
- for (win = 0; win < 8; win++)
- {
- int first = 0;
- int last = 0;
-
- memcpy(transBuffS, transBuff + (win * BLOCK_LEN_SHORT) + (BLOCK_LEN_LONG - BLOCK_LEN_SHORT) / 2,
- 2 * psyInfo->sizeS * sizeof(double));
-
- Hann(gpsyInfo, transBuffS, 2 * psyInfo->sizeS);
- mdct( fft_tables, transBuffS, 2 * psyInfo->sizeS);
-
- // shift bufs
- tmp = psydata->engPrev[win];
- psydata->engPrev[win] = psydata->eng[win];
- psydata->eng[win] = psydata->engNext[win];
- psydata->engNext[win] = psydata->engNext2[win];
- psydata->engNext2[win] = tmp;
-
- for (sfb = 0; sfb < num_cb_short; sfb++)
- {
- double e;
- int l;
-
- first = last;
- last = first + cb_width_short[sfb];
-
- if (first < 1)
- first = 1;
-
- if (first >= psydata->bandS) // band out of range
- break;
-
- e = 0.0;
- for (l = first; l < last; l++)
- e += transBuffS[l] * transBuffS[l];
-
- psydata->engNext2[win][sfb] = e;
- }
- psydata->lastband = sfb;
- for (; sfb < num_cb_short; sfb++)
- {
- psydata->engNext2[win][sfb] = 0;
- }
- }
-
- memcpy(psyInfo->prevSamples, newSamples, psyInfo->size * sizeof(double));
-}
-
-static void BlockSwitch(CoderInfo * coderInfo, PsyInfo * psyInfo, unsigned int numChannels)
-{
- unsigned int channel;
- int desire = ONLY_LONG_WINDOW;
-
- /* Use the same block type for all channels
- If there is 1 channel that wants a short block,
- use a short block on all channels.
- */
- for (channel = 0; channel < numChannels; channel++)
- {
- if (psyInfo[channel].block_type == ONLY_SHORT_WINDOW)
- desire = ONLY_SHORT_WINDOW;
- }
-
- for (channel = 0; channel < numChannels; channel++)
- {
- int lasttype = coderInfo[channel].block_type;
-
- if (desire == ONLY_SHORT_WINDOW
- || coderInfo[channel].desired_block_type == ONLY_SHORT_WINDOW)
- {
- if (lasttype == ONLY_LONG_WINDOW || lasttype == SHORT_LONG_WINDOW)
- coderInfo[channel].block_type = LONG_SHORT_WINDOW;
- else
- coderInfo[channel].block_type = ONLY_SHORT_WINDOW;
- }
- else
- {
- if (lasttype == ONLY_SHORT_WINDOW || lasttype == LONG_SHORT_WINDOW)
- coderInfo[channel].block_type = SHORT_LONG_WINDOW;
- else
- coderInfo[channel].block_type = ONLY_LONG_WINDOW;
- }
- coderInfo[channel].desired_block_type = desire;
- }
-}
-
-psymodel_t psymodel2 =
-{
- PsyInit,
- PsyEnd,
- PsyCalculate,
- PsyBufferUpdate,
- BlockSwitch
-};