shithub: aacenc

Download patch

ref: 61c54b66612d77e6767c55b639969ebff9717caa
parent: 21c348fd5d20f77b018d0b812361a64fc139dc18
author: menno <menno>
date: Mon Mar 5 06:33:37 EST 2001

Added LTP
Needs some more refinement, but it works

--- a/frontend/faac.dsp
+++ b/frontend/faac.dsp
@@ -25,7 +25,7 @@
 # PROP AllowPerConfigDependencies 0
 # PROP Scc_ProjName ""
 # PROP Scc_LocalPath ""
-CPP=cl.exe
+CPP=xicl6.exe
 RSC=rc.exe
 
 !IF  "$(CFG)" == "faac - Win32 Release"
@@ -48,7 +48,7 @@
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
-LINK32=link.exe
+LINK32=xilink6.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
 # ADD LINK32 libsndfile.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /profile /machine:I386
 
@@ -72,7 +72,7 @@
 BSC32=bscmake.exe
 # ADD BASE BSC32 /nologo
 # ADD BSC32 /nologo
-LINK32=link.exe
+LINK32=xilink6.exe
 # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
 # ADD LINK32 libsndfile.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
 
--- a/frontend/faacgui.rc
+++ b/frontend/faacgui.rc
@@ -52,7 +52,7 @@
 // Dialog
 //
 
-IDD_MAINDIALOG DIALOGEX 0, 0, 266, 170
+IDD_MAINDIALOG DIALOGEX 0, 0, 266, 175
 STYLE DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | 
     WS_SYSMENU
 CAPTION "FAAC GUI"
@@ -65,9 +65,9 @@
     CONTROL         "Allow Mid/Side",IDC_ALLOWMIDSIDE,"Button",
                     BS_AUTOCHECKBOX | BS_LEFTTEXT | WS_TABSTOP,13,78,71,10
     EDITTEXT        IDC_BITRATE,142,73,69,14,ES_AUTOHSCROLL
-    EDITTEXT        IDC_BANDWIDTH,142,93,69,14,ES_AUTOHSCROLL
-    DEFPUSHBUTTON   "Encode",IDOK,75,149,50,14,WS_DISABLED
-    PUSHBUTTON      "Quit",IDCANCEL,141,149,50,14
+    EDITTEXT        IDC_BANDWIDTH,142,95,69,14,ES_AUTOHSCROLL
+    DEFPUSHBUTTON   "Encode",IDOK,75,154,50,14,WS_DISABLED
+    PUSHBUTTON      "Quit",IDCANCEL,141,154,50,14
     EDITTEXT        IDC_INPUTFILENAME,61,12,161,14,ES_AUTOHSCROLL
     EDITTEXT        IDC_OUTPUTFILENAME,61,32,161,14,ES_AUTOHSCROLL | 
                     WS_DISABLED
@@ -78,17 +78,20 @@
     LTEXT           "-",IDC_INPUTPARAMS,32,66,55,8
     LTEXT           "In:",IDC_STATIC,14,66,12,8
     CONTROL         "Progress1",IDC_PROGRESS,"msctls_progress32",WS_BORDER,7,
-                    120,252,10
-    GROUPBOX        "Output Format",IDC_STATIC,94,62,153,51
-    CTEXT           "- - -",IDC_TIME,7,136,252,8
-    LTEXT           "Bandwidth:",IDC_STATIC,101,96,37,8
+                    124,252,10
+    GROUPBOX        "Output Format",IDC_STATIC,94,62,153,57
+    CTEXT           "- - -",IDC_TIME,7,140,252,8
+    LTEXT           "Bandwidth:",IDC_STATIC,101,98,37,8
     LTEXT           "Bitrate:",IDC_STATIC,101,76,37,8
     LTEXT           "bps/ch",IDC_STATIC,218,76,24,8
-    LTEXT           "Hz",IDC_STATIC,218,96,10,8
+    LTEXT           "Hz",IDC_STATIC,218,98,10,8
     CONTROL         "Use LFE channel",IDC_USELFE,"Button",BS_AUTOCHECKBOX | 
-                    BS_LEFTTEXT | WS_DISABLED | WS_TABSTOP,13,102,71,10
+                    BS_LEFTTEXT | WS_DISABLED | WS_TABSTOP,13,111,71,10
     CONTROL         "Use TNS",IDC_USETNS,"Button",BS_AUTOCHECKBOX | 
-                    BS_LEFTTEXT | WS_TABSTOP,13,90,71,10
+                    BS_LEFTTEXT | WS_TABSTOP,13,89,71,10
+    CONTROL         "Use LTP",IDC_USELTP,"Button",BS_AUTOCHECKBOX | 
+                    BS_LEFTTEXT | WS_TABSTOP,13,100,71,10
+    RTEXT           "-",IDC_COMPILEDATE,196,160,63,8
 END
 
 
@@ -105,7 +108,7 @@
         LEFTMARGIN, 7
         RIGHTMARGIN, 259
         TOPMARGIN, 7
-        BOTTOMMARGIN, 163
+        BOTTOMMARGIN, 168
     END
 END
 #endif    // APSTUDIO_INVOKED
--- a/frontend/main.c
+++ b/frontend/main.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: main.c,v 1.8 2001/03/02 08:48:24 menno Exp $
+ * $Id: main.c,v 1.9 2001/03/05 11:33:37 menno Exp $
  */
 
 #ifdef _WIN32
@@ -69,7 +69,7 @@
 	int mins;
 #endif
 
-	printf("FAAC - command line demo\n");
+	printf("FAAC - command line demo of %s\n", __DATE__);
 	printf("Uses FAACLIB version: %.1f %s\n\n", FAACENC_VERSION, (FAACENC_VERSIONB)?"beta":"");
 
 	if (argc < 3)
@@ -78,6 +78,7 @@
 		printf("Options:\n");
 		printf("  -nm   Don\'t use mid/side coding\n");
 		printf("  -tns  Use TNS coding\n");
+		printf("  -ltp  Use LTP coding\n");
 		printf("  -bwX  Set the bandwidth, X in Hz\n");
 		printf("  -brX  Set the bitrate per channel, X in bps\n\n");
 		return 1;
@@ -121,6 +122,10 @@
 				case 't': case 'T':
 					if ((argv[i][2] == 'n') || (argv[i][2] == 'N'))
 						myFormat->useTns = 1;
+				break;
+				case 'l': case 'L':
+					if ((argv[i][2] == 't') || (argv[i][2] == 'T'))
+						myFormat->useLtp = 1;
 				break;
 				case 'n': case 'N':
 					if ((argv[i][2] == 'm') || (argv[i][2] == 'M'))
--- a/frontend/maingui.c
+++ b/frontend/maingui.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: maingui.c,v 1.7 2001/02/28 19:09:56 menno Exp $
+ * $Id: maingui.c,v 1.8 2001/03/05 11:33:37 menno Exp $
  */
 
 #include <windows.h>
@@ -138,6 +138,7 @@
 
 		config->allowMidside = IsDlgButtonChecked(hWnd, IDC_ALLOWMIDSIDE) == BST_CHECKED ? 1 : 0;
 		config->useTns = IsDlgButtonChecked(hWnd, IDC_USETNS) == BST_CHECKED ? 1 : 0;
+		config->useLtp = IsDlgButtonChecked(hWnd, IDC_USELTP) == BST_CHECKED ? 1 : 0;
 		GetDlgItemText(hWnd, IDC_BITRATE, szTemp, sizeof(szTemp));
 		config->bitRate = atoi(szTemp);
 		GetDlgItemText(hWnd, IDC_BANDWIDTH, szTemp, sizeof(szTemp));
@@ -180,6 +181,7 @@
 			config->allowMidside = IsDlgButtonChecked(hWnd, IDC_ALLOWMIDSIDE) == BST_CHECKED ? 1 : 0;
 			config->useTns = IsDlgButtonChecked(hWnd, IDC_USETNS) == BST_CHECKED ? 1 : 0;
 			config->useLfe = IsDlgButtonChecked(hWnd, IDC_USELFE) == BST_CHECKED ? 1 : 0;
+			config->useLtp = IsDlgButtonChecked(hWnd, IDC_USELTP) == BST_CHECKED ? 1 : 0;
 			GetDlgItemText(hWnd, IDC_BITRATE, szTemp, sizeof(szTemp));
 			config->bitRate = atoi(szTemp);
 			GetDlgItemText(hWnd, IDC_BANDWIDTH, szTemp, sizeof(szTemp));
@@ -317,8 +319,11 @@
 		CheckDlgButton(hWnd, IDC_ALLOWMIDSIDE, TRUE);
 		CheckDlgButton(hWnd, IDC_USELFE, FALSE);
 		CheckDlgButton(hWnd, IDC_USETNS, TRUE);
+		CheckDlgButton(hWnd, IDC_USELTP, FALSE);
 		SetDlgItemText(hWnd, IDC_BITRATE, "64000");
 		SetDlgItemText(hWnd, IDC_BANDWIDTH, "18000");
+
+		SetDlgItemText(hWnd, IDC_COMPILEDATE, "Ver: " __DATE__);
 
 		DragAcceptFiles(hWnd, TRUE);
 		return TRUE;
--- a/frontend/resource.h
+++ b/frontend/resource.h
@@ -15,6 +15,8 @@
 #define IDC_BITRATE                     1010
 #define IDC_USELFE                      1011
 #define IDC_USETNS                      1012
+#define IDC_USELTP                      1013
+#define IDC_COMPILEDATE                 1018
 
 // Next default values for new objects
 // 
@@ -22,7 +24,7 @@
 #ifndef APSTUDIO_READONLY_SYMBOLS
 #define _APS_NEXT_RESOURCE_VALUE        103
 #define _APS_NEXT_COMMAND_VALUE         40001
-#define _APS_NEXT_CONTROL_VALUE         1016
+#define _APS_NEXT_CONTROL_VALUE         1019
 #define _APS_NEXT_SYMED_VALUE           101
 #endif
 #endif
--- a/include/faac.h
+++ b/include/faac.h
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: faac.h,v 1.3 2001/02/28 18:39:34 menno Exp $
+ * $Id: faac.h,v 1.4 2001/03/05 11:33:37 menno Exp $
  */
 
 #ifndef FAACLIB_H
@@ -58,6 +58,9 @@
 
 	/* Use Temporal Noise Shaping */
 	unsigned int useTns;
+
+	/* Use Long Term Prediction */
+	unsigned int useLtp;
 
 	/* bitrate / channel of AAC file */
 	unsigned long bitRate;
--- a/libfaac/aacquant.c
+++ b/libfaac/aacquant.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: aacquant.c,v 1.4 2001/02/28 18:39:34 menno Exp $
+ * $Id: aacquant.c,v 1.5 2001/03/05 11:33:37 menno Exp $
  */
 
 #include <math.h>
@@ -62,14 +62,22 @@
 	for (channel = 0; channel < numChannels; channel++) {
 		coderInfo[channel].old_value = 0;
 		coderInfo[channel].CurrentStep = 4;
+
+		coderInfo[channel].requantFreq = (double*)malloc(BLOCK_LEN_LONG*sizeof(double));
 	}
 }
 
-void AACQuantizeEnd()
+void AACQuantizeEnd(CoderInfo *coderInfo, unsigned int numChannels)
 {
+	unsigned int channel;
+
 	if (pow43) free(pow43);
 	if (adj43) free(adj43);
 	if (adj43asm) free(adj43asm);
+
+	for (channel = 0; channel < numChannels; channel++) {
+		if (coderInfo[channel].requantFreq) free(coderInfo[channel].requantFreq);
+	}
 }
 
 int AACQuantize(CoderInfo *coderInfo,
@@ -406,7 +414,6 @@
 	int *scale_factor = coderInfo->scale_factor;
 
 	int *best_scale_factor;
-	double *requant_xr;
 	int *save_xi;
 	double *distort;
 
@@ -413,7 +420,6 @@
 	distort = (double*)malloc(MAX_SCFAC_BANDS*sizeof(double));
 	best_scale_factor = (int*)malloc(MAX_SCFAC_BANDS*sizeof(int));
 
-	requant_xr = (double*)malloc(FRAME_LEN*sizeof(double));
 	save_xi = (int*)malloc(FRAME_LEN*sizeof(int));
 
 	notdone = 1;
@@ -428,7 +434,7 @@
 
 		store_global_gain = coderInfo->global_gain;
 
-		over = CalcNoise(coderInfo, xr, xi, requant_xr, distort, xmin, &noiseInfo);
+		over = CalcNoise(coderInfo, xr, xi, coderInfo->requantFreq, distort, xmin, &noiseInfo);
 
 		if (outer_loop_count == 1)
 			better = 1;
@@ -467,7 +473,6 @@
 	}
 	memcpy(xi, save_xi, sizeof(int)*BLOCK_LEN_LONG);
 
-	if (requant_xr) free(requant_xr);
 	if (best_scale_factor) free(best_scale_factor);
 	if (save_xi) free(save_xi);
 	if (distort) free(distort);
--- a/libfaac/aacquant.h
+++ b/libfaac/aacquant.h
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: aacquant.h,v 1.1 2001/01/17 11:21:40 menno Exp $
+ * $Id: aacquant.h,v 1.2 2001/03/05 11:33:37 menno Exp $
  */
 
 #ifndef AACQUANT_H
@@ -47,7 +47,7 @@
 } calcNoiseResult;
 
 void AACQuantizeInit(CoderInfo *coderInfo, unsigned int numChannels);
-void AACQuantizeEnd();
+void AACQuantizeEnd(CoderInfo *coderInfo, unsigned int numChannels);
 
 int AACQuantize(CoderInfo *coderInfo,
 				PsyInfo *psyInfo,
--- a/libfaac/bitstream.c
+++ b/libfaac/bitstream.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: bitstream.c,v 1.4 2001/02/28 18:39:34 menno Exp $
+ * $Id: bitstream.c,v 1.5 2001/03/05 11:33:37 menno Exp $
  */
 
 #include <stdlib.h>
@@ -26,8 +26,8 @@
 #include "channels.h"
 #include "huffman.h"
 #include "bitstream.h"
+#include "ltp.h"
 
-
 int WriteBitstream(faacEncHandle hEncoder,
 				   CoderInfo *coderInfo,
 				   ChannelInfo *channelInfo,
@@ -377,18 +377,50 @@
 	return bits;
 }
 
-static int WriteLTPPredictorData(CoderInfo *coderInfo,
-								 BitStream *bitStream,
-								 int writeFlag)
+static int WriteLTPPredictorData(CoderInfo *coderInfo, BitStream *bitStream, int writeFlag)
 {
-	int bits = 0;
+	int i, last_band;
+	int bits;
+	LtpInfo *ltpInfo = &coderInfo->ltpInfo;
 
-	if(writeFlag)
-		PutBit (bitStream, 0, 1);  /* LTP not used */
+	bits = 1;
+	
+	if (ltpInfo->global_pred_flag)
+	{
+		if(writeFlag)
+			PutBit(bitStream, 1, 1); /* LTP used */
 
-	bits += 1;
+		switch(coderInfo->block_type)
+		{
+		case ONLY_LONG_WINDOW:
+		case LONG_SHORT_WINDOW:
+		case SHORT_LONG_WINDOW:
+			bits += LEN_LTP_LAG;
+			bits += LEN_LTP_COEF;
+			if(writeFlag)
+			{
+				PutBit(bitStream, ltpInfo->delay[0], LEN_LTP_LAG);
+				PutBit(bitStream, ltpInfo->weight_idx,  LEN_LTP_COEF);
+			}
 
-	return bits;
+			last_band = (coderInfo->nr_of_sfb < MAX_LT_PRED_LONG_SFB) ?
+				coderInfo->nr_of_sfb : MAX_LT_PRED_LONG_SFB;
+
+			bits += last_band;
+			if(writeFlag)
+				for (i = 0; i < last_band; i++)
+					PutBit(bitStream, ltpInfo->sfb_prediction_used[i], LEN_LTP_LONG_USED);
+				break;
+				
+		default:
+			break;
+		}
+	} else {
+		if(writeFlag)
+			PutBit(bitStream, 0, 1); /* LTP not used */
+	}
+
+	return (bits);
 }
 
 static int WritePulseData(CoderInfo *coderInfo,
--- a/libfaac/coder.h
+++ b/libfaac/coder.h
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: coder.h,v 1.3 2001/02/28 18:39:34 menno Exp $
+ * $Id: coder.h,v 1.4 2001/03/05 11:33:37 menno Exp $
  */
 
 #ifndef CODER_H
@@ -44,7 +44,6 @@
 	SHORT_LONG_WINDOW
 };
 
-/* Added TNS defines and structures here to get it to compile */
 #define TNS_MAX_ORDER 20
 #define DEF_TNS_GAIN_THRESH 1.4
 #define DEF_TNS_COEFF_THRESH 0.1
@@ -53,6 +52,23 @@
 #define LEN_TNS_NFILTL 2
 #define LEN_TNS_NFILTS 1
 
+#define LPC 1
+#define DELAY 2048
+#define	LEN_LTP_DATA_PRESENT 1
+#define	LEN_LTP_LAG 11
+#define	LEN_LTP_COEF 3
+#define	LEN_LTP_SHORT_USED 1
+#define	LEN_LTP_SHORT_LAG_PRESENT 1
+#define	LEN_LTP_SHORT_LAG 5
+#define	LTP_LAG_OFFSET 16
+#define	LEN_LTP_LONG_USED 1
+#define	MAX_LT_PRED_LONG_SFB 40
+#define	MAX_LT_PRED_SHORT_SFB 13
+#define SHORT_SQ_OFFSET (BLOCK_LEN_LONG-(BLOCK_LEN_SHORT*4+BLOCK_LEN_SHORT/2))
+#define CODESIZE 8
+#define NOK_LT_BLEN (3 * BLOCK_LEN_LONG)
+
+
 typedef struct {
 	int order;                           /* Filter order */
 	int direction;		                 /* Filtering direction */
@@ -79,9 +95,23 @@
 	int tnsMaxOrderShort;
 	TnsWindowData windowData[MAX_SHORT_WINDOWS]; /* TNS data per window */
 } TnsInfo;
-/* End of TNS defines and structures */
 
+typedef struct
+{
+	int weight_idx;
+	double weight;
+	int sbk_prediction_used[MAX_SHORT_WINDOWS];
+	int sfb_prediction_used[MAX_SCFAC_BANDS];
+	int delay[MAX_SHORT_WINDOWS];
+	int global_pred_flag;
+	int side_info;
+	short *buffer;
+	double *mdct_predicted;
 
+	double *time_buffer;
+	double *ltp_overlap_buffer;
+} LtpInfo;
+
 typedef struct {
 	int window_shape;
 	int prev_window_shape;
@@ -111,7 +141,11 @@
 	/* Lengths of spectral bitstream elements */
 	int *len;
 
+	/* Holds the requantized spectrum */
+	double *requantFreq;
+
 	TnsInfo tnsInfo;
+	LtpInfo ltpInfo;
 
 } CoderInfo;
 
--- a/libfaac/filtbank.c
+++ b/libfaac/filtbank.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: filtbank.c,v 1.4 2001/02/28 18:39:34 menno Exp $
+ * $Id: filtbank.c,v 1.5 2001/03/05 11:33:37 menno Exp $
  */
 
 /*
@@ -82,10 +82,11 @@
 				CoderInfo *coderInfo,
 				double *p_in_data,
 				double *p_out_mdct,
-				double *p_overlap)
+				double *p_overlap,
+				int overlap_select)
 {
-	double *transf_buf;
 	double *p_o_buf, *first_window, *second_window;
+	double *transf_buf;
 	int k, i;
 	int block_type = coderInfo->block_type;
 
@@ -93,39 +94,49 @@
 
 	/* create / shift old values */
 	/* We use p_overlap here as buffer holding the last frame time signal*/
-	memcpy(transf_buf, p_overlap, FRAME_LEN*sizeof(double));
-	memcpy(transf_buf+BLOCK_LEN_LONG, p_in_data, FRAME_LEN*sizeof(double));
-	memcpy(p_overlap, p_in_data, FRAME_LEN*sizeof(double));
+	if(overlap_select != MNON_OVERLAPPED) {
+		memcpy(transf_buf, p_overlap, FRAME_LEN*sizeof(double));
+		memcpy(transf_buf+BLOCK_LEN_LONG, p_in_data, FRAME_LEN*sizeof(double));
+		memcpy(p_overlap, p_in_data, FRAME_LEN*sizeof(double));
+	} else {
+		memcpy(transf_buf, p_in_data, 2*FRAME_LEN*sizeof(double));
+	}
 
 	/*  Window shape processing */
-	switch (coderInfo->prev_window_shape){
-    case SINE_WINDOW:
-		if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW))
-			first_window = hEncoder->sin_window_long;
-		else
-			first_window = hEncoder->sin_window_short;
-		break;
-    case KBD_WINDOW:
-		if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW))
-			first_window = hEncoder->kbd_window_long;
-		else
-			first_window = hEncoder->kbd_window_short;
-		break;
-	}
+	if(overlap_select != MNON_OVERLAPPED) {
+		switch (coderInfo->prev_window_shape) {
+		case SINE_WINDOW:
+			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW))
+				first_window = hEncoder->sin_window_long;
+			else
+				first_window = hEncoder->sin_window_short;
+			break;
+		case KBD_WINDOW:
+			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW))
+				first_window = hEncoder->kbd_window_long;
+			else
+				first_window = hEncoder->kbd_window_short;
+			break;
+		}
 
-	switch (coderInfo->window_shape){
-    case SINE_WINDOW:
-		if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW))
-			second_window = hEncoder->sin_window_long;
-		else
-			second_window = hEncoder->sin_window_short;
-		break;
-    case KBD_WINDOW:
-		if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW))
-			second_window = hEncoder->kbd_window_long;
-		else
-			second_window = hEncoder->kbd_window_short;
-		break;
+		switch (coderInfo->window_shape){
+		case SINE_WINDOW:
+			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW))
+				second_window = hEncoder->sin_window_long;
+			else
+				second_window = hEncoder->sin_window_short;
+			break;
+		case KBD_WINDOW:
+			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW))
+				second_window = hEncoder->kbd_window_long;
+			else
+				second_window = hEncoder->kbd_window_short;
+			break;
+		}
+	} else {
+		/* Always long block and sine window for LTP */
+		first_window = hEncoder->sin_window_long;
+		second_window = hEncoder->sin_window_long;
 	}
 
 	/* Set ptr to transf-Buffer */
@@ -132,7 +143,7 @@
 	p_o_buf = transf_buf;
 
 	/* Separate action for each Block Type */
-	switch( block_type ) {
+	switch (block_type) {
     case ONLY_LONG_WINDOW :
 		for ( i = 0 ; i < BLOCK_LEN_LONG ; i++){
 			p_out_mdct[i] = p_o_buf[i] * first_window[i];
@@ -179,6 +190,161 @@
 	if (transf_buf) free(transf_buf);
 }
 
+void IFilterBank(faacEncHandle hEncoder,
+				 CoderInfo *coderInfo,
+				 double *p_in_data,
+				 double *p_out_data,
+				 double *p_overlap,
+				 int overlap_select)
+{
+	double *o_buf, *transf_buf, *overlap_buf;
+	double *first_window, *second_window;
+
+	double  *fp;
+	int k, i;
+	int block_type = coderInfo->block_type;
+
+	transf_buf = (double*)malloc(2*BLOCK_LEN_LONG*sizeof(double));
+	overlap_buf = (double*)malloc(2*BLOCK_LEN_LONG*sizeof(double));
+
+	/*  Window shape processing */
+	if (overlap_select != MNON_OVERLAPPED) {
+//		switch (coderInfo->prev_window_shape){
+//		case SINE_WINDOW:
+			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW))
+				first_window = hEncoder->sin_window_long;
+			else
+				first_window = hEncoder->sin_window_short;
+//			break;
+//		case KBD_WINDOW:
+//			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == LONG_SHORT_WINDOW))
+//				first_window = hEncoder->kbd_window_long;
+//			else
+//				first_window = hEncoder->kbd_window_short;
+//			break;
+//		}
+
+//		switch (coderInfo->window_shape){
+//		case SINE_WINDOW:
+			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW))
+				second_window = hEncoder->sin_window_long;
+			else
+				second_window = hEncoder->sin_window_short;
+//			break;
+//		case KBD_WINDOW:
+//			if ( (block_type == ONLY_LONG_WINDOW) || (block_type == SHORT_LONG_WINDOW))
+//				second_window = hEncoder->kbd_window_long;
+//			else
+//				second_window = hEncoder->kbd_window_short;
+//			break;
+//		}
+	} else {
+		/* Always long block and sine window for LTP */
+		first_window  = hEncoder->sin_window_long;
+		second_window = hEncoder->sin_window_long;
+	}
+
+	/* Assemble overlap buffer */
+	memcpy(overlap_buf,p_overlap,BLOCK_LEN_LONG*sizeof(double));
+	o_buf = overlap_buf;
+
+	/* Separate action for each Block Type */
+	switch( block_type ) {
+    case ONLY_LONG_WINDOW :
+		memcpy(transf_buf, p_in_data,BLOCK_LEN_LONG*sizeof(double));
+		IMDCT( transf_buf, 2*BLOCK_LEN_LONG );
+		for ( i = 0 ; i < BLOCK_LEN_LONG ; i++)
+			transf_buf[i] *= first_window[i];
+		if (overlap_select != MNON_OVERLAPPED) {
+			for ( i = 0 ; i < BLOCK_LEN_LONG; i++ ){
+				o_buf[i] += transf_buf[i];
+				o_buf[i+BLOCK_LEN_LONG] = transf_buf[i+BLOCK_LEN_LONG] * second_window[BLOCK_LEN_LONG-i-1];
+			}
+		} else { /* overlap_select == NON_OVERLAPPED */
+			for ( i = 0 ; i < BLOCK_LEN_LONG; i++ )
+				transf_buf[i+BLOCK_LEN_LONG] *= second_window[BLOCK_LEN_LONG-i-1];
+        }
+		break;
+
+    case LONG_SHORT_WINDOW :
+		memcpy(transf_buf, p_in_data,BLOCK_LEN_LONG*sizeof(double));
+		IMDCT( transf_buf, 2*BLOCK_LEN_LONG );
+		for ( i = 0 ; i < BLOCK_LEN_LONG ; i++)
+			transf_buf[i] *= first_window[i];
+        if (overlap_select != MNON_OVERLAPPED) {
+			for ( i = 0 ; i < BLOCK_LEN_LONG; i++ )
+				o_buf[i] += transf_buf[i];
+			memcpy(o_buf+BLOCK_LEN_LONG,transf_buf+BLOCK_LEN_LONG,NFLAT_LS*sizeof(double));
+			for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++)
+				o_buf[i+BLOCK_LEN_LONG+NFLAT_LS] = transf_buf[i+BLOCK_LEN_LONG+NFLAT_LS] * second_window[BLOCK_LEN_SHORT-i-1];
+			memset(o_buf+BLOCK_LEN_LONG+NFLAT_LS+BLOCK_LEN_SHORT,0,NFLAT_LS*sizeof(double));
+        } else { /* overlap_select == NON_OVERLAPPED */
+			for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++)
+				transf_buf[i+BLOCK_LEN_LONG+NFLAT_LS] *= second_window[BLOCK_LEN_SHORT-i-1];
+			memset(transf_buf+BLOCK_LEN_LONG+NFLAT_LS+BLOCK_LEN_SHORT,0,NFLAT_LS*sizeof(double));
+		}
+		break;
+
+	case SHORT_LONG_WINDOW :
+		memcpy(transf_buf, p_in_data,BLOCK_LEN_LONG*sizeof(double));
+		IMDCT( transf_buf, 2*BLOCK_LEN_LONG );
+		for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++)
+			transf_buf[i+NFLAT_LS] *= first_window[i];
+		if (overlap_select != MNON_OVERLAPPED) {
+			for ( i = 0 ; i < BLOCK_LEN_SHORT; i++ )
+				o_buf[i+NFLAT_LS] += transf_buf[i+NFLAT_LS];
+			memcpy(o_buf+BLOCK_LEN_SHORT+NFLAT_LS,transf_buf+BLOCK_LEN_SHORT+NFLAT_LS,NFLAT_LS*sizeof(double));
+			for ( i = 0 ; i < BLOCK_LEN_LONG ; i++)
+				o_buf[i+BLOCK_LEN_LONG] = transf_buf[i+BLOCK_LEN_LONG] * second_window[BLOCK_LEN_LONG-i-1];
+		} else { /* overlap_select == NON_OVERLAPPED */
+			memset(transf_buf,0,NFLAT_LS*sizeof(double));
+			for ( i = 0 ; i < BLOCK_LEN_LONG ; i++)
+				transf_buf[i+BLOCK_LEN_LONG] *= second_window[BLOCK_LEN_LONG-i-1];
+		}
+		break;
+
+	case ONLY_SHORT_WINDOW :
+		if (overlap_select != MNON_OVERLAPPED) {
+			fp = o_buf + NFLAT_LS;
+		} else { /* overlap_select == NON_OVERLAPPED */
+			fp = transf_buf;
+		}
+		for ( k=0; k < MAX_SHORT_WINDOWS; k++ ) {
+			memcpy(transf_buf,p_in_data,BLOCK_LEN_SHORT*sizeof(double));
+			IMDCT( transf_buf, 2*BLOCK_LEN_SHORT );
+			p_in_data += BLOCK_LEN_SHORT;
+			if (overlap_select != MNON_OVERLAPPED) {
+				for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++){
+					transf_buf[i] *= first_window[i];
+					fp[i] += transf_buf[i];
+					fp[i+BLOCK_LEN_SHORT] = transf_buf[i+BLOCK_LEN_SHORT] * second_window[BLOCK_LEN_SHORT-i-1];
+				}
+				fp += BLOCK_LEN_SHORT;
+			} else { /* overlap_select == NON_OVERLAPPED */
+				for ( i = 0 ; i < BLOCK_LEN_SHORT ; i++){
+					fp[i] *= first_window[i];
+					fp[i+BLOCK_LEN_SHORT] *= second_window[BLOCK_LEN_SHORT-i-1];
+				}
+				fp += 2*BLOCK_LEN_SHORT;
+			}
+			first_window = second_window;
+		}
+		memset(o_buf+BLOCK_LEN_LONG+NFLAT_LS+BLOCK_LEN_SHORT,0,NFLAT_LS*sizeof(double));
+		break;
+	}
+
+	if (overlap_select != MNON_OVERLAPPED)
+		memcpy(p_out_data,o_buf,BLOCK_LEN_LONG*sizeof(double));
+	else  /* overlap_select == NON_OVERLAPPED */
+		memcpy(p_out_data,transf_buf,2*BLOCK_LEN_LONG*sizeof(double));
+
+	/* save unused output data */
+	memcpy(p_overlap,o_buf+BLOCK_LEN_LONG,BLOCK_LEN_LONG*sizeof(double));
+
+	if (overlap_buf) free(overlap_buf);
+	if (transf_buf) free(transf_buf);
+}
+
 void specFilter(double *freqBuff,
 				int sampleRate,
 				int lowpassFreq,
@@ -308,6 +474,86 @@
 		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) free(xr);
+	if (xi) free(xi);
+}
+
+static void IMDCT(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 fac, cosfreq8, sinfreq8;
+	int i;
+
+	xi = (double*)malloc((N >> 2)*sizeof(double));
+	xr = (double*)malloc((N >> 2)*sizeof(double));
+
+	/* Choosing to allocate 2/N factor to Inverse Xform! */
+	fac = 2. / N; /* remaining 2/N from 4/N IFFT factor */
+
+	/* 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) */
+		tempr = -data[2 * i];
+		tempi = data[(N >> 1) - 1 - 2 * i];
+
+		/* 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 IFFT of length N/4 */
+	switch (N) {
+    case 256:
+		srifft(xr, xi, 6);
+		break;
+    case 2048:
+		srifft(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 = fac * (xr[i] * c - xi[i] * s);
+		tempi = fac * (xi[i] * c + xr[i] * s);
+
+		/* fill in output values */
+		data [(N >> 1) + (N >> 2) - 1 - 2 * i] = tempr;
+		if (i < (N >> 3))
+			data [(N >> 1) + (N >> 2) + 2 * i] = tempr;
+		else
+			data [2 * i - (N >> 2)] = -tempr;
+
+		data [(N >> 2) + 2 * i] = tempi;
+		if (i < (N >> 3))
+			data [(N >> 2) - 1 - 2 * i] = -tempi;
+		else
+			data [(N >> 2) + N - 1 - 2*i] = tempi;
 
 		/* use recurrence to prepare cosine and sine for next value of i */
 		cold = c;
--- a/libfaac/filtbank.h
+++ b/libfaac/filtbank.h
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: filtbank.h,v 1.5 2001/02/28 18:39:34 menno Exp $
+ * $Id: filtbank.h,v 1.6 2001/03/05 11:33:37 menno Exp $
  */
 
 #ifndef FILTBANK_H
@@ -31,6 +31,10 @@
 #define NFLAT_LS 448
 
 
+#define MOVERLAPPED     0
+#define MNON_OVERLAPPED 1
+
+
 #define SINE_WINDOW 0
 #define KBD_WINDOW  1
 
@@ -42,7 +46,15 @@
 				CoderInfo *coderInfo,
 				double *p_in_data,
 				double *p_out_mdct,
-				double *p_overlap);
+				double *p_overlap,
+				int overlap_select);
+
+void IFilterBank(faacEncHandle hEncoder,
+				 CoderInfo *coderInfo,
+				 double *p_in_data,
+				 double *p_out_mdct,
+				 double *p_overlap,
+				 int overlap_select);
 
 void specFilter(double *freqBuff,
 				int sampleRate,
--- a/libfaac/frame.c
+++ b/libfaac/frame.c
@@ -16,7 +16,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *
- * $Id: frame.c,v 1.10 2001/02/28 18:39:34 menno Exp $
+ * $Id: frame.c,v 1.11 2001/03/05 11:33:37 menno Exp $
  */
 
 /*
@@ -41,6 +41,7 @@
 #include "huffman.h"
 #include "psych.h"
 #include "tns.h"
+#include "ltp.h"
 
 
 faacEncConfigurationPtr FAACAPI faacEncGetCurrentConfiguration(faacEncHandle hEncoder)
@@ -56,6 +57,7 @@
 	hEncoder->config.allowMidside = config->allowMidside;
 	hEncoder->config.useLfe = config->useLfe;
 	hEncoder->config.useTns = config->useTns;
+	hEncoder->config.useLtp = config->useLtp;
 	hEncoder->config.aacProfile = config->aacProfile;
 
 	 /* No SSR supported yet */
@@ -100,6 +102,7 @@
 	hEncoder->config.allowMidside = 1;
 	hEncoder->config.useLfe = 0;
 	hEncoder->config.useTns = 0;
+	hEncoder->config.useLtp = 0;
 	hEncoder->config.bitRate = 64000; /* default bitrate / channel */
 	hEncoder->config.bandWidth = 18000; /* default bandwidth */
 
@@ -116,6 +119,8 @@
 		hEncoder->sampleBuff[channel] = NULL;
 		hEncoder->nextSampleBuff[channel] = NULL;
 		hEncoder->next2SampleBuff[channel] = NULL;
+		hEncoder->ltpTimeBuff[channel] = (double*)malloc(2*BLOCK_LEN_LONG*sizeof(double));
+		memset(hEncoder->ltpTimeBuff[channel], 0, 2*BLOCK_LEN_LONG*sizeof(double));
 	}
 
 	/* Initialize coder functions */
@@ -126,6 +131,8 @@
 
     TnsInit(hEncoder);
 
+	LtpInit(hEncoder);
+
 	AACQuantizeInit(hEncoder->coderInfo, hEncoder->numChannels);
 
 	HuffmanInit(hEncoder->coderInfo, hEncoder->numChannels);
@@ -143,12 +150,15 @@
 
 	FilterBankEnd(hEncoder);
 
-	AACQuantizeEnd();
+	LtpEnd(hEncoder);
 
+	AACQuantizeEnd(hEncoder->coderInfo, hEncoder->numChannels);
+
 	HuffmanEnd(hEncoder->coderInfo, hEncoder->numChannels);
 
 	/* Free remaining buffer memory */
 	for (channel = 0; channel < hEncoder->numChannels; channel++) {
+		if (hEncoder->ltpTimeBuff[channel]) free(hEncoder->ltpTimeBuff[channel]);
 		if (hEncoder->sampleBuff[channel]) free(hEncoder->sampleBuff[channel]);
 		if (hEncoder->nextSampleBuff[channel]) free(hEncoder->nextSampleBuff[channel]);
 	}
@@ -170,6 +180,8 @@
 	int sb, frameBytes;
 	unsigned int bitsToUse, offset;
 	BitStream *bitStream; /* bitstream used for writing the frame to */
+	TnsInfo *tnsInfo_for_LTP;
+	TnsInfo *tnsDecInfo;
 
 	/* local copy's of parameters */
 	ChannelInfo *channelInfo = hEncoder->channelInfo;
@@ -179,6 +191,7 @@
 	unsigned int aacProfile = hEncoder->config.aacProfile;
 	unsigned int useLfe = hEncoder->config.useLfe;
 	unsigned int useTns = hEncoder->config.useTns;
+	unsigned int useLtp = hEncoder->config.useLtp;
 	unsigned int allowMidside = hEncoder->config.allowMidside;
 	unsigned int bitRate = hEncoder->config.bitRate;
 	unsigned int bandWidth = hEncoder->config.bandWidth;
@@ -189,7 +202,7 @@
 	if (samplesInput == 0)
 		hEncoder->flushFrame++;
 
-	/* After 4 flush frames all samples have been encoded,
+	/* After 2 flush frames all samples have been encoded,
 	   return 0 bytes written */
 	if (hEncoder->flushFrame == 2)
 		return 0;
@@ -199,6 +212,18 @@
 
 	/* Update current sample buffers */
 	for (channel = 0; channel < numChannels; channel++) {
+		if (hEncoder->sampleBuff[channel]) {
+			for(i = 0; i < FRAME_LEN; i++) {
+				hEncoder->ltpTimeBuff[channel][i] =	hEncoder->sampleBuff[channel][i];
+			}
+		}
+		if (hEncoder->nextSampleBuff[channel]) {
+			for(i = 0; i < FRAME_LEN; i++) {
+				hEncoder->ltpTimeBuff[channel][FRAME_LEN + i] =
+					hEncoder->nextSampleBuff[channel][i];
+			}
+		}
+
 		if (hEncoder->sampleBuff[channel])
 			free(hEncoder->sampleBuff[channel]);
 		hEncoder->sampleBuff[channel] = hEncoder->nextSampleBuff[channel];
@@ -240,7 +265,8 @@
 			&coderInfo[channel],
 			hEncoder->sampleBuff[channel],
 			hEncoder->freqBuff[channel],
-			hEncoder->overlapBuff[channel]);
+			hEncoder->overlapBuff[channel],
+			MOVERLAPPED);
 
 		if (coderInfo[channel].block_type == ONLY_SHORT_WINDOW) {
 			for (k = 0; k < 8; k++) {
@@ -307,6 +333,27 @@
 		}
 	}
 
+	for(channel = 0; channel < numChannels; channel++)
+	{
+		if((coderInfo[channel].tnsInfo.tnsDataPresent != 0) && (useTns))
+			tnsInfo_for_LTP = &(coderInfo[channel].tnsInfo);
+		else
+			tnsInfo_for_LTP = NULL;
+
+		if(channelInfo[channel].present && (!channelInfo[channel].lfe) &&
+			(coderInfo[channel].block_type != ONLY_SHORT_WINDOW) && (useLtp)) 
+		{
+			LtpEncode(hEncoder,
+				&coderInfo[channel],
+				&(coderInfo[channel].ltpInfo),
+				tnsInfo_for_LTP,
+				hEncoder->freqBuff[channel],
+				hEncoder->ltpTimeBuff[channel]);
+		} else {
+			coderInfo[channel].ltpInfo.global_pred_flag = 0;
+		}
+	}
+
 	MSEncode(coderInfo, channelInfo, hEncoder->freqBuff, numChannels, allowMidside);
 
 	/* Quantize and code the signal */
@@ -320,6 +367,44 @@
 			AACQuantize(&coderInfo[channel], &hEncoder->psyInfo[channel],
 				&channelInfo[channel], hEncoder->srInfo->cb_width_long,
 				hEncoder->srInfo->num_cb_long, hEncoder->freqBuff[channel], bitsToUse);
+		}
+	}
+
+	for (channel = 0; channel < numChannels; channel++) 
+	{
+		if((coderInfo[channel].tnsInfo.tnsDataPresent != 0) && (useTns))
+			tnsDecInfo = &(coderInfo[channel].tnsInfo);
+		else
+			tnsDecInfo = NULL;
+		
+		if ((!channelInfo[channel].lfe) && (useLtp)) {  /* no reconstruction needed for LFE channel*/
+
+			LtpReconstruct(&coderInfo[channel], &(coderInfo[channel].ltpInfo),
+				coderInfo[channel].requantFreq);
+
+			if(tnsDecInfo != NULL)
+				TnsDecodeFilterOnly(&(coderInfo[channel].tnsInfo), coderInfo[channel].nr_of_sfb,
+					coderInfo[channel].max_sfb, coderInfo[channel].block_type,
+					coderInfo[channel].sfb_offset, coderInfo[channel].requantFreq);
+
+			IFilterBank(hEncoder, &coderInfo[channel],
+				coderInfo[channel].requantFreq,
+				coderInfo[channel].ltpInfo.time_buffer,
+				coderInfo[channel].ltpInfo.ltp_overlap_buffer,
+				MOVERLAPPED);
+
+			LtpUpdate(&(coderInfo[channel].ltpInfo),
+				coderInfo[channel].ltpInfo.time_buffer,
+				coderInfo[channel].ltpInfo.ltp_overlap_buffer,
+				BLOCK_LEN_LONG);
+		}
+
+		/* If short window, reconstruction not needed for prediction */
+		if ((coderInfo[channel].block_type == ONLY_SHORT_WINDOW)) {
+			int sind;
+			for (sind = 0; sind < 1024; sind++) {
+				coderInfo[channel].requantFreq[sind] = 0.0;
+			}
 		}
 	}
 
--- a/todo.txt
+++ b/todo.txt
@@ -5,9 +5,9 @@
 - DONE: Add frequency cutoff filter
 - DONE: Add ADTS headers
 - DONE: Write GUI
-- Add TNS
+- DONE: Add TNS
+- DONE: Add LTP
 - Add PNS
-- Add LTP
 - Add backward prediction (MPEG2-AAC)????
 - Add IS
 - Add bit reservoir control