mirror of
https://github.com/clangen/musikcube.git
synced 2025-04-16 14:42:41 +00:00
Working MP3 decoder!
This commit is contained in:
parent
5207bb36de
commit
8cd06ea886
@ -1,20 +1,72 @@
|
|||||||
#include "StdAfx.h"
|
#include "StdAfx.h"
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
#include <iostream>
|
||||||
#include "mp3decoder.h"
|
#include "mp3decoder.h"
|
||||||
|
|
||||||
MP3Decoder::MP3Decoder() :
|
static bool splitFrame(musik::core::io::IDataStream *dataStream, Frame &fr) {
|
||||||
m_hFile(NULL),
|
unsigned char headerbuf[4] = { 0, 0, 0, 0 };
|
||||||
m_pDecoder(NULL)
|
unsigned char crcbuf[2];
|
||||||
{
|
unsigned char sideInfoBuffer[32];
|
||||||
|
unsigned long bytesRead;
|
||||||
|
unsigned long errorCount = 0;
|
||||||
|
unsigned long currentOffset = dataStream->Position();
|
||||||
|
|
||||||
|
if (dataStream->Read(headerbuf, 4) != 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!fr.m_Header.Load(headerbuf)) {
|
||||||
|
headerbuf[0] = headerbuf[1];
|
||||||
|
headerbuf[1] = headerbuf[2];
|
||||||
|
headerbuf[2] = headerbuf[3];
|
||||||
|
|
||||||
|
if (dataStream->Read(&headerbuf[3], 1) != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorCount++ >= fr.m_Header.GetDataSize()) {
|
||||||
|
fr.m_Header.Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fr.m_Header.IsCRC()) {
|
||||||
|
if (dataStream->Read(crcbuf, 2) != 2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fr.m_CRC.Load(crcbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fr.m_Header.GetLayer() == LAYER3) {
|
||||||
|
unsigned count = fr.m_Header.GetSideInfoSize();
|
||||||
|
|
||||||
|
if (dataStream->Read(sideInfoBuffer, count) != count) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fr.m_SI.Load(&fr.m_Header, sideInfoBuffer)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned frameBytes = fr.m_Header.GetDataSize();
|
||||||
|
if (dataStream->Read(fr.m_Data, frameBytes) != frameBytes) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
MP3Decoder::~MP3Decoder(void)
|
MP3Decoder::MP3Decoder()
|
||||||
{
|
: m_pDecoder(NULL) {
|
||||||
Close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long MP3Decoder::GetID3HeaderLength(unsigned char * buffer)
|
MP3Decoder::~MP3Decoder() {
|
||||||
{
|
}
|
||||||
|
|
||||||
|
unsigned long MP3Decoder::GetID3HeaderLength(unsigned char * buffer) {
|
||||||
unsigned char VerMajor;
|
unsigned char VerMajor;
|
||||||
unsigned char VerMinor;
|
unsigned char VerMinor;
|
||||||
unsigned char Flags;
|
unsigned char Flags;
|
||||||
@ -22,7 +74,7 @@ unsigned long MP3Decoder::GetID3HeaderLength(unsigned char * buffer)
|
|||||||
|
|
||||||
if( (toupper(buffer[0]) == 'I') &&
|
if( (toupper(buffer[0]) == 'I') &&
|
||||||
(toupper(buffer[1]) == 'D') &&
|
(toupper(buffer[1]) == 'D') &&
|
||||||
(toupper(buffer[2]) == '3') )
|
(toupper(buffer[2]) == '3'))
|
||||||
{
|
{
|
||||||
VerMajor = buffer[3];
|
VerMajor = buffer[3];
|
||||||
VerMinor = buffer[4];
|
VerMinor = buffer[4];
|
||||||
@ -34,50 +86,55 @@ unsigned long MP3Decoder::GetID3HeaderLength(unsigned char * buffer)
|
|||||||
return(Length);
|
return(Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return(0);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MP3Decoder::GetXingHeader(unsigned char * XingBuffer)
|
bool MP3Decoder::GetXingHeader(unsigned char * xingBuffer) {
|
||||||
{
|
#define FRAMES_FLAG 0x0001
|
||||||
#define FRAMES_FLAG 0x0001
|
#define BYTES_FLAG 0x0002
|
||||||
#define BYTES_FLAG 0x0002
|
#define TOC_FLAG 0x0004
|
||||||
#define TOC_FLAG 0x0004
|
#define VBR_SCALE_FLAG 0x0008
|
||||||
#define VBR_SCALE_FLAG 0x0008
|
#define GET_INT32BE(b) (i = (b[0] << 24) | (b[1] << 16) | b[2] << 8 | b[3], b += 4, i) /* windows only? */
|
||||||
#define GET_INT32BE(b) (i = (b[0] << 24) | (b[1] << 16) | b[2] << 8 | b[3], b += 4, i)
|
|
||||||
|
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
m_bXingValid = false;
|
m_bXingValid = false;
|
||||||
|
|
||||||
if(strncmp((char *)XingBuffer, "Xing", 4))
|
if (strncmp((char *) xingBuffer, "Xing", 4)) {
|
||||||
if(strncmp((char *)XingBuffer, "Info", 4))
|
if (strncmp((char *)xingBuffer, "Info", 4)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
XingBuffer += 4;
|
xingBuffer += 4;
|
||||||
|
|
||||||
unsigned long HeadFlags = GET_INT32BE(XingBuffer);
|
unsigned long headFlags = GET_INT32BE(xingBuffer);
|
||||||
|
|
||||||
m_NumFrames = 0;
|
m_NumFrames = 0;
|
||||||
if(HeadFlags & FRAMES_FLAG)
|
if (headFlags & FRAMES_FLAG) {
|
||||||
m_NumFrames = GET_INT32BE(XingBuffer);
|
m_NumFrames = GET_INT32BE(xingBuffer);
|
||||||
if(m_NumFrames < 1)
|
}
|
||||||
return false;
|
|
||||||
|
if (m_NumFrames < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_StreamDataLength = 0;
|
m_StreamDataLength = 0;
|
||||||
if(HeadFlags & BYTES_FLAG)
|
if (headFlags & BYTES_FLAG) {
|
||||||
m_StreamDataLength = GET_INT32BE(XingBuffer);
|
m_StreamDataLength = GET_INT32BE(xingBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
if(HeadFlags & TOC_FLAG)
|
if (headFlags & TOC_FLAG) {
|
||||||
{
|
for (i = 0; i < 100; i++) {
|
||||||
for (i = 0; i < 100; i++)
|
m_TOC[i] = xingBuffer[i];
|
||||||
m_TOC[i] = XingBuffer[i];
|
}
|
||||||
XingBuffer += 100;
|
|
||||||
|
xingBuffer += 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_VbrScale = -1;
|
m_VbrScale = -1;
|
||||||
if(HeadFlags & VBR_SCALE_FLAG)
|
if (headFlags & VBR_SCALE_FLAG) {
|
||||||
{
|
m_VbrScale = GET_INT32BE(xingBuffer);
|
||||||
m_VbrScale = GET_INT32BE(XingBuffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_bXingValid = true;
|
m_bXingValid = true;
|
||||||
@ -85,205 +142,143 @@ bool MP3Decoder::GetXingHeader(unsigned char * XingBuffer)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MP3Decoder::GetStreamData(void)
|
bool MP3Decoder::GetStreamData() {
|
||||||
{
|
|
||||||
unsigned char tbuf[11];
|
unsigned char tbuf[11];
|
||||||
unsigned long bytesread;
|
unsigned long bytesread;
|
||||||
Frame fr;
|
Frame fr;
|
||||||
|
|
||||||
ReadFile(m_hFile, tbuf, 10, &bytesread, NULL);
|
this->dataStream->Read(tbuf, 10);
|
||||||
|
m_ID3v2Length = GetID3HeaderLength(tbuf);
|
||||||
|
this->dataStream->SetPosition(m_ID3v2Length);
|
||||||
|
|
||||||
m_ID3v2Length = GetID3HeaderLength(tbuf);
|
if(splitFrame(this->dataStream, fr)) {
|
||||||
SetFilePointer(m_hFile, m_ID3v2Length, NULL, FILE_BEGIN);
|
|
||||||
|
|
||||||
if(m_Splitter.Process(m_hFile, fr))
|
|
||||||
{
|
|
||||||
unsigned char * pHeader = fr.m_Data;
|
unsigned char * pHeader = fr.m_Data;
|
||||||
if(!GetXingHeader(pHeader))
|
if(!GetXingHeader(pHeader))
|
||||||
{
|
{
|
||||||
// analyse file here
|
// analyse file here
|
||||||
SetFilePointer(m_hFile, m_ID3v2Length, NULL, FILE_BEGIN);
|
this->dataStream->SetPosition(m_ID3v2Length);
|
||||||
// just guesstimate the number of frames!
|
|
||||||
|
// just guesstimate the number of frames!
|
||||||
|
/* DANGEROUS -- ASSUMES FINITE LENGTH*/
|
||||||
|
m_StreamDataLength = this->dataStream->Filesize() - m_ID3v2Length;
|
||||||
|
|
||||||
m_StreamDataLength = GetFileSize(m_hFile, NULL) - m_ID3v2Length;
|
|
||||||
// TODO: check for ID3 TAG at the end of the file and subtract
|
// TODO: check for ID3 TAG at the end of the file and subtract
|
||||||
// also remove the size of this current header
|
// also remove the size of this current header
|
||||||
m_StreamDataLength -= fr.m_Header.GetTotalFrameSize();
|
m_StreamDataLength -= fr.m_Header.GetTotalFrameSize();
|
||||||
|
|
||||||
m_NumFrames = m_StreamDataLength / fr.m_Header.GetTotalFrameSize();
|
m_NumFrames = m_StreamDataLength / fr.m_Header.GetTotalFrameSize();
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
if (m_bXingValid == false) {
|
||||||
if(m_bXingValid == false)
|
std::cout << "Mp3Decoder.cpp: Mp3 has Xing header but it is invalid.";
|
||||||
LogConsoleMessage(TEXT("MP3 Decoder"), TEXT("Mp3 has Xing header but it is invalid."));
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double bs[3] = { 384.0, 1152.0, 1152.0 };
|
double bs[3] = { 384.0, 1152.0, 1152.0 };
|
||||||
double TimePerFrame = (double)bs[fr.m_Header.GetLayer()] / (((double)fr.m_Header.GetSampleFrequency() / 1000.0));
|
double TimePerFrame = (double)bs[fr.m_Header.GetLayer()] / (((double)fr.m_Header.GetSampleFrequency() / 1000.0));
|
||||||
|
|
||||||
m_StreamLengthMS = TimePerFrame * m_NumFrames;
|
m_StreamLengthMS = TimePerFrame * m_NumFrames;
|
||||||
|
|
||||||
if(fr.m_Header.GetMpegVersion() != MPEG1)
|
if (fr.m_Header.GetMpegVersion() != MPEG1) {
|
||||||
m_StreamLengthMS /= 2;
|
m_StreamLengthMS /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
m_SampleRate = fr.m_Header.GetSampleFrequency();
|
m_SampleRate = fr.m_Header.GetSampleFrequency();
|
||||||
m_NumChannels = fr.m_Header.GetChannels();
|
m_NumChannels = fr.m_Header.GetChannels();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogConsoleMessage(TEXT("MP3 Decoder"), TEXT("Error calculating mp3 stream information."));
|
LogConsoleMessage(TEXT("MP3 Decoder"), TEXT("Error calculating mp3 stream information."));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MP3Decoder::Open(const utfchar* sourcePath)
|
bool MP3Decoder::Open(musik::core::io::IDataStream *dataStream) {
|
||||||
{
|
this->dataStream = dataStream;
|
||||||
m_LastLayer = -1;
|
this->m_LastLayer = -1;
|
||||||
|
return GetStreamData();
|
||||||
m_hFile = CreateFile( sourcePath,
|
|
||||||
GENERIC_READ,
|
|
||||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
||||||
NULL,
|
|
||||||
OPEN_EXISTING,
|
|
||||||
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if(m_hFile == INVALID_HANDLE_VALUE)
|
|
||||||
{
|
|
||||||
m_hFile = NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->sourcePath = sourcePath;
|
|
||||||
|
|
||||||
return GetStreamData();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MP3Decoder::Close(void)
|
void MP3Decoder::Destroy(void) {
|
||||||
{
|
delete this;
|
||||||
if(m_pDecoder)
|
|
||||||
{
|
|
||||||
delete m_pDecoder;
|
|
||||||
m_pDecoder = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_hFile)
|
|
||||||
{
|
|
||||||
CloseHandle(m_hFile);
|
|
||||||
m_hFile = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MP3Decoder::Destroy(void)
|
#define MP3_BUFFER_FLOAT_ALLOWANCE 2304 /* why? */
|
||||||
{
|
|
||||||
delete this;
|
bool MP3Decoder::GetBuffer(IBuffer *buffer) {
|
||||||
|
buffer->SetChannels(this->m_NumChannels);
|
||||||
|
buffer->SetSamples(MP3_BUFFER_FLOAT_ALLOWANCE / buffer->Channels());
|
||||||
|
buffer->SetSampleRate(this->m_SampleRate);
|
||||||
|
|
||||||
|
if (splitFrame(this->dataStream, m_Frame)) {
|
||||||
|
/* bail if the mpeg layer is incorrect*/
|
||||||
|
if ((m_Frame.m_Header.GetLayer() != m_LastLayer) || (m_pDecoder == NULL)) {
|
||||||
|
switch (m_Frame.m_Header.GetLayer()) {
|
||||||
|
case LAYER3: {
|
||||||
|
if (m_pDecoder) {
|
||||||
|
delete m_pDecoder;
|
||||||
|
m_pDecoder = NULL;
|
||||||
|
}
|
||||||
|
m_pDecoder = new CLayer3Decoder();
|
||||||
|
m_LastLayer = LAYER3;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
LogConsoleMessage(
|
||||||
|
L"MP3 Decoder",
|
||||||
|
L"Unsupported Layer (Only Layer 3 supported).");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long bufferCount = 0;
|
||||||
|
if (!m_pDecoder->ProcessFrame(&m_Frame, buffer->BufferPointer(), &bufferCount)) {
|
||||||
|
m_Frame.m_Header.Reset();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer->SetSamples(bufferCount / buffer->Channels());
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MP3Decoder::GetFormat(unsigned long * SampleRate, unsigned long * Channels)
|
double MP3Decoder::SetPosition(double seconds, double totalLength) {
|
||||||
{
|
float milliseconds = (float) seconds * 1000.0f;
|
||||||
*SampleRate = m_SampleRate;
|
float percent = 100.00f * ((float) milliseconds / (float) m_StreamLengthMS);
|
||||||
*Channels = m_NumChannels;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MP3Decoder::SetState(unsigned long State)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MP3Decoder::GetBuffer(float ** ppBuffer, unsigned long * NumSamples)
|
|
||||||
{
|
|
||||||
static float SampleBuffer[2304];
|
|
||||||
|
|
||||||
if(m_Splitter.Process(m_hFile, m_Frame))
|
|
||||||
{
|
|
||||||
if((m_Frame.m_Header.GetLayer() != m_LastLayer) || (m_pDecoder == NULL))
|
|
||||||
{
|
|
||||||
switch(m_Frame.m_Header.GetLayer())
|
|
||||||
{
|
|
||||||
case LAYER3:
|
|
||||||
{
|
|
||||||
if(m_pDecoder)
|
|
||||||
{
|
|
||||||
delete m_pDecoder;
|
|
||||||
m_pDecoder = NULL;
|
|
||||||
}
|
|
||||||
m_pDecoder = new CLayer3Decoder();
|
|
||||||
m_LastLayer = LAYER3;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
LogConsoleMessage(TEXT("MP3 Decoder"), TEXT("Unsupported Layer (Only Layer 3 supported)."));
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!m_pDecoder->ProcessFrame(&m_Frame, SampleBuffer, NumSamples))
|
|
||||||
{
|
|
||||||
*ppBuffer = NULL;
|
|
||||||
*NumSamples = 0;
|
|
||||||
|
|
||||||
m_Frame.m_Header.Reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
*ppBuffer = SampleBuffer;
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MP3Decoder::GetLength(unsigned long * MS)
|
|
||||||
{
|
|
||||||
*MS = m_StreamLengthMS;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool MP3Decoder::SetPosition(unsigned long * MS)
|
|
||||||
{
|
|
||||||
unsigned long newMS = *MS;
|
|
||||||
float percent = 100.00f * ((float)newMS / (float)m_StreamLengthMS);
|
|
||||||
unsigned long offset;
|
unsigned long offset;
|
||||||
|
|
||||||
if(m_bXingValid)
|
if (m_bXingValid)
|
||||||
{
|
{
|
||||||
/* interpolate in TOC to get file seek point in bytes */
|
/* interpolate in TOC to get file seek point in bytes */
|
||||||
int a;
|
int a = min(percent, 99);
|
||||||
float fa, fb, fx;
|
float fa, fb, fx;
|
||||||
|
|
||||||
a = min(percent, 99);
|
fa = m_TOC[a];
|
||||||
|
|
||||||
fa = m_TOC[a];
|
if (a < 99) {
|
||||||
|
fb = m_TOC[a + 1];
|
||||||
if (a < 99)
|
}
|
||||||
fb = m_TOC[a + 1];
|
else {
|
||||||
else
|
fb = 256;
|
||||||
fb = 256;
|
}
|
||||||
|
|
||||||
fx = fa + (fb - fa) * (percent - a);
|
fx = fa + (fb - fa) * (percent - a);
|
||||||
offset = (1.0f / 256.0f) * fx * m_StreamDataLength;
|
offset = (1.0f / 256.0f) * fx * m_StreamDataLength;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
offset = (float) m_StreamDataLength * (float)(percent/ 100.0f) ;
|
||||||
offset = (float)m_StreamDataLength * (float)(percent/ 100.0f) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetFilePointer(m_hFile, offset + m_ID3v2Length, NULL, FILE_BEGIN);
|
this->dataStream->SetPosition(offset + m_ID3v2Length);
|
||||||
|
bool result = splitFrame(this->dataStream, m_Frame);
|
||||||
|
|
||||||
m_Splitter.Process(m_hFile, m_Frame);
|
if (m_pDecoder) {
|
||||||
if(m_pDecoder)
|
|
||||||
{
|
|
||||||
delete m_pDecoder;
|
delete m_pDecoder;
|
||||||
m_pDecoder = NULL;
|
m_pDecoder = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return result ? seconds : -1;
|
||||||
}
|
}
|
||||||
|
@ -1,57 +1,46 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <core/audio/IAudioSource.h>
|
#include <core/sdk/IDecoder.h>
|
||||||
|
|
||||||
#include "FrameSplitter.h"
|
#include "FrameSplitter.h"
|
||||||
#include "Layer3Decoder.h"
|
#include "Layer3Decoder.h"
|
||||||
|
|
||||||
using namespace musik::core::audio;
|
using namespace musik::core::audio;
|
||||||
|
|
||||||
class MP3Decoder : public IAudioSource
|
class MP3Decoder : public IDecoder
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
CFrameSplitter m_Splitter;
|
|
||||||
Frame m_Frame;
|
|
||||||
IMPEGDecoder * m_pDecoder;
|
|
||||||
|
|
||||||
HANDLE m_hFile;
|
|
||||||
|
|
||||||
unsigned long m_LastLayer;
|
|
||||||
|
|
||||||
unsigned long m_SampleRate;
|
|
||||||
unsigned long m_NumChannels;
|
|
||||||
|
|
||||||
unsigned long m_ID3v2Length;
|
|
||||||
unsigned long m_StreamLengthMS;
|
|
||||||
unsigned long m_NumFrames;
|
|
||||||
unsigned long m_StreamDataLength;
|
|
||||||
unsigned long m_VbrScale;
|
|
||||||
unsigned char m_TOC[100];
|
|
||||||
|
|
||||||
bool m_bXingValid;
|
|
||||||
|
|
||||||
unsigned long GetID3HeaderLength(unsigned char * buffer);
|
|
||||||
bool GetXingHeader(unsigned char * XingBuffer);
|
|
||||||
bool GetStreamData(void);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
MP3Decoder(void);
|
MP3Decoder();
|
||||||
~MP3Decoder(void);
|
~MP3Decoder();
|
||||||
|
|
||||||
bool Open(const utfchar* sourcePath);
|
bool Open(musik::core::io::IDataStream *dataStream);
|
||||||
bool Close(void);
|
double SetPosition(double seconds, double totalLength);
|
||||||
void Destroy(void);
|
bool GetBuffer(IBuffer *buffer);
|
||||||
bool GetLength(unsigned long * MS);
|
void Destroy();
|
||||||
bool SetPosition(unsigned long * MS);
|
|
||||||
bool SetState(unsigned long State);
|
|
||||||
bool GetFormat(unsigned long * SampleRate, unsigned long * Channels);
|
|
||||||
bool GetBuffer(float ** ppBuffer, unsigned long * NumSamples);
|
|
||||||
|
|
||||||
const utfchar* GetSource() const { return sourcePath.c_str(); };
|
protected:
|
||||||
|
CFrameSplitter m_Splitter;
|
||||||
|
IMPEGDecoder *m_pDecoder;
|
||||||
|
Frame m_Frame;
|
||||||
|
|
||||||
|
unsigned long m_LastLayer;
|
||||||
|
unsigned long m_SampleRate;
|
||||||
|
unsigned long m_NumChannels;
|
||||||
|
unsigned long m_ID3v2Length;
|
||||||
|
unsigned long m_StreamLengthMS;
|
||||||
|
unsigned long m_NumFrames;
|
||||||
|
unsigned long m_StreamDataLength;
|
||||||
|
unsigned long m_VbrScale;
|
||||||
|
unsigned char m_TOC[100];
|
||||||
|
bool m_bXingValid;
|
||||||
|
|
||||||
|
unsigned long GetID3HeaderLength(unsigned char * buffer);
|
||||||
|
bool GetXingHeader(unsigned char * XingBuffer);
|
||||||
|
bool GetStreamData();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
utfstring sourcePath;
|
musik::core::io::IDataStream *dataStream;
|
||||||
|
|
||||||
// Stubs
|
// Stubs
|
||||||
void LogConsoleMessage(LPTSTR szModuleName, LPTSTR szMessage) {}; // TODO: replace with sigslot
|
void LogConsoleMessage(LPTSTR szModuleName, LPTSTR szMessage) {}; // TODO: replace with sigslot
|
||||||
|
@ -36,42 +36,36 @@
|
|||||||
#include "boost/algorithm/string.hpp"
|
#include "boost/algorithm/string.hpp"
|
||||||
#include "boost/filesystem.hpp"
|
#include "boost/filesystem.hpp"
|
||||||
|
|
||||||
#include "MP3SourceSupplier.h"
|
#include "Mp3DecoderFactory.h"
|
||||||
|
|
||||||
#include "MP3Decoder.h"
|
#include "MP3Decoder.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
MP3SourceSupplier::MP3SourceSupplier()
|
Mp3DecoderFactory::Mp3DecoderFactory() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MP3SourceSupplier::~MP3SourceSupplier()
|
Mp3DecoderFactory::~Mp3DecoderFactory() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MP3SourceSupplier::Destroy()
|
void Mp3DecoderFactory::Destroy() {
|
||||||
{
|
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
|
|
||||||
IAudioSource* MP3SourceSupplier::CreateAudioSource()
|
IDecoder* Mp3DecoderFactory::CreateDecoder() {
|
||||||
{
|
|
||||||
return new MP3Decoder();
|
return new MP3Decoder();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MP3SourceSupplier::CanHandle(const utfchar* source) const
|
bool Mp3DecoderFactory::CanHandle(const char* source) const
|
||||||
{
|
{
|
||||||
using namespace boost::filesystem;
|
std::string str(source);
|
||||||
using namespace boost::algorithm;
|
|
||||||
|
|
||||||
wpath sourcepath(source);
|
if (str.find("mp3") != std::string::npos ||
|
||||||
|
str.find("audio/mpeg3") != std::string::npos ||
|
||||||
|
str.find("audio/x-mpeg-3") != std::string::npos ||
|
||||||
|
str.find("audio/mp3") != std::string::npos)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_regular(sourcepath))
|
return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
if (to_lower_copy(extension(sourcepath)) != TEXT(".mp3"))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
@ -33,16 +33,17 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <core\audio\IAudioSource.h>
|
#include <core\sdk\IDecoderFactory.h>
|
||||||
|
|
||||||
using namespace musik::core::audio;
|
using namespace musik::core::audio;
|
||||||
|
|
||||||
class MP3SourceSupplier : public IAudioSourceSupplier
|
class Mp3DecoderFactory : public IDecoderFactory
|
||||||
{
|
{
|
||||||
public: MP3SourceSupplier();
|
public:
|
||||||
public: ~MP3SourceSupplier();
|
Mp3DecoderFactory();
|
||||||
|
~Mp3DecoderFactory();
|
||||||
|
|
||||||
public: IAudioSource* CreateAudioSource();
|
IDecoder* CreateDecoder();
|
||||||
public: void Destroy();
|
void Destroy();
|
||||||
public: bool CanHandle(const utfchar* source) const;
|
bool CanHandle(const char* type) const;
|
||||||
};
|
};
|
@ -53,7 +53,7 @@
|
|||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<Optimization>Disabled</Optimization>
|
<Optimization>Disabled</Optimization>
|
||||||
<AdditionalIncludeDirectories>.;../..;../../3rdparty/include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
<AdditionalIncludeDirectories>.;../..;../../3rdparty/include;../../../../boost_1_60_0;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<MinimalRebuild>false</MinimalRebuild>
|
<MinimalRebuild>false</MinimalRebuild>
|
||||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||||
@ -65,7 +65,7 @@
|
|||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<AdditionalLibraryDirectories>../../3rdparty/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
<AdditionalLibraryDirectories>../../3rdparty/lib;../../../../boost_1_60_0/lib32-msvc-14.0;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
@ -94,7 +94,7 @@
|
|||||||
<ClCompile Include="SideInfo.cpp" />
|
<ClCompile Include="SideInfo.cpp" />
|
||||||
<ClCompile Include="MP3Decoder.cpp" />
|
<ClCompile Include="MP3Decoder.cpp" />
|
||||||
<ClCompile Include="mp3decoder_plugin.cpp" />
|
<ClCompile Include="mp3decoder_plugin.cpp" />
|
||||||
<ClCompile Include="MP3SourceSupplier.cpp" />
|
<ClCompile Include="Mp3DecoderFactory.cpp" />
|
||||||
<ClCompile Include="stdafx.cpp" />
|
<ClCompile Include="stdafx.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -110,7 +110,7 @@
|
|||||||
<ClInclude Include="resource.h" />
|
<ClInclude Include="resource.h" />
|
||||||
<ClInclude Include="SideInfo.h" />
|
<ClInclude Include="SideInfo.h" />
|
||||||
<ClInclude Include="MP3Decoder.h" />
|
<ClInclude Include="MP3Decoder.h" />
|
||||||
<ClInclude Include="MP3SourceSupplier.h" />
|
<ClInclude Include="Mp3DecoderFactory.h" />
|
||||||
<ClInclude Include="stdafx.h" />
|
<ClInclude Include="stdafx.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -35,31 +35,26 @@
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
|
#include <core/sdk/IPlugin.h>
|
||||||
|
#include <core/sdk/IDecoder.h>
|
||||||
|
#include "Mp3DecoderFactory.h"
|
||||||
|
|
||||||
#include "core/IPlugin.h"
|
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved) {
|
||||||
|
|
||||||
#include "MP3SourceSupplier.h"
|
|
||||||
|
|
||||||
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MP3DecoderPlugin : public musik::core::IPlugin
|
class MP3DecoderPlugin : public musik::core::IPlugin
|
||||||
{
|
{
|
||||||
void Destroy() { delete this; };
|
void Destroy() { delete this; }
|
||||||
|
const char* Name() { return "MP3 decoder"; };
|
||||||
const utfchar* Name() { return TEXT("MP3 decoder"); };
|
const char* Version() { return "1"; };
|
||||||
const utfchar* Version() { return TEXT("1"); };
|
const char* Author() { return "Björn Olievier"; };
|
||||||
const utfchar* Author() { return TEXT("Björn Olievier"); };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) musik::core::IPlugin* GetPlugin()
|
extern "C" __declspec(dllexport) musik::core::IPlugin* GetPlugin() {
|
||||||
{
|
|
||||||
return new MP3DecoderPlugin();
|
return new MP3DecoderPlugin();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) IAudioSourceSupplier* CreateAudioSourceSupplier()
|
extern "C" __declspec(dllexport) IDecoderFactory* GetDecoderFactory() {
|
||||||
{
|
return new Mp3DecoderFactory();
|
||||||
return new MP3SourceSupplier();
|
|
||||||
}
|
}
|
||||||
|
@ -51,21 +51,22 @@ IDecoder* OggDecoderFactory::CreateDecoder() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool OggDecoderFactory::CanHandle(const char* type) const {
|
bool OggDecoderFactory::CanHandle(const char* type) const {
|
||||||
if (type) {
|
std::string typeString(type);
|
||||||
std::string typeString(type);
|
|
||||||
|
|
||||||
if (typeString.find("ogg") != std::string::npos) {
|
if (typeString.find("ogg") != std::string::npos) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (typeString.find("oga") != std::string::npos) {
|
|
||||||
return true;
|
if (typeString.find("oga") != std::string::npos) {
|
||||||
}
|
return true;
|
||||||
if (typeString.find("audio/ogg") != std::string::npos) {
|
}
|
||||||
return true;
|
|
||||||
}
|
if (typeString.find("audio/ogg") != std::string::npos) {
|
||||||
if (typeString.find("audio/vorbis") != std::string::npos) {
|
return true;
|
||||||
return true;
|
}
|
||||||
}
|
|
||||||
|
if (typeString.find("audio/vorbis") != std::string::npos) {
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -81,6 +81,8 @@ void WaveOut::SetVolume(double volume) {
|
|||||||
void WaveOut::Stop() {
|
void WaveOut::Stop() {
|
||||||
boost::recursive_mutex::scoped_lock lock(this->outputDeviceMutex);
|
boost::recursive_mutex::scoped_lock lock(this->outputDeviceMutex);
|
||||||
|
|
||||||
|
/* reset waveout first. if we don't do this, it seems like it'll still
|
||||||
|
try to send events to the thread, and fail with a runtime exception. */
|
||||||
if (this->waveHandle != NULL) {
|
if (this->waveHandle != NULL) {
|
||||||
waveOutReset(this->waveHandle);
|
waveOutReset(this->waveHandle);
|
||||||
}
|
}
|
||||||
@ -88,7 +90,7 @@ void WaveOut::Stop() {
|
|||||||
/* stop the thread so nothing else is processed */
|
/* stop the thread so nothing else is processed */
|
||||||
this->StopWaveOutThread();
|
this->StopWaveOutThread();
|
||||||
|
|
||||||
/* reset will free the buffers, close deallocs */
|
/* dealloc the handle, we'll create a new one later if we need to... */
|
||||||
if (this->waveHandle != NULL) {
|
if (this->waveHandle != NULL) {
|
||||||
waveOutClose(this->waveHandle);
|
waveOutClose(this->waveHandle);
|
||||||
this->waveHandle = NULL;
|
this->waveHandle = NULL;
|
||||||
|
@ -148,7 +148,7 @@ void Buffer::CopyFormat(BufferPtr fromBuffer) {
|
|||||||
void Buffer::ResizeBuffer() {
|
void Buffer::ResizeBuffer() {
|
||||||
long requiredBufferSize = this->sampleSize * this->channels;
|
long requiredBufferSize = this->sampleSize * this->channels;
|
||||||
if (requiredBufferSize > this->internalBufferSize) {
|
if (requiredBufferSize > this->internalBufferSize) {
|
||||||
if(this->buffer) {
|
if (this->buffer) {
|
||||||
delete this->buffer;
|
delete this->buffer;
|
||||||
this->buffer = NULL;
|
this->buffer = NULL;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ namespace musik { namespace core { namespace io {
|
|||||||
///\returns
|
///\returns
|
||||||
///how much has acctually been read
|
///how much has acctually been read
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual PositionType Read(void* buffer, PositionType readBytes) = 0;
|
virtual PositionType Read(void *buffer, PositionType readBytes) = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
|
@ -52,7 +52,7 @@ class IDecoder{
|
|||||||
///The Destroy method is used so that it's guaranteed that the object is
|
///The Destroy method is used so that it's guaranteed that the object is
|
||||||
///destroyed inside the right DLL/exe
|
///destroyed inside the right DLL/exe
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual void Destroy() = 0;
|
virtual void Destroy() = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
@ -61,7 +61,7 @@ class IDecoder{
|
|||||||
///\returns
|
///\returns
|
||||||
///The actual position set
|
///The actual position set
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual double SetPosition(double seconds,double totalLength) = 0;
|
virtual double SetPosition(double seconds, double totalLength) = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
@ -70,7 +70,7 @@ class IDecoder{
|
|||||||
///\returns
|
///\returns
|
||||||
///false is there is nothing left
|
///false is there is nothing left
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual bool GetBuffer(IBuffer *buffer) = 0; // return false to signal that we are done decoding.
|
virtual bool GetBuffer(IBuffer *buffer) = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
|
@ -51,21 +51,20 @@ class IDecoderFactory{
|
|||||||
///\brief
|
///\brief
|
||||||
///Create a instance of the decoder
|
///Create a instance of the decoder
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual IDecoder* CreateDecoder() = 0;
|
virtual IDecoder* CreateDecoder() = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
///Destroy the object
|
///Destroy the object
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual void Destroy() = 0;
|
virtual void Destroy() = 0;
|
||||||
|
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
///\brief
|
///\brief
|
||||||
///Can this plugin handle this kind of filetype?
|
///Can this plugin handle this kind of filetype?
|
||||||
///The "type" can either be a file extension or a mimetype
|
///The "type" can either be a file extension or a mimetype
|
||||||
//////////////////////////////////////////
|
//////////////////////////////////////////
|
||||||
virtual bool CanHandle(const char* type) const = 0;
|
virtual bool CanHandle(const char* type) const = 0;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -85,6 +85,8 @@ void ConsoleUI::Run()
|
|||||||
{
|
{
|
||||||
std::string command;
|
std::string command;
|
||||||
|
|
||||||
|
transport.SetVolume(0.1);
|
||||||
|
|
||||||
while (!this->shouldQuit)
|
while (!this->shouldQuit)
|
||||||
{
|
{
|
||||||
this->PrintCommands();
|
this->PrintCommands();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user