From cc73f54cdd9c94d5edd0ab596cdfdcd6742cd3b3 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Fri, 16 Jul 2010 15:27:04 +0300 Subject: [PATCH] mp3decoder separated --- od-win32/mp3decoder.cpp | 218 ++++++++++++++++++++++++++++++++++++++++ od-win32/mp3decoder.h | 10 ++ 2 files changed, 228 insertions(+) create mode 100644 od-win32/mp3decoder.cpp create mode 100644 od-win32/mp3decoder.h diff --git a/od-win32/mp3decoder.cpp b/od-win32/mp3decoder.cpp new file mode 100644 index 00000000..95730ee2 --- /dev/null +++ b/od-win32/mp3decoder.cpp @@ -0,0 +1,218 @@ + +/* +* UAE +* +* mp3 decoder helper class +* +* Copyright 2010 Toni Wilen +* +*/ + +#include "sysconfig.h" +#include "sysdeps.h" + +#include +#include + +#include +#include +#include + +#define MP3_BLOCK_SIZE 522 + +static int mp3_bitrates[] = { + 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1, + 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1, + 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1, + 0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, -1, + 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, -1 +}; +static int mp3_frequencies[] = { + 44100, 48000, 32000, 0, + 22050, 24000, 16000, 0, + 11025, 12000, 8000, 0 +}; +static int mp3_samplesperframe[] = { + 384, 384, 384, + 1152, 1152, 1152, + 1152, 576, 576 +}; + +mp3decoder::~mp3decoder() +{ + if (g_mp3stream) + acmStreamClose((HACMSTREAM)g_mp3stream, 0); + g_mp3stream = NULL; +} + +mp3decoder::mp3decoder() +{ + MMRESULT mmr; + LPWAVEFORMATEX waveFormat; + LPMPEGLAYER3WAVEFORMAT mp3format; + DWORD maxFormatSize; + + // find the biggest format size + maxFormatSize = 0; + mmr = acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &maxFormatSize); + + // define desired output format + waveFormat = (LPWAVEFORMATEX)LocalAlloc(LPTR, maxFormatSize); + waveFormat->wFormatTag = WAVE_FORMAT_PCM; + waveFormat->nChannels = 2; // stereo + waveFormat->nSamplesPerSec = 44100; // 44.1kHz + waveFormat->wBitsPerSample = 16; // 16 bits + waveFormat->nBlockAlign = 4; // 4 bytes of data at a time are useful (1 sample) + waveFormat->nAvgBytesPerSec = 4 * 44100; // byte-rate + waveFormat->cbSize = 0; // no more data to follow + + // define MP3 input format + mp3format = (LPMPEGLAYER3WAVEFORMAT)LocalAlloc(LPTR, maxFormatSize); + mp3format->wfx.cbSize = MPEGLAYER3_WFX_EXTRA_BYTES; + mp3format->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3; + mp3format->wfx.nChannels = 2; + mp3format->wfx.nAvgBytesPerSec = 128 * (1024 / 8); // not really used but must be one of 64, 96, 112, 128, 160kbps + mp3format->wfx.wBitsPerSample = 0; // MUST BE ZERO + mp3format->wfx.nBlockAlign = 1; // MUST BE ONE + mp3format->wfx.nSamplesPerSec = 44100; // 44.1kHz + mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_OFF; + mp3format->nBlockSize = MP3_BLOCK_SIZE; // voodoo value #1 + mp3format->nFramesPerBlock = 1; // MUST BE ONE + mp3format->nCodecDelay = 1393; // voodoo value #2 + mp3format->wID = MPEGLAYER3_ID_MPEG; + + mmr = acmStreamOpen((LPHACMSTREAM)&g_mp3stream, // open an ACM conversion stream + NULL, // querying all ACM drivers + (LPWAVEFORMATEX) mp3format, // converting from MP3 + waveFormat, // to WAV + NULL, // with no filter + 0, // or async callbacks + 0, // (and no data for the callback) + 0 // and no flags + ); + + LocalFree(mp3format); + LocalFree(waveFormat); + if (mmr != MMSYSERR_NOERROR) { + write_log(L"CUEMP3: couldn't open ACM mp3 decoder, %d\n", mmr); + throw exception(); + } +} + +uae_u8 *mp3decoder::get (struct zfile *zf, int maxsize) +{ + MMRESULT mmr; + unsigned long rawbufsize = 0; + LPBYTE mp3buf; + LPBYTE rawbuf; + uae_u8 *outbuf = NULL; + int outoffset = 0; + ACMSTREAMHEADER mp3streamHead; + HACMSTREAM h = (HACMSTREAM)g_mp3stream; + + write_log(L"CUEMP3: decoding '%s'..\n", zfile_getname(zf)); + mmr = acmStreamSize(h, MP3_BLOCK_SIZE, &rawbufsize, ACM_STREAMSIZEF_SOURCE); + if (mmr != MMSYSERR_NOERROR) { + write_log (L"CUEMP3: acmStreamSize, %d\n", mmr); + return NULL; + } + // allocate our I/O buffers + mp3buf = (LPBYTE)LocalAlloc(LPTR, MP3_BLOCK_SIZE); + rawbuf = (LPBYTE)LocalAlloc(LPTR, rawbufsize); + + // prepare the decoder + ZeroMemory(&mp3streamHead, sizeof (ACMSTREAMHEADER)); + mp3streamHead.cbStruct = sizeof (ACMSTREAMHEADER); + mp3streamHead.pbSrc = mp3buf; + mp3streamHead.cbSrcLength = MP3_BLOCK_SIZE; + mp3streamHead.pbDst = rawbuf; + mp3streamHead.cbDstLength = rawbufsize; + mmr = acmStreamPrepareHeader(h, &mp3streamHead, 0); + if (mmr != MMSYSERR_NOERROR) { + write_log(L"CUEMP3: acmStreamPrepareHeader, %d\n", mmr); + return NULL; + } + zfile_fseek(zf, 0, SEEK_SET); + outbuf = xcalloc(uae_u8, maxsize); + for (;;) { + int count = zfile_fread(mp3buf, 1, MP3_BLOCK_SIZE, zf); + if (count != MP3_BLOCK_SIZE) + break; + // convert the data + mmr = acmStreamConvert(h, &mp3streamHead, ACM_STREAMCONVERTF_BLOCKALIGN); + if (mmr != MMSYSERR_NOERROR) { + write_log(L"CUEMP3: acmStreamConvert, %d\n", mmr); + return NULL; + } + if (outoffset + mp3streamHead.cbDstLengthUsed > maxsize) + break; + memcpy(outbuf + outoffset, rawbuf, mp3streamHead.cbDstLengthUsed); + outoffset += mp3streamHead.cbDstLengthUsed; + } + acmStreamUnprepareHeader(h, &mp3streamHead, 0); + LocalFree(rawbuf); + LocalFree(mp3buf); + write_log(L"CUEMP3: unpacked size %d bytes\n", outoffset); + return outbuf; +} + +uae_u32 mp3decoder::getsize (struct zfile *zf) +{ + uae_u32 size; + int frames; + + frames = 0; + size = 0; + for (;;) { + int ver, layer, bitrate, freq, padding, bitindex, iscrc; + int samplerate, framelen, bitrateidx, channelmode; + int isstereo; + uae_u8 header[4]; + + if (zfile_fread(header, sizeof header, 1, zf) != 1) + return size; + if (header[0] != 0xff || ((header[1] & (0x80 | 0x40 | 0x20)) != (0x80 | 0x40 | 0x20))) { + zfile_fseek (zf, -3, SEEK_CUR); + continue; + } + ver = (header[1] >> 3) & 3; + if (ver == 1) + return 0; + if (ver == 0) + ver = 2; + else if (ver == 2) + ver = 1; + else if (ver == 3) + ver = 0; + layer = 4 - ((header[1] >> 1) & 3); + if (layer == 4) + return 0; + iscrc = ((header[1] >> 0) & 1) ? 0 : 2; + bitrateidx = (header[2] >> 4) & 15; + freq = mp3_frequencies[(header[2] >> 2) & 3]; + if (!freq) + return 0; + channelmode = (header[3] >> 6) & 3; + isstereo = channelmode != 3; + if (ver == 0) { + bitindex = layer - 1; + } else { + if (layer == 1) + bitindex = 3; + else + bitindex = 4; + } + bitrate = mp3_bitrates[bitindex * 16 + bitrateidx] * 1000; + if (bitrate <= 0) + return 0; + padding = (header[2] >> 1) & 1; + samplerate = mp3_samplesperframe[(layer - 1) * 3 + ver]; + framelen = ((samplerate / 8 * bitrate) / freq) + padding; + if (framelen <= 4) + return 0; + zfile_fseek(zf, framelen + iscrc - 4, SEEK_CUR); + frames++; + size += samplerate * 2 * (isstereo ? 2 : 1); + } + return size; +} diff --git a/od-win32/mp3decoder.h b/od-win32/mp3decoder.h new file mode 100644 index 00000000..7655c801 --- /dev/null +++ b/od-win32/mp3decoder.h @@ -0,0 +1,10 @@ + +class mp3decoder +{ + void *g_mp3stream; +public: + mp3decoder(); + ~mp3decoder(); + uae_u8 *get(struct zfile *zf, int maxsize); + uae_u32 mp3decoder::getsize(struct zfile *zf); +}; -- 2.47.3