📄 mp3.cpp
字号:
/*++
Copyright (c) 2004 Sten
Contact information:
mail: stenri@mail.ru
This program 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 2
of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Module Name:
mp3.cpp
Abstract: Helper mp3 decoding routines.
Revision History:
St 06/01/2004
Initial release
--*/
extern "C" {
#pragma warning ( push, 3 )
#include <ntddk.h>
#pragma warning ( pop )
}
#pragma warning ( disable: 4514 ) // unreferenced inline function has been removed
#pragma warning ( disable: 4127 ) // conditional expression is constant
#include <windef.h>
#include <ntverp.h>
#include <stdio.h>
#include "mp3.h"
/*
* The following utility routine performs simple rounding, clipping, and
* scaling of MAD's high-resolution samples down to 16 bits. It does not
* perform any dithering or noise shaping, which would be recommended to
* obtain any exceptional audio quality. It is therefore not recommended to
* use this routine if high-quality output is desired.
*/
static inline signed int mp3_scale(mad_fixed_t sample)
{
/* round */
sample += (1L << (MAD_F_FRACBITS - 16));
/* clip */
if (sample >= MAD_F_ONE)
sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE)
sample = -MAD_F_ONE;
/* quantize */
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
/*
* This is the output callback function. It is called after each frame of
* MPEG audio data has been completely decoded. The purpose of this callback
* is to output (or play) the decoded PCM audio.
*/
static int last_nsamples_left = 0;
static int bad_last_frame = 0;
static int mp3_output(struct mad_header const *header,
struct mad_pcm *pcm,
unsigned char *buf,
int size)
{
UNREFERENCED_PARAMETER(header);
int out_size = 0;
unsigned int nchannels, nsamples;
mad_fixed_t const *left_ch, *right_ch;
/* pcm->samplerate contains the sampling frequency */
nchannels = pcm->channels;
nsamples = pcm->length;
left_ch = pcm->samples[0];
right_ch = pcm->samples[1];
if (last_nsamples_left)
{
left_ch += nsamples - last_nsamples_left;
right_ch += nsamples - last_nsamples_left;
nsamples = last_nsamples_left;
}
while (nsamples)
{
signed int sample;
nsamples--;
// output sample(s) in 16-bit signed little-endian PCM
sample = mp3_scale(*left_ch++);
if (out_size >= size) break;
out_size += 2;
*buf++ = (UCHAR)((sample >> 0) & 0xff);
*buf++ = (UCHAR)((sample >> 8) & 0xff);
if (nchannels == 2)
{
if (out_size >= size) break;
out_size += 2;
sample = mp3_scale(*right_ch++);
*buf++ = (UCHAR)((sample >> 0) & 0xff);
*buf++ = (UCHAR)((sample >> 8) & 0xff);
}
}
last_nsamples_left = nsamples;
return out_size;
}
/*
* This is the error callback function. It is called whenever a decoding
* error occurs. The error is indicated by stream->error; the list of
* possible MAD_ERROR_* errors can be found in the mad.h (or
* libmad/stream.h) header file.
*/
static enum mad_flow mp3_error(struct mad_stream *stream,
struct mad_frame *frame)
{
DbgPrint("decoding error 0x%04x (%s) at offset %u\n",
stream->error, mad_stream_errorstr(stream),
(PUCHAR)stream->this_frame - (PUCHAR)stream->buffer);
switch (stream->error)
{
case MAD_ERROR_BADCRC:
if (bad_last_frame)
mad_frame_mute(frame);
else
bad_last_frame = 1;
return MAD_FLOW_IGNORE;
default:
return MAD_FLOW_IGNORE;
}
}
static struct mad_stream stream;
static struct mad_frame frame;
static struct mad_synth synth;
void mp3_Init(void *mp3buf, int size)
{
last_nsamples_left = 0;
bad_last_frame = 0;
mad_stream_init(&stream);
mad_frame_init(&frame);
mad_synth_init(&synth);
mad_stream_options(&stream, 0);
mad_stream_buffer(&stream, (const unsigned char *)mp3buf, size);
}
void mp3_Done()
{
mad_synth_finish(&synth);
mad_frame_finish(&frame);
mad_stream_finish(&stream);
}
int mp3_GetData(unsigned char *buf, int size)
{
int out_size = 0;
if (mp3_EOF()) return -1;
memset(buf, 0, size);
while (1)
{
int delta = mp3_output(&frame.header, &synth.pcm, buf, size - out_size);
out_size += delta;
buf += delta;
if (out_size >= size) break;
if (mad_header_decode(&frame.header, &stream) == -1)
{
if (!MAD_RECOVERABLE(stream.error)) return -1;
switch (mp3_error(&stream, &frame))
{
case MAD_FLOW_STOP:
return -1;
case MAD_FLOW_BREAK:
return -1;
case MAD_FLOW_IGNORE:
case MAD_FLOW_CONTINUE:
default:
continue;
}
}
if (mad_frame_decode(&frame, &stream) == -1)
{
if (!MAD_RECOVERABLE(stream.error)) return -1;
switch (mp3_error(&stream, &frame))
{
case MAD_FLOW_STOP:
return -1;
case MAD_FLOW_BREAK:
return -1;
case MAD_FLOW_IGNORE:
break;
case MAD_FLOW_CONTINUE:
default:
continue;
}
}
else
bad_last_frame = 0;
mad_synth_frame(&synth, &frame);
}
return out_size;
}
int mp3_GetCurrentSampleRate()
{
return (frame.header.samplerate * synth.pcm.channels) / 2; // we always play stereo sound
}
bool mp3_EOF()
{
return stream.this_frame >= stream.bufend;
}
void mp3_RestartStream()
{
last_nsamples_left = 0;
bad_last_frame = 0;
mad_stream_buffer(&stream, stream.buffer, (PUCHAR)stream.bufend - (PUCHAR)stream.buffer);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -