/** ** 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 . **/ /* * audio.cpp * * Main Amp module. */ /* this file is a part of amp software, (C) tomislav uzelac 1996,1997 */ /* audio.c main amp source file * * Created by: tomislav uzelac Apr 1996 * Karl Anders Oygard added the IRIX code, 10 Mar 1997. * Ilkka Karvinen fixed /dev/dsp initialization, 11 Mar 1997. * Lutz Vieweg added the HP/UX code, 14 Mar 1997. * Dan Nelson added FreeBSD modifications, 23 Mar 1997. * Andrew Richards complete reorganisation, new features, 25 Mar 1997 * Edouard Lafargue added sajber jukebox support, 12 May 1997 */ #include "amp.h" #define AUDIO #include "amp_audio.h" #include "formats.h" #include "getbits.h" #include "huffman.h" #include "layer2.h" #include "layer3.h" #include "position.h" #include "rtbuf.h" #include "transform.h" //#ifndef __BEOS__ //typedef int bool; //#endif #include #include #include "Supermodel.h" #include "MPEG.h" //#include "m1snd.h" //#include "oss.h" //#include "mpeg.h" #define BUF_SIZE (1152 * sizeof(short) * 2) void calculate_t43(void); static int decoder_init = 0; static int cnt = 0; static int stream = -1; static char *buf0; static int playing = 0; static int outpos = 0; static int mpeg_eof = 0; static char *dst, *readbuf; static struct AUDIO_HEADER m1hdr;; void statusDisplay(struct AUDIO_HEADER *header, int frameNo) { int minutes,seconds; if ((A_SHOW_CNT || A_SHOW_TIME) && !(frameNo%10)) msg("\r"); if (A_SHOW_CNT && !(frameNo%10) ) { msg("{ %d } ",frameNo); } if (A_SHOW_TIME && !(frameNo%10)) { seconds=frameNo*1152/t_sampling_frequency[header->ID][header->sampling_frequency]; minutes=seconds/60; seconds=seconds % 60; msg("[%d:%02d]",minutes,seconds); } if (A_SHOW_CNT || A_SHOW_TIME) fflush(stderr); } // one mpeg frame is 576 samples. int decodeMPEGOneFrame(struct AUDIO_HEADER *header) { int snd_eof = 0, g; if ((g=gethdr(header))!=0) { report_header_error(g); snd_eof=1; return snd_eof; } if (header->protection_bit==0) getcrc(); statusDisplay(header,0); if (header->layer==1) { if (layer3_frame(header,cnt)) { ErrorLog("Internal error in MPEG decoder (%s:%d).", __FILE__, __LINE__); return -1; } } else if (header->layer==2) if (layer2_frame(header,cnt)) { ErrorLog("Internal error in MPEG decoder (%s:%d).", __FILE__, __LINE__); return -1; } cnt++; return snd_eof; } int decodeMPEG(void) { struct AUDIO_HEADER header; int g,snd_eof=0; initialise_globals(); cnt = 0; if ((g=gethdr(&header))!=0) { report_header_error(g); return -1; } if (header.protection_bit==0) getcrc(); //printf("%d Hz, layer %d\n", t_sampling_frequency[header.ID][header.sampling_frequency], header.layer); if (setup_audio(&header)!=0) { // will never fail (setup_audio() does nothing) ErrorLog("Internal error in MPEG decoder (%s:%d).", __FILE__, __LINE__); return -1; } if (header.layer==1) { if (layer3_frame(&header,cnt)) { ErrorLog("Internal error in MPEG decoder (%s:%d).", __FILE__, __LINE__); return -1; } } else if (header.layer==2) if (layer2_frame(&header,cnt)) { ErrorLog("Internal error in MPEG decoder (%s:%d).", __FILE__, __LINE__); return -1; } /* * decoder loop ********************************** */ snd_eof=0; while (!snd_eof) { while (!snd_eof && ready_audio()) { snd_eof = decodeMPEGOneFrame(&header); } } return 0; } /* call this once at the beginning */ void initialise_decoder(void) { premultiply(); imdct_init(); calculate_t43(); } /* call this before each file is played */ void initialise_globals(void) { append=::data=nch=0; f_bdirty=TRUE; bclean_bytes=0; memset(s,0,sizeof s); memset(res,0,sizeof res); } void report_header_error(int err) { switch (err) { case GETHDR_ERR: ErrorLog("Internal error in MPEG decoder: unable to read bit stream."); break; case GETHDR_NS : ErrorLog("Internal error in MPEG decoder: invalid MPEG format encountered."); break; case GETHDR_FL1: ErrorLog("Internal error in MPEG decoder: unsupported MPEG format encountered."); break; case GETHDR_FF : ErrorLog("Internal error in MPEG decoder: unsupported bit stream encountered."); break; case GETHDR_SYN: ErrorLog("Internal error in MPEG decoder: out of sync!"); break; case GETHDR_EOF: default: ; /* some stupid compilers need the semicolon */ } } int setup_audio(struct AUDIO_HEADER *header) { return 0; } void close_audio(void) { } int ready_audio(void) { return 1; } // callback: called by the engine to output a frame of audio void printout(void) { int j; if (nch==2) { j=32 * 18 * 2; } else { j=32 * 18; } // printf("printout: %x, %d\n", (unsigned int), j*2); memcpy(dst, sample_buffer, j*2); dst += j*2; outpos += j/2; } void MPEG_Decode(INT16 **outputs, int length) { int i, remaining, bias; INT16 *get; remaining = length; // printf("%d: %x %x\n", length, (unsigned int)outputs[0], (unsigned int)outputs[1]); if (!playing) { memset(&outputs[0][0], 0, length * sizeof(INT16)); memset(&outputs[1][0], 0, length * sizeof(INT16)); return; } bias = 0; // will we need more data from the decoder? if (outpos < length) { // if there's anything left in the current buffer, drain it first if (outpos != 0) { get = (INT16 *)readbuf; for (i = 0; i < outpos; i++) { outputs[1][i] = *get++; outputs[0][i] = *get++; } remaining -= outpos; bias = outpos; readbuf += (outpos * 4); } outpos = 0; dst = buf0; while ((outpos < remaining) && (playing)) { mpeg_eof = decodeMPEGOneFrame(&m1hdr); if (mpeg_eof) { MPEG_StopPlaying(); } } // reset read pointer readbuf = buf0; } get = (INT16 *)readbuf; for (i = 0; i < remaining; i++) { outputs[1][i+bias] = *get++; outputs[0][i+bias] = *get++; } outpos -= remaining; readbuf += (remaining * 4); } void MPEG_PlayFile(char *filename) { memset(buf0, 0, BUF_SIZE); in_file = fopen(filename, "rb"); initialise_globals(); cnt = 0; mpeg_eof = 0; outpos = 0; dst = buf0; readbuf = buf0; gethdr(&m1hdr); if (m1hdr.protection_bit == 0) getcrc(); // printf("%d Hz, layer %d\n", t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency], m1hdr.layer); // stream_set_srate(stream, t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency]); // prime the stream if (m1hdr.layer == 1) { layer3_frame(&m1hdr, cnt); } else if (m1hdr.layer == 2) { layer2_frame(&m1hdr, cnt); } playing = 1; } extern void m1setfile(const char *mstart, int mend); void MPEG_PlayMemory(const char *sa, int length) { memset(buf0, 0, BUF_SIZE); m1setfile(sa, length); initialise_globals(); cnt = 0; mpeg_eof = 0; outpos = 0; dst = buf0; readbuf = buf0; gethdr(&m1hdr); if (m1hdr.protection_bit == 0) getcrc(); // printf("%d Hz, layer %d\n", t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency], m1hdr.layer); // stream_set_srate(stream, t_sampling_frequency[m1hdr.ID][m1hdr.sampling_frequency]); // prime the stream if (m1hdr.layer == 1) { layer3_frame(&m1hdr, cnt); } else if (m1hdr.layer == 2) { layer2_frame(&m1hdr, cnt); } in_file = NULL; playing = 1; } void MPEG_StopPlaying(void) { if (playing) { playing = 0; if (in_file) fclose(in_file); } } bool MPEG_IsPlaying(void) { return playing ? TRUE : false; } bool MPEG_Init(void) { if (!decoder_init) { initialise_decoder(); /* initialise decoder */ decoder_init = 1; buf0 = new(std::nothrow) char[BUF_SIZE]; if (NULL == buf0) return FAIL; memset(buf0, 0, BUF_SIZE); playing = 0; } return OKAY; } void MPEG_Shutdown( void ) { decoder_init = 0; if (buf0 != NULL) delete [] buf0; buf0 = NULL; }