From a9a8e1c3a5f957d61325b328578c536181b87cde Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 15 Jul 2009 14:43:56 -0700 Subject: [PATCH] sampleBuffer::decodeSampleMp3 implemented AudioFileProcessor can now open MP3 samples. --- include/lame_library.h | 14 ++++ include/sample_buffer.h | 2 + src/core/lame_library.cpp | 18 ++++- src/core/sample_buffer.cpp | 130 +++++++++++++++++++++++++++++++++---- 4 files changed, 151 insertions(+), 13 deletions(-) diff --git a/include/lame_library.h b/include/lame_library.h index 322546a74..28d51cca4 100644 --- a/include/lame_library.h +++ b/include/lame_library.h @@ -84,6 +84,14 @@ class LameLibrary { typedef int lame_set_VBR_mean_bitrate_kbps_t(lame_global_flags *, int); typedef int lame_set_VBR_max_bitrate_kbps_t(lame_global_flags *, int); + typedef int lame_decode_init_t(void); + typedef int lame_decode1_headers_t(unsigned char *, int, short *, + short *, mp3data_struct *); + typedef int lame_decode_headers_t(unsigned char *, int, short *, + short *, mp3data_struct *); + typedef int lame_decode_t(unsigned char *, int, short *, short *); + typedef int lame_decode_exit_t(void); + public: @@ -123,6 +131,12 @@ class LameLibrary { lame_set_VBR_mean_bitrate_kbps_t *lame_set_VBR_mean_bitrate_kbps; lame_set_VBR_max_bitrate_kbps_t *lame_set_VBR_max_bitrate_kbps; + lame_decode_init_t *lame_decode_init; + lame_decode1_headers_t *lame_decode1_headers; + lame_decode_headers_t *lame_decode_headers; + lame_decode_t *lame_decode; + lame_decode_exit_t *lame_decode_exit; + private: QLibrary * m_lameLib; // lame .so file diff --git a/include/sample_buffer.h b/include/sample_buffer.h index 6dbfa07ff..63976796b 100644 --- a/include/sample_buffer.h +++ b/include/sample_buffer.h @@ -222,6 +222,8 @@ private: ch_cnt_t & _channels, sample_rate_t & _sample_rate ); + f_cnt_t decodeSampleMp3( QString & file, int_sample_t * & _buf, + ch_cnt_t & _channels, sample_rate_t & _samplerate ); QString m_audioFile; sampleFrame * m_origData; diff --git a/src/core/lame_library.cpp b/src/core/lame_library.cpp index 01a6a7ff2..2d9bb31c4 100644 --- a/src/core/lame_library.cpp +++ b/src/core/lame_library.cpp @@ -102,6 +102,17 @@ LameLibrary::LameLibrary() : lame_set_VBR_max_bitrate_kbps = (lame_set_VBR_max_bitrate_kbps_t *) m_lameLib->resolve("lame_set_VBR_max_bitrate_kbps"); + lame_decode_init = (lame_decode_init_t*) + m_lameLib->resolve("lame_decode_init"); + lame_decode1_headers = (lame_decode1_headers_t*) + m_lameLib->resolve("lame_decode1_headers"); + lame_decode_headers = (lame_decode_headers_t*) + m_lameLib->resolve("lame_decode_headers"); + lame_decode = (lame_decode_t*) + m_lameLib->resolve("lame_decode"); + lame_decode_exit = (lame_decode_exit_t*) + m_lameLib->resolve("lame_decode_exit"); + // These are optional lame_get_lametag_frame = (lame_get_lametag_frame_t *) m_lameLib->resolve("lame_get_lametag_frame"); @@ -131,7 +142,12 @@ LameLibrary::LameLibrary() : !lame_set_findReplayGain || !lame_set_VBR_quality || !lame_set_VBR_mean_bitrate_kbps || - !lame_set_VBR_max_bitrate_kbps) + !lame_set_VBR_max_bitrate_kbps || + !lame_decode_init || + !lame_decode1_headers || + !lame_decode_headers || + !lame_decode || + !lame_decode_exit) { // some symbols are missing QMessageBox::information( NULL, QObject::tr( "LAME missing symbols" ), diff --git a/src/core/sample_buffer.cpp b/src/core/sample_buffer.cpp index 3122bf7fe..a5ee555c9 100644 --- a/src/core/sample_buffer.cpp +++ b/src/core/sample_buffer.cpp @@ -63,6 +63,7 @@ #include "interpolation.h" #include "templates.h" +#include "lame_library.h" sampleBuffer::sampleBuffer( const QString & _audio_file, @@ -194,23 +195,19 @@ void sampleBuffer::update( bool _keep_settings ) } else { + // PCM wave if( m_frames == 0 ) - { - m_frames = decodeSampleSF( f, buf, channels, - samplerate ); - } + m_frames = decodeSampleSF( f, buf, channels, samplerate ); #ifdef LMMS_HAVE_OGGVORBIS if( m_frames == 0 ) - { - m_frames = decodeSampleOGGVorbis( f, buf, channels, - samplerate ); - } + m_frames = decodeSampleOGGVorbis(f, buf, channels, samplerate); #endif if( m_frames == 0 ) - { - m_frames = decodeSampleDS( f, buf, channels, - samplerate ); - } + m_frames = decodeSampleDS( f, buf, channels, samplerate ); + + // MP3 + if( m_frames == 0 ) + m_frames = decodeSampleMp3( file, buf, channels, samplerate ); delete[] f; } @@ -502,6 +499,115 @@ f_cnt_t sampleBuffer::decodeSampleOGGVorbis( const char * _f, #endif +int lame_decode_fromfile(QFile &in, short pcm_l[], short pcm_r[], + mp3data_struct * mp3data, LameLibrary &lame) +{ + int ret = 0; + size_t len = 0; + unsigned char buf[1024]; + + /* first see if we still have data buffered in the decoder: */ + ret = lame.lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); + if (ret != 0) + return ret; + + + /* read until we get a valid output frame */ + while (1) { + len = in.read((char *)buf, 1024); + if (len == 0) { + /* we are done reading the file, but check for buffered data */ + ret = lame.lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); + if (ret <= 0) { + //lame.lame_decode_exit(); /* release mp3decoder memory */ + //return -1; /* done with file */ + + return 0; + } + break; + } + + ret = lame.lame_decode1_headers(buf, len, pcm_l, pcm_r, mp3data); + if (ret == -1) { + lame.lame_decode_exit(); /* release mp3decoder memory */ + return -1; + } + if (ret > 0) + break; + } + return ret; +} + +f_cnt_t sampleBuffer::decodeSampleMp3( QString & file, int_sample_t * & _buf, + ch_cnt_t & _channels, sample_rate_t & _samplerate ) +{ + // create instance of LameLibrary to decode + LameLibrary lame; + + // open the file + QFile in(file); + + if( ! in.open(QIODevice::ReadOnly) ){ + printf("sampleBuffer::decodeSampleMp3: error opening %s for reading\n", + file.toStdString().c_str()); + return 0; + } + + // initialize lame decoder + lame.lame_decode_init(); + + short int pcm_l[1152]; + short int pcm_r[1152]; + mp3data_struct mp3data; + + // TODO: calc _buf size + + int bufPos = 0; + bool initBuf = false; + + while(1) + { + int ret = lame_decode_fromfile(in, pcm_l, pcm_r, &mp3data, lame); + + if( ret == -1 ){ + delete[] _buf; + printf("error decoding mp3\n"); + return 0; + } else if( ret == 0 ) { + break; + } + + if( ! initBuf ) + { + if( mp3data.header_parsed == 0 ) + { + printf("failed to parse header\n"); + return 0; + } + else + { + // process header + _samplerate = mp3data.samplerate; + _channels = mp3data.stereo; + _buf = new int_sample_t[mp3data.totalframes * + mp3data.framesize * _channels]; + initBuf = true; + } + } + + // convert the decoded PCM into sample + for(int i = 0; i