mirror of
https://github.com/RetroDECK/Supermodel.git
synced 2024-11-30 01:25:49 +00:00
226 lines
5.5 KiB
C++
226 lines
5.5 KiB
C++
/**
|
|
** Supermodel
|
|
** A Sega Model 3 Arcade Emulator.
|
|
** Copyright 2011 Bart Trzynadlowski, Nik Henson
|
|
**
|
|
** This file is part of Supermodel.
|
|
**
|
|
** Supermodel 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.
|
|
**
|
|
** Supermodel 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 Supermodel. If not, see <http://www.gnu.org/licenses/>.
|
|
**/
|
|
|
|
/*
|
|
* layer3.cpp
|
|
*
|
|
* Amp library internal module.
|
|
*/
|
|
|
|
|
|
/* this file is a part of amp software, (C) tomislav uzelac 1996,1997
|
|
*/
|
|
|
|
/* layer3.c layer3 audio decoding
|
|
*
|
|
* Created by: tomislav uzelac Mar 1 97
|
|
* Last modified by:
|
|
*/
|
|
#include "amp.h"
|
|
#include "audio.h"
|
|
#include "dump.h"
|
|
#include "getbits.h"
|
|
#include "getdata.h"
|
|
#include "huffman.h"
|
|
#include "misc2.h"
|
|
#include "rtbuf.h"
|
|
#include "transform.h"
|
|
|
|
#define LAYER3
|
|
#include "layer3.h"
|
|
|
|
void requantize_downmix(int gr,struct SIDE_INFO *info,struct AUDIO_HEADER *header);
|
|
|
|
/* this function decodes one layer3 audio frame, except for the header decoding
|
|
* which is done in main() [audio.c]. returns 0 if everything is ok.
|
|
*/
|
|
int layer3_frame(struct AUDIO_HEADER *header,int cnt)
|
|
{
|
|
static struct SIDE_INFO info;
|
|
|
|
int gr,ch,sb,i;
|
|
int mean_frame_size,bitrate,fs,hsize,ssize;
|
|
|
|
/* we need these later, hsize is the size of header+side_info
|
|
*/
|
|
if (header->ID)
|
|
if (header->mode==3) {
|
|
nch=1;
|
|
hsize=21;
|
|
} else {
|
|
nch=2;
|
|
hsize=36;
|
|
}
|
|
else
|
|
if (header->mode==3) {
|
|
nch=1;
|
|
hsize=13;
|
|
} else {
|
|
nch=2;
|
|
hsize=21;
|
|
}
|
|
|
|
/* crc increases hsize by 2
|
|
*/
|
|
if (header->protection_bit==0) hsize+=2;
|
|
|
|
|
|
/* read layer3 specific side_info
|
|
*/
|
|
getinfo(header,&info);
|
|
|
|
|
|
/* MPEG2 only has one granule
|
|
*/
|
|
bitrate=t_bitrate[header->ID][3-header->layer][header->bitrate_index];
|
|
fs=t_sampling_frequency[header->ID][header->sampling_frequency];
|
|
if (header->ID) mean_frame_size=144000*bitrate/fs;
|
|
else mean_frame_size=72000*bitrate/fs;
|
|
|
|
|
|
/* check if mdb is too big for the first few frames. this means that
|
|
* a part of the stream could be missing. We must still fill the buffer
|
|
*
|
|
* don't forget to (re)initialise bclean_bytes to 0, and f_bdirty to FALSE!!!
|
|
*/
|
|
if (f_bdirty)
|
|
{
|
|
if (info.main_data_begin > bclean_bytes) {
|
|
fillbfr(mean_frame_size + header->padding_bit - hsize);
|
|
bclean_bytes+=mean_frame_size + header->padding_bit - hsize;
|
|
/* warn(" frame %d discarded, incomplete main_data\n",cnt); */
|
|
return 0;
|
|
} else {
|
|
/* re-initialise */
|
|
f_bdirty=FALSE;
|
|
bclean_bytes=0;
|
|
}
|
|
}
|
|
|
|
/* now update the data 'pointer' (counting in bits) according to
|
|
* the main_data_begin information
|
|
*/
|
|
data = 8 * ((append - info.main_data_begin) & (BUFFER_SIZE-1));
|
|
|
|
|
|
/* read into the buffer all bytes up to the start of next header
|
|
*/
|
|
fillbfr(mean_frame_size + header->padding_bit - hsize);
|
|
|
|
|
|
/* these two should go away
|
|
*/
|
|
t_l=&t_b8_l[header->ID][header->sampling_frequency][0];
|
|
t_s=&t_b8_s[header->ID][header->sampling_frequency][0];
|
|
|
|
/* debug/dump stuff
|
|
*/
|
|
if (A_DUMP_BINARY) dump((int *)info.part2_3_length);
|
|
|
|
/* decode the scalefactors and huffman data
|
|
* this part needs to be enhanced for error robustness
|
|
*/
|
|
for (gr=0;gr < ((header->ID) ? 2 : 1);gr++) {
|
|
for (ch=0;ch<nch;ch++) {
|
|
ssize=decode_scalefactors(&info,header,gr,ch);
|
|
decode_huffman_data(&info,gr,ch,ssize);
|
|
}
|
|
|
|
/* requantization, stereo processing, reordering(shortbl)
|
|
*/
|
|
|
|
if (A_DOWNMIX && nch==2) requantize_downmix(gr,&info,header);
|
|
else
|
|
if (header->mode!=1 || (header->mode==1 && header->mode_extension==0))
|
|
for (ch=0;ch<nch;ch++) requantize_mono(gr,ch,&info,header);
|
|
else requantize_ms(gr,&info,header);
|
|
|
|
/* just which window?
|
|
*/
|
|
|
|
/* this is a very temporary, very ugly hack.
|
|
*/
|
|
if (A_DOWNMIX) nch=1;
|
|
|
|
for (ch=0; ch < (A_DOWNMIX ? 1:nch) ;ch++) {
|
|
int win_type; /* same as in the standard, long=0, start=1 ,.... */
|
|
int window_switching_flag = info.window_switching_flag[gr][ch];
|
|
int block_type = info.block_type[gr][ch];
|
|
int mixed_block_flag = info.mixed_block_flag[gr][ch];
|
|
|
|
/* antialiasing butterflies
|
|
*/
|
|
if (!(window_switching_flag &&
|
|
block_type==2))
|
|
alias_reduction(ch);
|
|
|
|
if (window_switching_flag &&
|
|
block_type==2 &&
|
|
mixed_block_flag)
|
|
win_type=0;
|
|
else
|
|
if (!window_switching_flag) win_type=0;
|
|
else win_type=block_type;
|
|
|
|
/* imdct ...
|
|
*/
|
|
for (sb=0;sb<2;sb++)
|
|
imdct(win_type,sb,ch);
|
|
|
|
if (window_switching_flag &&
|
|
block_type==2 &&
|
|
mixed_block_flag)
|
|
win_type=2;
|
|
|
|
/* no_of_imdcts tells us how many subbands from the top are all zero
|
|
* it is set by the requantize functions in misc2.c
|
|
*/
|
|
for (sb=2;sb<no_of_imdcts[ch];sb++)
|
|
imdct(win_type,sb,ch);
|
|
|
|
for (;sb<32;sb++)
|
|
for (i=0;i<18;i++) {
|
|
res[sb][i]=s[ch][sb][i];
|
|
s[ch][sb][i]=0.0f;
|
|
}
|
|
|
|
/* polyphase filterbank
|
|
*/
|
|
/* if (nch == 2) this was a bug, tomislav */
|
|
for (i=0;i<18;i++)
|
|
poly(ch,i);
|
|
}
|
|
|
|
printout();
|
|
|
|
/* this is part2 of a particularily ugly hack. this should vanish as soon as nch isn't
|
|
a global variable anymore
|
|
*/
|
|
if (A_DOWNMIX && header->mode!=3) nch=2;
|
|
|
|
} /* for (gr... */
|
|
|
|
/* return status: 0 for ok, errors will be added
|
|
*/
|
|
return 0;
|
|
}
|
|
|