#include "stdafx.h"
#include "lameDecoder.h"
/*
for example:
mp3 to wav
ClameDecoder lameDec;
lameDec.init();
...
lameDec.decode_stream_write_header();
lameDec.get_data();
...
lameDec.write_tail();
lameDec.uninit();
//////////
mp3 to pcm
ClameDecoder lameDec;
lameDec.init();
...
lameDec.decode_stream();
lameDec.get_data();
...
lameDec.uninit();
*/
std::vector<short> resample(const std::vector<short>& pcmData, int srcFreq, int dstFreq) {
std::vector<short> resampledData;
// 计算采样频率比例
double ratio = static_cast<double>(dstFreq) / static_cast<double>(srcFreq);
// 计算目标采样点数
int dstSampleCount = static_cast<int>(pcmData.size() * ratio);
resampledData.resize(dstSampleCount);
for (int i = 0; i < dstSampleCount; ++i) {
// 计算源数据在目标采样中对应位置的索引
double srcIndex = i / ratio;
// 双线性插值计算目标位置的取值
int floorIndex = static_cast<int>(srcIndex);
int ceilIndex = floorIndex + 1;
if (ceilIndex >= pcmData.size()) {
ceilIndex = floorIndex;
}
double fraction = srcIndex - floorIndex;
short floorValue = pcmData[floorIndex];
short ceilValue = pcmData[ceilIndex];
short interpolatedValue = static_cast<short>((1.0 - fraction) * floorValue + fraction * ceilValue);
resampledData[i] = interpolatedValue;
}
return resampledData;
}
ClameDecoder::ClameDecoder()
{
//Initialize to NULL, aids deletion/closing later
}
ClameDecoder::~ClameDecoder()
{
//Destroy all declared objects
}
int ClameDecoder::init()
{
m_nChannels = -1;
m_nSampleRate = -1;
m_nWavsize = 0;
lame = lame_init();
m_nOutChannels = 1;
m_nOutSampleRate = 16000;
lame_set_decode_only(lame, 1);
if (lame_init_params(lame) == -1)
{
return -1;
}
hip = hip_decode_init();
memset(&m_mp3data, 0, sizeof(m_mp3data));
return 0;
}
int ClameDecoder::init(int outSampleRate, int channels)
{
m_nChannels = -1;
m_nSampleRate = -1;
m_nWavsize = 0;
lame = lame_init();
m_nOutChannels = channels;
m_nOutSampleRate = outSampleRate;
lame_set_decode_only(lame, 1);
if (lame_init_params(lame) == -1)
{
return -1;
}
hip = hip_decode_init();
memset(&m_mp3data, 0, sizeof(m_mp3data));
return 0;
}
void ClameDecoder::uninit()
{
hip_decode_exit(hip);
lame_close(lame);
}
void write_16_bits_low_high(FILE * fp, int val)
{
unsigned char bytes[2];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
fwrite(bytes, 1, 2, fp);
}
void write_32_bits_low_high(FILE * fp, int val)
{
unsigned char bytes[4];
bytes[0] = (val & 0xff);
bytes[1] = ((val >> 8) & 0xff);
bytes[2] = ((val >> 16) & 0xff);
bytes[3] = ((val >> 24) & 0xff);
fwrite(bytes, 1, 4, fp);
}
void WriteWaveHeader(FILE * const fp, int pcmbytes, int freq, int channels, int bits)
{
int bytes = (bits + 7) / 8;
/* quick and dirty, but documented */
fwrite("RIFF", 1, 4, fp); /* label */
write_32_bits_low_high(fp, pcmbytes + 44 - 8); /* length in bytes without header */
fwrite("WAVEfmt ", 2, 4, fp); /* 2 labels */
write_32_bits_low_high(fp, 2 + 2 + 4 + 4 + 2 + 2); /* length of PCM format declaration area */
write_16_bits_low_high(fp, 1); /* is PCM? */
write_16_bits_low_high(fp, channels); /* number of channels */
write_32_bits_low_high(fp, freq); /* sample frequency in [Hz] */
write_32_bits_low_high(fp, freq * channels * bytes); /* bytes per second */
write_16_bits_low_high(fp, channels * bytes); /* bytes per sample time */
write_16_bits_low_high(fp, bits); /* bits per sample */
fwrite("data", 1, 4, fp); /* label */
write_32_bits_low_high(fp, pcmbytes); /* length in bytes of raw PCM data */
}
void ClameDecoder::decode_stream_write_header(unsigned char* mp3_buffer, int mp3_data_length, int & pcm_data_length, FILE *wav)
{
short int pcm_l[PCM_SIZE], pcm_r[PCM_SIZE];
int nMp3Len = mp3_data_length;
int samples;
std::vector<short> beforeData;
m_recvData.clear();
char buf[2];
pcm_data_length = 0;
int j = 0;
do
{
if (m_mp3data.header_parsed == 0)
{
samples = hip_decode1_headers(hip, mp3_buffer, nMp3Len, pcm_l, pcm_r, &m_mp3data);
if (m_mp3data.header_parsed == 1)//header is gotten
{
if (m_nChannels < 0)//reading for the first time
{
//Write the header
WriteWaveHeader(wav, 0x7FFFFFFF, m_mp3data.samplerate, m_mp3data.stereo, 16); //unknown size, so write maximum 32 bit signed value
}
m_nChannels = m_mp3data.stereo;
m_nSampleRate = m_mp3data.samplerate;
}
if (samples > 0 && m_mp3data.header_parsed != 1)
{
printf("WARNING: lame decode error occured!");
break;
}
}
samples = hip_decode(hip, mp3_buffer, nMp3Len, pcm_l, pcm_r);
m_nWavsize += samples;
if (samples > 0)
{
for (int i = 0; i < samples; i++)
{
beforeData.push_back(pcm_l[i]);
if (m_nOutChannels == 2)
{
beforeData.push_back(pcm_r[i]);
}
}
m_recvData = resample(beforeData, m_nSampleRate, m_nOutSampleRate);
pcm_data_length = m_recvData.size() * sizeof(short);
}
nMp3Len = 0;
} while (samples>0);
}
void ClameDecoder::get_data(byte* data)
{
char buf[2];
for (int i = 0; i < m_recvData.size(); i++)
{
memcpy(buf, &m_recvData[i], sizeof(m_recvData[i]));
data[i*2] = buf[0];
data[i*2+1] = buf[1];
}
m_recvData.clear();
}
void ClameDecoder::write_tail(FILE *wav)
{
int i = (16 / 8) * m_mp3data.stereo;
if (m_nWavsize <= 0)
{
m_nWavsize = 0;
}
else if (m_nWavsize > 0xFFFFFFD0 / i)
{
m_nWavsize = 0xFFFFFFD0;
}
else
{
m_nWavsize *= i;
}
if (!fseek(wav, 0l, SEEK_SET))//seek back and adjust length
WriteWaveHeader(wav, (int)m_nWavsize, m_mp3data.samplerate, m_mp3data.stereo, 16);
}
void ClameDecoder::decode_stream(unsigned char* mp3_buffer, int mp3_data_length, int & pcm_data_length)
{
short int pcm_l[PCM_SIZE], pcm_r[PCM_SIZE];
int nMp3Len = mp3_data_length;
int samples;
std::vector<short> beforeData;
m_recvData.clear();
char buf[2];
pcm_data_length = 0;
int j = 0;
do
{
if (m_mp3data.header_parsed == 0)
{
samples = hip_decode1_headers(hip, mp3_buffer, nMp3Len, pcm_l, pcm_r, &m_mp3data);
if (m_mp3data.header_parsed == 1)//header is gotten
{
m_nChannels = m_mp3data.stereo;
m_nSampleRate = m_mp3data.samplerate;
}
if (samples > 0 && m_mp3data.header_parsed != 1)
{
printf("WARNING: lame decode error occured!");
break;
}
}
samples = hip_decode(hip, mp3_buffer, nMp3Len, pcm_l, pcm_r);
m_nWavsize += samples;
if (samples > 0)
{
for (int i = 0; i < samples; i++)
{
beforeData.push_back(pcm_l[i]);
if (m_nOutChannels == 2)
{
beforeData.push_back(pcm_r[i]);
}
}
m_recvData = resample(beforeData, m_nSampleRate, m_nOutSampleRate);
pcm_data_length = m_recvData.size() * sizeof(short);
}
nMp3Len = 0;
} while (samples>0);
}