[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Traverso-commit] traverso traverso.pro src/core/core.pro src/tra...
From: |
Ben Levitt |
Subject: |
[Traverso-commit] traverso traverso.pro src/core/core.pro src/tra... |
Date: |
Tue, 31 Jul 2007 18:45:16 +0000 |
CVSROOT: /sources/traverso
Module name: traverso
Changes by: Ben Levitt <benjie> 07/07/31 18:45:15
Modified files:
. : traverso.pro
src/core : core.pro
src/traverso : traverso.pro
Added files:
src/audiofileio: audiofileio.pro
src/audiofileio/decode: AbstractAudioReader.cpp
AbstractAudioReader.h
FlacAudioReader.cpp FlacAudioReader.h
MadAudioReader.cpp MadAudioReader.h
ResampleAudioReader.cpp
ResampleAudioReader.h SFAudioReader.cpp
SFAudioReader.h VorbisAudioReader.cpp
VorbisAudioReader.h WPAudioReader.cpp
WPAudioReader.h
Removed files:
src/core : AbstractAudioReader.cpp AbstractAudioReader.h
FlacAudioReader.cpp FlacAudioReader.h
MadAudioReader.cpp MadAudioReader.h
ResampleAudioReader.cpp ResampleAudioReader.h
SFAudioReader.cpp SFAudioReader.h
VorbisAudioReader.cpp VorbisAudioReader.h
WPAudioReader.cpp WPAudioReader.h
Log message:
move AudioReaders to src/audiofileio/decode
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/traverso/traverso.pro?cvsroot=traverso&r1=1.8&r2=1.9
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/audiofileio.pro?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/AbstractAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/AbstractAudioReader.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/FlacAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/FlacAudioReader.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/MadAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/MadAudioReader.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/ResampleAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/ResampleAudioReader.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/SFAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/SFAudioReader.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/VorbisAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/VorbisAudioReader.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/WPAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/audiofileio/decode/WPAudioReader.h?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/core.pro?cvsroot=traverso&r1=1.36&r2=1.37
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/AbstractAudioReader.cpp?cvsroot=traverso&r1=1.15&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/AbstractAudioReader.h?cvsroot=traverso&r1=1.13&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/FlacAudioReader.cpp?cvsroot=traverso&r1=1.13&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/FlacAudioReader.h?cvsroot=traverso&r1=1.5&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/MadAudioReader.cpp?cvsroot=traverso&r1=1.16&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/MadAudioReader.h?cvsroot=traverso&r1=1.6&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/ResampleAudioReader.cpp?cvsroot=traverso&r1=1.15&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/ResampleAudioReader.h?cvsroot=traverso&r1=1.11&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/SFAudioReader.cpp?cvsroot=traverso&r1=1.9&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/SFAudioReader.h?cvsroot=traverso&r1=1.6&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/VorbisAudioReader.cpp?cvsroot=traverso&r1=1.12&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/VorbisAudioReader.h?cvsroot=traverso&r1=1.7&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/WPAudioReader.cpp?cvsroot=traverso&r1=1.6&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/WPAudioReader.h?cvsroot=traverso&r1=1.4&r2=0
http://cvs.savannah.gnu.org/viewcvs/traverso/src/traverso/traverso.pro?cvsroot=traverso&r1=1.64&r2=1.65
Patches:
Index: traverso.pro
===================================================================
RCS file: /sources/traverso/traverso/traverso.pro,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -b -r1.8 -r1.9
--- traverso.pro 14 May 2007 04:29:18 -0000 1.8
+++ traverso.pro 31 Jul 2007 18:45:11 -0000 1.9
@@ -9,6 +9,7 @@
SUBDIRS += src/engine \
src/commands \
src/core \
+ src/audiofileio \
src/plugins \
src/traverso/songcanvas \
src/commands/plugins/TraversoCommands \
Index: src/core/core.pro
===================================================================
RCS file: /sources/traverso/traverso/src/core/core.pro,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -b -r1.36 -r1.37
--- src/core/core.pro 19 Jul 2007 05:25:59 -0000 1.36
+++ src/core/core.pro 31 Jul 2007 18:45:15 -0000 1.37
@@ -7,6 +7,8 @@
INCLUDEPATH += ../commands \
../engine \
+ ../audiofileio/decode \
+ ../audiofileio/encode \
../plugins \
../plugins/native
@@ -49,14 +51,7 @@
Snappable.cpp \
TimeLine.cpp \
Marker.cpp \
- Themer.cpp \
- AbstractAudioReader.cpp \
- SFAudioReader.cpp \
- FlacAudioReader.cpp \
- ResampleAudioReader.cpp \
- VorbisAudioReader.cpp \
- WPAudioReader.cpp \
- MadAudioReader.cpp
+ Themer.cpp
HEADERS = precompile.h \
AudioClip.h \
AudioClipList.h \
@@ -99,14 +94,7 @@
CommandPlugin.h \
TimeLine.h \
Marker.h \
- Themer.h \
- AbstractAudioReader.h \
- SFAudioReader.h \
- FlacAudioReader.h \
- ResampleAudioReader.h \
- VorbisAudioReader.h \
- WPAudioReader.h \
- MadAudioReader.h
+ Themer.h
macx{
QMAKE_LIBDIR += /usr/local/qt/lib
}
@@ -114,7 +102,3 @@
win32{
INCLUDEPATH += ../../3thparty/include .
}
-SOURCES -= MonoReader.cpp
-
-HEADERS -= MonoReader.h
-
Index: src/traverso/traverso.pro
===================================================================
RCS file: /sources/traverso/traverso/src/traverso/traverso.pro,v
retrieving revision 1.64
retrieving revision 1.65
diff -u -b -r1.64 -r1.65
--- src/traverso/traverso.pro 25 Jul 2007 00:52:32 -0000 1.64
+++ src/traverso/traverso.pro 31 Jul 2007 18:45:15 -0000 1.65
@@ -16,6 +16,7 @@
LIBS += \
-ltraversosongcanvas \
-ltraversocore \
+ -ltraversoaudiofileio \
-ltraversocommands \
-ltraversoaudiobackend \
-ltraversoplugins \
@@ -25,7 +26,7 @@
-lmad \
-lwavpack \
-lFLAC \
- -lfftw3 \
+ -lfftw3
HEADERS += \
BusMonitor.h \
@@ -114,6 +115,8 @@
INCLUDEPATH += ../core \
../commands \
../engine \
+ ../audiofileio/decode \
+ ../audiofileio/encode \
../plugins \
../plugins/LV2 \
../plugins/native \
Index: src/audiofileio/audiofileio.pro
===================================================================
RCS file: src/audiofileio/audiofileio.pro
diff -N src/audiofileio/audiofileio.pro
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/audiofileio.pro 31 Jul 2007 18:45:12 -0000 1.1
@@ -0,0 +1,33 @@
+include(../libbase.pri)
+
+INCLUDEPATH += decode encode \
+ ../core \
+ ../engine
+
+QMAKE_LIBDIR = ../../lib
+TARGET = traversoaudiofileio
+DESTDIR = ../../lib
+
+TEMPLATE = lib
+
+SOURCES = decode/AbstractAudioReader.cpp \
+ decode/SFAudioReader.cpp \
+ decode/FlacAudioReader.cpp \
+ decode/ResampleAudioReader.cpp \
+ decode/VorbisAudioReader.cpp \
+ decode/WPAudioReader.cpp \
+ decode/MadAudioReader.cpp
+HEADERS = decode/AbstractAudioReader.h \
+ decode/SFAudioReader.h \
+ decode/FlacAudioReader.h \
+ decode/ResampleAudioReader.h \
+ decode/VorbisAudioReader.h \
+ decode/WPAudioReader.h \
+ decode/MadAudioReader.h
+macx{
+ QMAKE_LIBDIR += /usr/local/qt/lib
+}
+
+win32{
+ INCLUDEPATH += ../../3thparty/include .
+}
Index: src/audiofileio/decode/AbstractAudioReader.cpp
===================================================================
RCS file: src/audiofileio/decode/AbstractAudioReader.cpp
diff -N src/audiofileio/decode/AbstractAudioReader.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/AbstractAudioReader.cpp 31 Jul 2007 18:45:12
-0000 1.1
@@ -0,0 +1,153 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "AbstractAudioReader.h"
+#include "SFAudioReader.h"
+#include "FlacAudioReader.h"
+#include "MadAudioReader.h"
+#include "WPAudioReader.h"
+#include "VorbisAudioReader.h"
+#include "ResampleAudioReader.h"
+
+#include <QString>
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+AbstractAudioReader::AbstractAudioReader(const QString& filename)
+ : QObject(0)
+{
+ m_fileName = filename;
+ m_readPos = 0;
+}
+
+
+AbstractAudioReader::~AbstractAudioReader()
+{
+}
+
+
+// Read cnt frames starting at start from the AudioReader, into dst
+// uses seek() and read() from AudioReader subclass
+nframes_t AbstractAudioReader::read_from(audio_sample_t** buffer, nframes_t
start, nframes_t count)
+{
+// printf("read_from:: before_seek from %d, framepos is %d\n", start,
m_readPos);
+
+ if (!seek(start)) {
+ return 0;
+ }
+
+ return read(buffer, count);
+}
+
+
+int AbstractAudioReader::get_num_channels()
+{
+ return m_channels;
+}
+
+
+nframes_t AbstractAudioReader::get_length()
+{
+ return m_length;
+}
+
+
+int AbstractAudioReader::get_file_rate()
+{
+ return m_rate;
+}
+
+
+bool AbstractAudioReader::eof()
+{
+ return (m_readPos >= m_length);
+}
+
+
+nframes_t AbstractAudioReader::pos()
+{
+ return m_readPos;
+}
+
+
+bool AbstractAudioReader::seek(nframes_t start)
+{
+ if (m_readPos != start) {
+ if (!seek_private(start)) {
+ return false;
+ }
+ m_readPos = start;
+ }
+
+ return true;
+}
+
+
+nframes_t AbstractAudioReader::read(audio_sample_t** buffer, nframes_t count)
+{
+ if (count && m_readPos < m_length) {
+ // printf("read_from:: after_seek from %d, framepos is %d\n",
start, m_readPos);
+ nframes_t framesRead = read_private(buffer, count);
+
+ m_readPos += framesRead;
+
+ return framesRead;
+ }
+
+ return 0;
+}
+
+
+// Static method used by other classes to get an AudioReader for the correct
file type
+AbstractAudioReader* AbstractAudioReader::create_audio_reader(const QString&
filename)
+{
+ AbstractAudioReader* newReader;
+
+ if (FlacAudioReader::can_decode(filename)) {
+ newReader = new FlacAudioReader(filename);
+ }
+ else if (VorbisAudioReader::can_decode(filename)) {
+ newReader = new VorbisAudioReader(filename);
+ }
+ else if (WPAudioReader::can_decode(filename)) {
+ newReader = new WPAudioReader(filename);
+ }
+ else if (SFAudioReader::can_decode(filename)) {
+ newReader = new SFAudioReader(filename);
+ }
+ else if (MadAudioReader::can_decode(filename)) {
+ newReader = new MadAudioReader(filename);
+ }
+ else {
+ return 0;
+ }
+
+ if (newReader->get_num_channels() <= 0) {
+ PERROR("new reader has 0 channels!");
+ return 0;
+ }
+
+ return newReader;
+}
+
Index: src/audiofileio/decode/AbstractAudioReader.h
===================================================================
RCS file: src/audiofileio/decode/AbstractAudioReader.h
diff -N src/audiofileio/decode/AbstractAudioReader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/AbstractAudioReader.h 31 Jul 2007 18:45:12
-0000 1.1
@@ -0,0 +1,63 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef ABSTRACTAUDIOREADER_H
+#define ABSTRACTAUDIOREADER_H
+
+#include <QObject>
+
+#include "defines.h"
+
+class QString;
+
+class AbstractAudioReader : public QObject
+{
+ Q_OBJECT
+
+public:
+ AbstractAudioReader(const QString& filename);
+ ~AbstractAudioReader();
+
+ int get_num_channels();
+ nframes_t get_length();
+ int get_file_rate();
+ bool eof();
+ nframes_t pos();
+
+ nframes_t read_from(audio_sample_t** buffer, nframes_t start, nframes_t
count);
+ bool seek(nframes_t start);
+ nframes_t read(audio_sample_t** buffer, nframes_t frameCount);
+
+ static AbstractAudioReader* create_audio_reader(const QString&
filename);
+
+protected:
+ virtual bool seek_private(nframes_t start) = 0;
+ virtual nframes_t read_private(audio_sample_t** buffer, nframes_t
frameCount) = 0;
+
+ QString m_fileName;
+
+ nframes_t m_readPos;
+ nframes_t m_channels;
+ nframes_t m_length;
+ nframes_t m_rate;
+};
+
+#endif
Index: src/audiofileio/decode/FlacAudioReader.cpp
===================================================================
RCS file: src/audiofileio/decode/FlacAudioReader.cpp
diff -N src/audiofileio/decode/FlacAudioReader.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/FlacAudioReader.cpp 31 Jul 2007 18:45:12 -0000
1.1
@@ -0,0 +1,572 @@
+/*
+Copyright (C) 2007 Ben Levitt
+ * Based on the FLAC decoder module for K3b.
+ * Based on the Ogg Vorbis module for same.
+ * Copyright (C) 1998-2007 Sebastian Trueg <address@hidden>
+ * Copyright (C) 2003-2004 John Steele Scott <address@hidden>
+
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "FlacAudioReader.h"
+#include <QFile>
+#include <QString>
+
+#include "FLAC/export.h"
+
+#if !defined FLAC_API_VERSION_CURRENT || FLAC_API_VERSION_CURRENT < 6
+#define LEGACY_FLAC
+#include "FLAC/seekable_stream_decoder.h"
+#else
+#undef LEGACY_FLAC
+#include "FLAC/stream_decoder.h"
+#endif
+
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+class FlacPrivate
+{
+ public:
+ FlacPrivate(QString filename)
+ {
+ internalBuffer = 0;
+ bufferSize = 0;
+ bufferUsed = 0;
+ bufferStart = 0;
+ open(filename);
+ }
+
+
+ ~FlacPrivate()
+ {
+ cleanup();
+ }
+
+
+ bool open(QString filename)
+ {
+ file = new QFile(filename);
+ if (!file->open(QIODevice::ReadOnly)) {
+ return false;
+ }
+
+#ifdef LEGACY_FLAC
+ flac = FLAC__seekable_stream_decoder_new();
+
+ FLAC__seekable_stream_decoder_set_read_callback(flac,
FlacPrivate::read_callback);
+ FLAC__seekable_stream_decoder_set_seek_callback(flac,
FlacPrivate::seek_callback);
+ FLAC__seekable_stream_decoder_set_tell_callback(flac,
FlacPrivate::tell_callback);
+ FLAC__seekable_stream_decoder_set_length_callback(flac,
FlacPrivate::length_callback);
+ FLAC__seekable_stream_decoder_set_eof_callback(flac,
FlacPrivate::eof_callback);
+ FLAC__seekable_stream_decoder_set_write_callback(flac,
FlacPrivate::write_callback);
+
FLAC__seekable_stream_decoder_set_metadata_callback(flac,
FlacPrivate::metadata_callback);
+ FLAC__seekable_stream_decoder_set_error_callback(flac,
FlacPrivate::error_callback);
+ FLAC__seekable_stream_decoder_set_client_data(flac,
this);
+
+ FLAC__seekable_stream_decoder_init(flac);
+
FLAC__seekable_stream_decoder_process_until_end_of_metadata(flac);
+#else
+ flac = FLAC__stream_decoder_new();
+
+ FLAC__stream_decoder_init_stream(flac,
+ FlacPrivate::read_callback,
+ FlacPrivate::seek_callback,
+ FlacPrivate::tell_callback,
+ FlacPrivate::length_callback,
+ FlacPrivate::eof_callback,
+ FlacPrivate::write_callback,
+ FlacPrivate::metadata_callback,
+ FlacPrivate::error_callback,
+ this);
+
+
FLAC__stream_decoder_process_until_end_of_metadata(flac);
+#endif
+ return true;
+ }
+
+
+ bool is_valid() { return (flac != 0); }
+#ifdef LEGACY_FLAC
+ bool flush() { return
FLAC__seekable_stream_decoder_flush(flac); }
+ bool finish() { return
FLAC__seekable_stream_decoder_finish(flac); }
+ bool reset() { return
FLAC__seekable_stream_decoder_reset(flac); }
+ bool process_single() { return
FLAC__seekable_stream_decoder_process_single(flac); }
+ FLAC__SeekableStreamDecoderState get_state() { return
FLAC__seekable_stream_decoder_get_state(flac); }
+#else
+ bool flush() { return FLAC__stream_decoder_flush(flac); }
+ bool finish() { return FLAC__stream_decoder_finish(flac); }
+ bool reset() { return FLAC__stream_decoder_reset(flac); }
+ bool process_single() { return
FLAC__stream_decoder_process_single(flac); }
+ FLAC__StreamDecoderState get_state() { return
FLAC__stream_decoder_get_state(flac); }
+#endif
+
+
+ void cleanup()
+ {
+ if (internalBuffer) {
+ delete internalBuffer;
+ }
+ file->close();
+ delete file;
+
+ finish();
+
+#ifdef LEGACY_FLAC
+ FLAC__seekable_stream_decoder_delete(flac);
+#else
+ FLAC__stream_decoder_delete(flac);
+#endif
+ }
+
+
+ bool seek(nframes_t start)
+ {
+#ifdef LEGACY_FLAC
+ return
FLAC__seekable_stream_decoder_seek_absolute(flac, start);
+#else
+ return FLAC__stream_decoder_seek_absolute(flac, start);
+#endif
+ }
+
+ uint m_channels;
+ uint m_rate;
+ uint m_bitsPerSample;
+ uint m_samples;
+
+ audio_sample_t *internalBuffer;
+ int bufferSize;
+ int bufferUsed;
+ int bufferStart;
+
+ protected:
+#ifdef LEGACY_FLAC
+ static FLAC__SeekableStreamDecoderReadStatus
read_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[],
unsigned *bytes, void *client_data);
+ static FLAC__SeekableStreamDecoderSeekStatus
seek_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64
absolute_byte_offset, void *client_data);
+ static FLAC__SeekableStreamDecoderTellStatus
tell_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64
*absolute_byte_offset, void *client_data);
+ static FLAC__SeekableStreamDecoderLengthStatus
length_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64
*stream_length, void *client_data);
+ static FLAC__bool eof_callback(const
FLAC__SeekableStreamDecoder *decoder, void *client_data);
+ static void error_callback(const FLAC__SeekableStreamDecoder
*decoder, FLAC__StreamDecoderErrorStatus s, void *client_data){ printf("!!! %d
!!!\n", s); };
+ static void metadata_callback(const FLAC__SeekableStreamDecoder
*decoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
+ static FLAC__StreamDecoderWriteStatus write_callback(const
FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const
FLAC__int32 * const buffer[], void *client_data);
+#else
+ static FLAC__StreamDecoderReadStatus read_callback(const
FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void
*client_data);
+ static FLAC__StreamDecoderSeekStatus seek_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void
*client_data);
+ static FLAC__StreamDecoderTellStatus tell_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void
*client_data);
+ static FLAC__StreamDecoderLengthStatus length_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
+ static FLAC__bool eof_callback(const FLAC__StreamDecoder
*decoder, void *client_data);
+ static void error_callback(const FLAC__StreamDecoder *decoder,
FLAC__StreamDecoderErrorStatus s, void *client_data){ printf("!!! %d !!!\n",
s); };
+ static void metadata_callback(const FLAC__StreamDecoder
*decoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
+ static FLAC__StreamDecoderWriteStatus write_callback(const
FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *
const buffer[], void *client_data);
+#endif
+
+ QFile *file;
+#ifdef LEGACY_FLAC
+ FLAC__SeekableStreamDecoder *flac;
+#else
+ FLAC__StreamDecoder *flac;
+#endif
+};
+
+
+#ifdef LEGACY_FLAC
+FLAC__StreamDecoderWriteStatus FlacPrivate::write_callback(const
FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const
FLAC__int32 * const buffer[], void *client_data)
+#else
+FLAC__StreamDecoderWriteStatus FlacPrivate::write_callback(const
FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *
const buffer[], void *client_data)
+#endif
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ unsigned i, c, pos = 0;
+ int frames = frame->header.blocksize;
+
+ if (fp->bufferUsed > 0) {
+ // This shouldn't be happening
+ PERROR("internalBuffer is already non-empty");
+ }
+
+ if (fp->bufferSize < frames * frame->header.channels) {
+ if (fp->internalBuffer) {
+ delete fp->internalBuffer;
+ }
+ fp->internalBuffer = new audio_sample_t[frames *
frame->header.channels];
+ fp->bufferSize = frames * frame->header.channels;
+ }
+
+ for (i=0; i < frames; i++) {
+ // in FLAC channel 0 is left, 1 is right
+ for (c=0; c < frame->header.channels; c++) {
+ audio_sample_t value =
(audio_sample_t)((float)buffer[c][i] /
(float)((uint)1<<(frame->header.bits_per_sample-1)));
+ fp->internalBuffer[pos++] = value;
+ }
+ }
+
+ fp->bufferUsed = frames * frame->header.channels;
+
+ return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+
+#ifdef LEGACY_FLAC
+FLAC__SeekableStreamDecoderReadStatus FlacPrivate::read_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes,
void *client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ long retval = fp->file->read((char *)buffer, (*bytes));
+ if(retval == -1) {
+ return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
+ } else {
+ (*bytes) = retval;
+ return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
+ }
+}
+#else
+FLAC__StreamDecoderReadStatus FlacPrivate::read_callback(const
FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void
*client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ long retval = fp->file->read((char *)buffer, (*bytes));
+ if(retval == -1) {
+ return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
+ } else {
+ (*bytes) = retval;
+ return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
+ }
+}
+#endif
+
+#ifdef LEGACY_FLAC
+FLAC__SeekableStreamDecoderSeekStatus FlacPrivate::seek_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void
*client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ if(!fp->file->seek(absolute_byte_offset))
+ return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
+ else
+ return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
+}
+#else
+FLAC__StreamDecoderSeekStatus FlacPrivate::seek_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void
*client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ if(!fp->file->seek(absolute_byte_offset))
+ return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+ else
+ return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+#endif
+
+#ifdef LEGACY_FLAC
+FLAC__SeekableStreamDecoderTellStatus FlacPrivate::tell_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void
*client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ (*absolute_byte_offset) = fp->file->pos();
+ return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
+}
+#else
+FLAC__StreamDecoderTellStatus FlacPrivate::tell_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void
*client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ (*absolute_byte_offset) = fp->file->pos();
+ return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+#endif
+
+#ifdef LEGACY_FLAC
+FLAC__SeekableStreamDecoderLengthStatus FlacPrivate::length_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void
*client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ (*stream_length) = fp->file->size();
+ return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+}
+#else
+FLAC__StreamDecoderLengthStatus FlacPrivate::length_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ (*stream_length) = fp->file->size();
+ return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+#endif
+
+
+#ifdef LEGACY_FLAC
+void FlacPrivate::metadata_callback(const FLAC__SeekableStreamDecoder
*decoder, const FLAC__StreamMetadata *metadata, void *client_data)
+#else
+void FlacPrivate::metadata_callback(const FLAC__StreamDecoder *decoder, const
FLAC__StreamMetadata *metadata, void *client_data)
+#endif
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ switch (metadata->type)
+ {
+ case FLAC__METADATA_TYPE_STREAMINFO:
+ fp->m_channels = metadata->data.stream_info.channels;
+ fp->m_rate = metadata->data.stream_info.sample_rate;
+ fp->m_bitsPerSample =
metadata->data.stream_info.bits_per_sample;
+ fp->m_samples =
metadata->data.stream_info.total_samples;
+ break;
+ case FLAC__METADATA_TYPE_VORBIS_COMMENT:
+ //comments = new
FLAC::Metadata::VorbisComment((FLAC__StreamMetadata *)metadata, true);
+ break;
+ default:
+ break;
+ }
+}
+
+
+#ifdef LEGACY_FLAC
+FLAC__bool FlacPrivate::eof_callback(const FLAC__SeekableStreamDecoder
*decoder, void *client_data)
+#else
+FLAC__bool FlacPrivate::eof_callback(const FLAC__StreamDecoder *decoder, void
*client_data)
+#endif
+{
+ FlacPrivate *fp = (FlacPrivate*)client_data;
+
+ return fp->file->atEnd();
+}
+
+
+
+
+FlacAudioReader::FlacAudioReader(QString filename)
+ : AbstractAudioReader(filename)
+{
+ m_flac = new FlacPrivate(filename);
+
+ if (m_flac) {
+ m_channels = m_flac->m_channels;
+ m_length = m_flac->m_samples;
+ m_rate = m_flac->m_rate;
+ }
+}
+
+
+FlacAudioReader::~FlacAudioReader()
+{
+ if (m_flac) {
+ delete m_flac;
+ }
+}
+
+
+bool FlacAudioReader::can_decode(QString filename)
+{
+ // buffer large enough to read an ID3 tag header
+ char buf[10];
+
+ // Note: since file is created on the stack it will be closed
automatically
+ // by its destructor when this method (i.e. canDecode) returns.
+ QFile f(filename);
+
+ if (!f.open(QIODevice::ReadOnly)) {
+ PERROR("Could not open file %s", filename.toUtf8().data());
+ return false;
+ }
+
+ // look for a fLaC magic number or ID3 tag header
+ if (10 != f.read(buf, 10)) {
+ //PERROR("File too small to be a FLAC file: %s",
QS_C(filename));
+ return false;
+ }
+
+ if (0 == memcmp(buf, "ID3", 3)) {
+ // Found ID3 tag, try and seek past it.
+ //kdDebug() << "(K3bFLACDecorder) File " << filename << ":
found ID3 tag" << endl;
+
+ // See www.id3.org for details of the header, note that the
size field
+ // unpacks to 7-bit bytes, then the +10 is for the header
itself.
+ int pos;
+ pos = ((buf[6]<<21)|(buf[7]<<14)|(buf[8]<<7)|buf[9]) + 10;
+
+ //kdDebug() << "(K3bFLACDecoder) " << filename << ": seeking to
"
+ // << pos << endl;
+ if (!f.seek(pos)) {
+ //PERROR("Couldn't seek to %d in file: %s", pos,
QS_C(filename));
+ return false;
+ }
+ else {
+ // seek was okay, try and read magic number into buf
+ if (4 != f.read(buf, 4)) {
+ //PERROR("File has ID3 tag but nothing else:
%s", QS_C(filename));
+ return false;
+ }
+ }
+ }
+
+ if (memcmp(buf, "fLaC", 4) != 0) {
+ //PERROR("Not a flac file: %s", QS_C(filename));
+ return false;
+ }
+
+ f.close();
+
+ FlacPrivate flac(filename);
+
+ bool valid = flac.is_valid();
+
+ flac.finish();
+
+ //PERROR("Return: Is%s a flac file: %s", ((valid) ? "" : " not"),
QS_C(filename));
+ return valid;
+}
+
+
+bool FlacAudioReader::seek_private(nframes_t start)
+{
+ Q_ASSERT(m_flac);
+
+ if (start >= get_length()) {
+ PERROR("FlacAudioReader: could not seek to frame %d within %s,
it's past the end.", start, m_fileName.toUtf8().data());
+ return false;
+ }
+
+ m_flac->bufferUsed = 0;
+ m_flac->bufferStart = 0;
+
+ m_flac->flush();
+
+ if (!m_flac->seek(start)) {
+ PERROR("FlacAudioReader: could not seek to frame %d within %s",
start, m_fileName.toUtf8().data());
+ return false;
+ }
+
+ return true;
+}
+
+
+nframes_t FlacAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
+{
+ Q_ASSERT(m_flac);
+
+ nframes_t framesToCopy;
+ nframes_t framesAvailable;
+ nframes_t framesCoppied = 0;
+
+ while (framesCoppied < frameCount) {
+ if (m_flac->bufferUsed == 0) {
+ // want more data
+#ifdef LEGACY_FLAC
+ if (m_flac->get_state() ==
FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
+ //printf("flac file finish\n");
+ m_flac->flush();
+ m_flac->reset();
+ break;
+ }
+ else if(m_flac->get_state() ==
FLAC__SEEKABLE_STREAM_DECODER_OK) {
+ //printf("process\n");
+ if (!m_flac->process_single()) {
+ PERROR("process_single() error\n");
+ m_flac->reset();
+ seek(m_readPos);
+ return 0;
+ }
+ }
+ else {
+ PERROR("flac_state() = %d\n",
int(m_flac->get_state()));
+ m_flac->reset();
+ seek(m_readPos);
+ return 0;
+ }
+#else
+ if (m_flac->get_state() ==
FLAC__STREAM_DECODER_END_OF_STREAM) {
+ //printf("flac file finish\n");
+ m_flac->flush();
+ m_flac->reset();
+ break;
+ }
+ else if(m_flac->get_state() <
FLAC__STREAM_DECODER_END_OF_STREAM) {
+ //printf("process\n");
+ if (!m_flac->process_single()) {
+ PERROR("process_single() error\n");
+ m_flac->reset();
+ seek(m_readPos);
+ return 0;
+ }
+ }
+ else {
+ PERROR("flac_state() = %d\n",
int(m_flac->get_state()));
+ m_flac->reset();
+ seek(m_readPos);
+ return 0;
+ }
+#endif
+ }
+
+ framesAvailable = (m_flac->bufferUsed - m_flac->bufferStart) /
get_num_channels() ;
+ framesToCopy = (frameCount - framesCoppied < framesAvailable) ?
frameCount - framesCoppied : framesAvailable;
+ switch (get_num_channels()) {
+ case 1:
+ memcpy(buffer[0] + framesCoppied,
m_flac->internalBuffer + m_flac->bufferStart, framesToCopy);
+ break;
+ case 2:
+ for (int i = 0; i < framesToCopy; i++) {
+ buffer[0][framesCoppied + i] =
m_flac->internalBuffer[m_flac->bufferStart + i * 2];
+ buffer[1][framesCoppied + i] =
m_flac->internalBuffer[m_flac->bufferStart + i * 2 + 1];
+ }
+ break;
+ default:
+ for (int i = 0; i < framesToCopy; i++) {
+ for (int c = 0; c < get_num_channels();
c++) {
+ buffer[c][framesCoppied + i] =
m_flac->internalBuffer[m_flac->bufferStart + i * get_num_channels() + c];
+ }
+ }
+ break;
+ }
+
+ if(framesToCopy == framesAvailable) {
+ m_flac->bufferUsed = 0;
+ m_flac->bufferStart = 0;
+ }
+ else {
+ m_flac->bufferStart += framesToCopy *
get_num_channels();
+ }
+ framesCoppied += framesToCopy;
+
+ //printf("samplesCoppied = %d (%d, %d)\n", samplesCoppied,
m_flac->bufferStart, m_flac->buferSize);
+ }
+
+ // Pad end of file with 0s if necessary. (Shouldn't be necessary...)
+ /*int remainingFramesRequested = frameCount - framesCoppied;
+ int remainingFramesInFile = get_length() - (m_readPos + framesCoppied);
+ if (framesCoppied == 0 && remainingFramesInFile > 0) {
+ int padLength = (remainingFramesRequested >
remainingFramesInFile) ? remainingFramesInFile : remainingFramesRequested;
+ PERROR("padLength: %d", padLength);
+ for (int c = 0; c < get_num_channels(); c++) {
+ memset(buffer[c] + framesCoppied, 0, padLength *
sizeof(audio_sample_t));
+ }
+ framesCoppied += padLength;
+ }
+ if (framesCoppied > frameCount) {
+ PERROR("Truncating");
+ framesCoppied = frameCount;
+ }*/
+
+ //printf("copied %d of %d. nextFrame: %lu of %lu\n", framesCoppied,
frameCount, m_readPos, m_length); fflush(stdout);
+
+ return framesCoppied;
+}
+
Index: src/audiofileio/decode/FlacAudioReader.h
===================================================================
RCS file: src/audiofileio/decode/FlacAudioReader.h
diff -N src/audiofileio/decode/FlacAudioReader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/FlacAudioReader.h 31 Jul 2007 18:45:12 -0000
1.1
@@ -0,0 +1,45 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef FLACAUDIOREADER_H
+#define FLACAUDIOREADER_H
+
+#include "AbstractAudioReader.h"
+
+
+class FlacPrivate;
+
+class FlacAudioReader : public AbstractAudioReader
+{
+public:
+ FlacAudioReader(QString filename);
+ ~FlacAudioReader();
+
+ static bool can_decode(QString filename);
+
+protected:
+ bool seek_private(nframes_t start);
+ nframes_t read_private(audio_sample_t** buffer, nframes_t sampleCount);
+
+ FlacPrivate *m_flac;
+};
+
+#endif
Index: src/audiofileio/decode/MadAudioReader.cpp
===================================================================
RCS file: src/audiofileio/decode/MadAudioReader.cpp
diff -N src/audiofileio/decode/MadAudioReader.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/MadAudioReader.cpp 31 Jul 2007 18:45:12 -0000
1.1
@@ -0,0 +1,885 @@
+/*
+Copyright (C) 2007 Ben Levitt
+ * This file based on the mp3 decoding plugin of the K3b project.
+ * Copyright (C) 1998-2007 Sebastian Trueg <address@hidden>
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "MadAudioReader.h"
+#include <QFile>
+#include <QString>
+#include <QVector>
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+
+
+static const int INPUT_BUFFER_SIZE = 5*8192;
+
+class K3bMad
+{
+public:
+ K3bMad();
+ ~K3bMad();
+
+ bool open(const QString& filename);
+
+ /**
+ * @return true if the mad stream contains data
+ * false if there is no data left or an error occurred.
+ * In the latter case inputError() returns true.
+ */
+ bool fillStreamBuffer();
+
+ /**
+ * Skip id3 tags.
+ *
+ * This will reset the input file.
+ */
+ bool skipTag();
+
+ /**
+ * Find first frame and seek to the beginning of that frame.
+ * This is used to skip the junk that many mp3 files start with.
+ */
+ bool seekFirstHeader();
+
+ bool eof() const;
+ bool inputError() const;
+
+ /**
+ * Current position in theinput file. This does NOT
+ * care about the status of the mad stream. Use streamPos()
+ * in that case.
+ */
+ qint64 inputPos() const;
+
+ /**
+ * Current absolut position of the decoder stream.
+ */
+ qint64 streamPos() const;
+ bool inputSeek(qint64 pos);
+
+ void initMad();
+ void cleanup();
+
+ bool decodeNextFrame();
+ bool findNextHeader();
+ bool checkFrameHeader(mad_header* header) const;
+
+ mad_stream* madStream;
+ mad_frame* madFrame;
+ mad_synth* madSynth;
+ mad_timer_t* madTimer;
+
+private:
+ QFile m_inputFile;
+ bool m_madStructuresInitialized;
+ unsigned char* m_inputBuffer;
+ bool m_bInputError;
+
+ int m_channels;
+ int m_sampleRate;
+};
+
+
+K3bMad::K3bMad()
+ : m_madStructuresInitialized(false),
+ m_bInputError(false)
+{
+ madStream = new mad_stream;
+ madFrame = new mad_frame;
+ madSynth = new mad_synth;
+ madTimer = new mad_timer_t;
+
+ //
+ // we allocate additional MAD_BUFFER_GUARD bytes to always be able to
append the
+ // zero bytes needed for decoding the last frame.
+ //
+ m_inputBuffer = new unsigned char[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD];
+}
+
+
+K3bMad::~K3bMad()
+{
+ cleanup();
+
+ delete madStream;
+ delete madFrame;
+ delete madSynth;
+ delete madTimer;
+
+ delete [] m_inputBuffer;
+}
+
+
+bool K3bMad::open(const QString& filename)
+{
+ cleanup();
+
+ m_bInputError = false;
+ m_channels = m_sampleRate = 0;
+
+ m_inputFile.setFileName(filename);
+
+ if (!m_inputFile.open(QIODevice::ReadOnly)) {
+ PERROR("could not open file %s",
m_inputFile.fileName().toUtf8().data());
+ return false;
+ }
+
+ initMad();
+
+ memset(m_inputBuffer, 0, INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD);
+
+ return true;
+}
+
+
+bool K3bMad::inputError() const
+{
+ return m_bInputError;
+}
+
+
+bool K3bMad::fillStreamBuffer()
+{
+ /* The input bucket must be filled if it becomes empty or if
+ * it's the first execution of the loop.
+ */
+ if (madStream->buffer == 0 || madStream->error == MAD_ERROR_BUFLEN) {
+ if (eof()) {
+ return false;
+ }
+
+ long readSize, remaining;
+ unsigned char* readStart;
+
+ if (madStream->next_frame != 0) {
+ remaining = madStream->bufend - madStream->next_frame;
+ memmove(m_inputBuffer, madStream->next_frame,
remaining);
+ readStart = m_inputBuffer + remaining;
+ readSize = INPUT_BUFFER_SIZE - remaining;
+ }
+ else {
+ readSize = INPUT_BUFFER_SIZE;
+ readStart = m_inputBuffer;
+ remaining = 0;
+ }
+
+ // Fill-in the buffer.
+ long result = m_inputFile.read((char*)readStart, readSize);
+ if (result < 0) {
+ //kdDebug() << "(K3bMad) read error on bitstream)" <<
endl;
+ m_bInputError = true;
+ return false;
+ }
+ else if (result == 0) {
+ //kdDebug() << "(K3bMad) end of input stream" << endl;
+ return false;
+ }
+ else {
+ readStart += result;
+
+ if (eof()) {
+ //kdDebug() << "(K3bMad::fillStreamBuffer)
MAD_BUFFER_GUARD" << endl;
+ memset(readStart, 0, MAD_BUFFER_GUARD);
+ result += MAD_BUFFER_GUARD;
+ }
+
+ // Pipe the new buffer content to libmad's stream
decoder facility.
+ mad_stream_buffer(madStream, m_inputBuffer, result +
remaining);
+ madStream->error = MAD_ERROR_NONE;
+ }
+ }
+
+ return true;
+}
+
+
+bool K3bMad::skipTag()
+{
+ // skip the tag at the beginning of the file
+ m_inputFile.seek(0);
+
+ //
+ // now check if the file starts with an id3 tag and skip it if so
+ //
+ char buf[4096];
+ int bufLen = 4096;
+ if (m_inputFile.read(buf, bufLen) < bufLen) {
+ //kdDebug() << "(K3bMad) unable to read " << bufLen << " bytes
from "
+ // << m_inputFile.name() << endl;
+ return false;
+ }
+
+ if ((buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3') &&
+ ((unsigned short)buf[3] < 0xff && (unsigned short)buf[4] < 0xff)) {
+ // do we have a footer?
+ bool footer = (buf[5] & 0x10);
+
+ // the size is saved as a synched int meaning bit 7 is always
cleared to 0
+ unsigned int size =
+ ( (buf[6] & 0x7f) << 21 ) |
+ ( (buf[7] & 0x7f) << 14 ) |
+ ( (buf[8] & 0x7f) << 7) |
+ (buf[9] & 0x7f);
+ unsigned int offset = size + 10;
+
+ if (footer) {
+ offset += 10;
+ }
+
+ // skip the id3 tag
+ if (!m_inputFile.seek(offset)) {
+ PERROR("Couldn't seek to %u in %s", offset,
m_inputFile.fileName().toUtf8().data());
+ return false;
+ }
+ }
+ else {
+ // reset file
+ return m_inputFile.seek(0);
+ }
+
+ return true;
+}
+
+
+bool K3bMad::seekFirstHeader()
+{
+ //
+ // A lot of mp3 files start with a lot of junk which confuses mad.
+ // We "allow" an mp3 file to start with at most 1 KB of junk. This is
just
+ // some random value since we do not want to search the hole file. That
would
+ // take way to long for non-mp3 files.
+ //
+ bool headerFound = findNextHeader();
+ qint64 inputPos = streamPos();
+ while (!headerFound &&
+ !m_inputFile.atEnd() &&
+ streamPos() <= inputPos+1024) {
+ headerFound = findNextHeader();
+ }
+
+ // seek back to the begin of the frame
+ if (headerFound) {
+ int streamSize = madStream->bufend - madStream->buffer;
+ int bytesToFrame = madStream->this_frame - madStream->buffer;
+ m_inputFile.seek(m_inputFile.pos() - streamSize + bytesToFrame);
+
+ //kdDebug() << "(K3bMad) found first header at " <<
m_inputFile.pos() << endl;
+ }
+
+ // reset the stream to make sure mad really starts decoding at out seek
position
+ mad_stream_finish(madStream);
+ mad_stream_init(madStream);
+
+ return headerFound;
+}
+
+
+bool K3bMad::eof() const
+{
+ return m_inputFile.atEnd();
+}
+
+
+qint64 K3bMad::inputPos() const
+{
+ return m_inputFile.pos();
+}
+
+
+qint64 K3bMad::streamPos() const
+{
+ return inputPos() - (madStream->bufend - madStream->this_frame + 1);
+}
+
+
+bool K3bMad::inputSeek(qint64 pos)
+{
+ return m_inputFile.seek(pos);
+}
+
+
+void K3bMad::initMad()
+{
+ if (!m_madStructuresInitialized) {
+ mad_stream_init(madStream);
+ mad_timer_set(madTimer, 0, 0, 0);
+ mad_frame_init(madFrame);
+ mad_synth_init(madSynth);
+
+ m_madStructuresInitialized = true;
+ }
+}
+
+
+void K3bMad::cleanup()
+{
+ if (m_inputFile.isOpen()) {
+ //kdDebug() << "(K3bMad) cleanup at offset: "
+ // << "Input file at: " << m_inputFile.pos() << " "
+ // << "Input file size: " << m_inputFile.size() << "
"
+ // << "stream pos: "
+ // << ( m_inputFile.pos() - (madStream->bufend -
madStream->this_frame + 1) )
+ // << endl;
+ m_inputFile.close();
+ }
+
+ if (m_madStructuresInitialized) {
+ mad_frame_finish(madFrame);
+ mad_synth_finish(madSynth);
+ mad_stream_finish(madStream);
+ }
+
+ m_madStructuresInitialized = false;
+}
+
+
+//
+// LOSTSYNC could happen when mad encounters the id3 tag...
+//
+bool K3bMad::findNextHeader()
+{
+ if (!fillStreamBuffer()) {
+ return false;
+ }
+
+ //
+ // MAD_RECOVERABLE == true: frame was read, decoding failed (about to
skip frame)
+ // MAD_RECOVERABLE == false: frame was not read, need data
+ //
+
+ if (mad_header_decode( &madFrame->header, madStream ) < 0) {
+ if (MAD_RECOVERABLE(madStream->error) ||
+ madStream->error == MAD_ERROR_BUFLEN) {
+ return findNextHeader();
+ }
+ else
+ // kdDebug() << "(K3bMad::findNextHeader) error: " <<
mad_stream_errorstr( madStream ) << endl;
+
+ // FIXME probably we should not do this here since we don't do
it
+ // in the frame decoding
+ // if(!checkFrameHeader(&madFrame->header))
+ // return findNextHeader();
+
+ return false;
+ }
+
+ if (!m_channels) {
+ m_channels = MAD_NCHANNELS(&madFrame->header);
+ m_sampleRate = madFrame->header.samplerate;
+ }
+
+ mad_timer_add(madTimer, madFrame->header.duration);
+
+ return true;
+}
+
+
+bool K3bMad::decodeNextFrame()
+{
+ if (!fillStreamBuffer()) {
+ return false;
+ }
+
+ if (mad_frame_decode(madFrame, madStream) < 0) {
+ if (MAD_RECOVERABLE(madStream->error) ||
+ madStream->error == MAD_ERROR_BUFLEN) {
+ return decodeNextFrame();
+ }
+
+ return false;
+ }
+
+ if (!m_channels) {
+ m_channels = MAD_NCHANNELS(&madFrame->header);
+ m_sampleRate = madFrame->header.samplerate;
+ }
+
+ mad_timer_add(madTimer, madFrame->header.duration);
+
+ return true;
+}
+
+
+//
+// This is from the arts mad decoder
+//
+bool K3bMad::checkFrameHeader(mad_header* header) const
+{
+ int frameSize = MAD_NSBSAMPLES(header) * 32;
+
+ if (frameSize <= 0) {
+ return false;
+ }
+
+ if (m_channels && m_channels != MAD_NCHANNELS(header)) {
+ return false;
+ }
+
+ return true;
+}
+
+
+
+class MadAudioReader::MadDecoderPrivate
+{
+public:
+ MadDecoderPrivate()
+ {
+ outputBuffers = 0;
+ outputPos = 0;
+ outputSize = 0;
+ overflowSize = 0;
+ overflowStart = 0;
+
+ mad_header_init( &firstHeader );
+ }
+
+ K3bMad* handle;
+
+ QVector<unsigned long long> seekPositions;
+
+ bool bOutputFinished;
+
+ audio_sample_t** outputBuffers;
+ nframes_t outputPos;
+ nframes_t outputSize;
+
+ QVector<audio_sample_t*> overflowBuffers;
+ nframes_t overflowSize;
+ nframes_t overflowStart;
+
+ // the first frame header for technical info
+ mad_header firstHeader;
+ bool vbr;
+};
+
+
+MadAudioReader::MadAudioReader(QString filename)
+ : AbstractAudioReader(filename)
+{
+ d = new MadDecoderPrivate();
+ d->handle = new K3bMad();
+
+ initDecoderInternal();
+
+ switch( d->firstHeader.mode ) {
+ case MAD_MODE_SINGLE_CHANNEL:
+ m_channels = 1;
+ case MAD_MODE_DUAL_CHANNEL:
+ case MAD_MODE_JOINT_STEREO:
+ case MAD_MODE_STEREO:
+ m_channels = 2;
+ }
+
+ m_length = countFrames();
+
+ if (m_length <= 0) {
+ d->handle->cleanup();
+ delete d->handle;
+ delete d;
+ d = 0;
+ return;
+ }
+
+ m_rate = d->firstHeader.samplerate;
+
+ for (int c = 0; c < m_channels; c++) {
+ d->overflowBuffers.append(new audio_sample_t[1152]);
+ }
+
+ seek_private(0);
+}
+
+
+MadAudioReader::~MadAudioReader()
+{
+ if (d) {
+ d->handle->cleanup();
+ delete d->handle;
+ while (d->overflowBuffers.size()) {
+ delete d->overflowBuffers.back();
+ d->overflowBuffers.pop_back();
+ }
+ delete d;
+ }
+}
+
+
+bool MadAudioReader::can_decode(QString filename)
+{
+ //
+ // HACK:
+ //
+ // I am simply no good at this and this detection code is no good as
well
+ // It always takes waves for mp3 files so we introduce this hack to
+ // filter out wave files. :(
+ //
+ QFile f(filename);
+ if (!f.open( QIODevice::ReadOnly)) {
+ return false;
+ }
+
+ char buffer[12];
+ if (f.read(buffer, 12) != 12) {
+ return false;
+ }
+ if (!qstrncmp(buffer, "RIFF", 4) && !qstrncmp(buffer + 8, "WAVE", 4)) {
+ return false;
+ }
+ f.close();
+
+
+ K3bMad handle;
+ if (!handle.open(filename)) {
+ return false;
+ }
+ handle.skipTag();
+ if (!handle.seekFirstHeader()) {
+ return false;
+ }
+ if (handle.findNextHeader()) {
+ int c = MAD_NCHANNELS(&handle.madFrame->header);
+ int layer = handle.madFrame->header.layer;
+ unsigned int s = handle.madFrame->header.samplerate;
+
+ //
+ // find 4 more mp3 headers (random value since 2 was not enough)
+ // This way we get most of the mp3 files while sorting out
+ // for example wave files.
+ //
+ int cnt = 1;
+ while (handle.findNextHeader()) {
+ // compare the found headers
+ if (MAD_NCHANNELS(&handle.madFrame->header) == c &&
+ handle.madFrame->header.layer == layer &&
+ handle.madFrame->header.samplerate == s) {
+ // only support layer III for now since
otherwise some wave files
+ // are taken for layer I
+ if (++cnt >= 5) {
+ //stdout << "(MadDecoder) valid mpeg 1
layer " << layer
+ //<< " file with " << c << " channels
and a samplerate of "
+ //<< s << endl;
+ return (layer == MAD_LAYER_III);
+ }
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ //PERROR("unsupported format: %s",QS_C(filename));
+
+ return false;
+}
+
+
+bool MadAudioReader::seek_private(nframes_t start)
+{
+ Q_ASSERT(d);
+
+ if (start >= m_length) {
+ return false;
+ }
+
+ //
+ // we need to reset the complete mad stuff
+ //
+ if (!initDecoderInternal()) {
+ return false;
+ }
+
+ //
+ // search a position
+ // This is all hacking, I don't really know what I am doing here... ;)
+ //
+ double mp3FrameSecs =
static_cast<double>(d->firstHeader.duration.seconds) +
static_cast<double>(d->firstHeader.duration.fraction) /
static_cast<double>(MAD_TIMER_RESOLUTION);
+
+ double posSecs = static_cast<double>(start) / m_rate;
+
+ // seekPosition to seek after frame i
+ unsigned int frame = static_cast<unsigned int>(posSecs / mp3FrameSecs);
+ nframes_t frameOffset = (nframes_t)(start - (frame * mp3FrameSecs *
m_rate + 0.5));
+
+ // K3b source: Rob said: 29 frames is the theoretically max frame
reservoir limit
+ // (whatever that means...) it seems that mad needs at most 29 frames
to get ready
+ //
+ // Ben says: It looks like Rob (the author of MAD) implies here:
+ // http://www.mars.org/mailman/public/mad-dev/2001-August/000321.html
+ // that 3 frames (1 + 2 extra) is enough... seems to work fine...
+ unsigned int frameReservoirProtect = (frame > 3 ? 3 : frame);
+
+ frame -= frameReservoirProtect;
+
+ // seek in the input file behind the already decoded data
+ d->handle->inputSeek( d->seekPositions[frame] );
+
+ // decode some frames ignoring MAD_ERROR_BADDATAPTR errors
+ unsigned int i = 1;
+ while (i <= frameReservoirProtect) {
+ d->handle->fillStreamBuffer();
+ if (mad_frame_decode( d->handle->madFrame,
d->handle->madStream)) {
+ if (MAD_RECOVERABLE( d->handle->madStream->error)) {
+ if (d->handle->madStream->error ==
MAD_ERROR_BUFLEN) {
+ continue;
+ }
+ else if (d->handle->madStream->error !=
MAD_ERROR_BADDATAPTR) {
+ //kdDebug() << "(K3bMadDecoder)
Seeking: recoverable mad error ("
+ //<<
mad_stream_errorstr(d->handle->madStream) << ")" << endl;
+ continue;
+ }
+ else {
+ //kdDebug() << "(K3bMadDecoder)
Seeking: ignoring ("
+ //<<
mad_stream_errorstr(d->handle->madStream) << ")" << endl;
+ }
+ }
+ else {
+ return false;
+ }
+ }
+
+ if (i == frameReservoirProtect) { // synth only the last frame
(Rob said so ;)
+ mad_synth_frame( d->handle->madSynth,
d->handle->madFrame );
+ }
+
+ ++i;
+ }
+
+ d->overflowStart = 0;
+ d->overflowSize = 0;
+
+ // Seek to exact traverso frame, within this mp3 frame
+ if (frameOffset > 0) {
+ //printf("seekOffset: %lu (start: %lu)\n", frameOffset, start);
+ d->outputBuffers = 0; // Zeros so that we write to overflow
+ d->outputSize = 0;
+ d->outputPos = 0;
+ createPcmSamples(d->handle->madSynth);
+ d->overflowStart = frameOffset;
+ d->overflowSize -= frameOffset;
+ }
+
+ return true;
+}
+
+
+bool MadAudioReader::initDecoderInternal()
+{
+ d->handle->cleanup();
+
+ d->bOutputFinished = false;
+
+ if (!d->handle->open(m_fileName)) {
+ return false;
+ }
+
+ if (!d->handle->skipTag()) {
+ return false;
+ }
+
+ if (!d->handle->seekFirstHeader()) {
+ return false;
+ }
+
+ return true;
+}
+
+
+unsigned long MadAudioReader::countFrames()
+ {
+ //kdDebug() << "(K3bMadDecoder::countFrames)" << endl;
+
+ unsigned long frames = 0;
+ bool error = false;
+ d->vbr = false;
+ bool bFirstHeaderSaved = false;
+
+ d->seekPositions.clear();
+
+ while (!error && d->handle->findNextHeader()) {
+ if (!bFirstHeaderSaved) {
+ bFirstHeaderSaved = true;
+ d->firstHeader = d->handle->madFrame->header;
+ }
+ else if (d->handle->madFrame->header.bitrate !=
d->firstHeader.bitrate) {
+ d->vbr = true;
+ }
+ //
+ // position in stream: position in file minus the not yet used
buffer
+ //
+ unsigned long long seekPos = d->handle->inputPos() -
+ (d->handle->madStream->bufend -
d->handle->madStream->this_frame + 1);
+
+ // save the number of bytes to be read to decode i-1 frames at
position i
+ // in other words: when seeking to seekPos the next decoded
frame will be i
+ d->seekPositions.append(seekPos);
+ }
+
+ if (!d->handle->inputError() && !error) {
+ frames = d->firstHeader.samplerate *
(d->handle->madTimer->seconds + (unsigned long)(
+
(float)d->handle->madTimer->fraction/(float)MAD_TIMER_RESOLUTION));
+ //kdDebug() << "(K3bMadDecoder) length of track " << seconds <<
endl;
+ }
+
+ d->handle->cleanup();
+
+ //kdDebug() << "(K3bMadDecoder::countFrames) end" << endl;
+
+ return frames;
+}
+
+
+nframes_t MadAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
+{
+ d->outputBuffers = buffer;
+ d->outputSize = frameCount;
+ d->outputPos = 0;
+
+ bool bOutputBufferFull = false;
+
+ // Deal with existing overflow
+ if (d->overflowSize > 0) {
+ if (d->overflowSize < frameCount) {
+ //printf("output all %d overflow samples\n",
d->overflowSize);
+ for (int c = 0; c < m_channels; c++) {
+ memcpy(d->outputBuffers[c],
d->overflowBuffers[c] + d->overflowStart, d->overflowSize *
sizeof(audio_sample_t));
+ }
+ d->outputPos += d->overflowSize;
+ d->overflowSize = 0;
+ d->overflowStart = 0;
+ }
+ else {
+ //printf("output %d overflow frames, returned from
overflow\n", frameCount);
+ for (int c = 0; c < m_channels; c++) {
+ memcpy(d->outputBuffers[c],
d->overflowBuffers[c] + d->overflowStart, frameCount * sizeof(audio_sample_t));
+ }
+ d->overflowSize -= frameCount;
+ d->overflowStart += frameCount;
+ return frameCount;
+ }
+ }
+
+ while (!bOutputBufferFull && d->handle->fillStreamBuffer()) {
+ // a mad_synth contains of the data of one mad_frame
+ // one mad_frame represents a mp3-frame which is always 1152
samples
+ // for us that means we need 1152 samples per channel of output
buffer
+ // for every frame
+ if (d->outputPos >= d->outputSize) {
+ bOutputBufferFull = true;
+ }
+ else if (d->handle->decodeNextFrame()) {
+ //
+ // Once decoded the frame is synthesized to PCM
samples. No errors
+ // are reported by mad_synth_frame();
+ //
+ mad_synth_frame( d->handle->madSynth,
d->handle->madFrame );
+
+ // this fills the output buffer
+ if (!createPcmSamples(d->handle->madSynth)) {
+ PERROR("createPcmSamples");
+ return 0;
+ }
+ }
+ else if (d->handle->inputError()) {
+ PERROR("inputError");
+ return 0;
+ }
+ }
+
+ nframes_t framesWritten = d->outputPos;
+
+ // Pad end with zeros if necessary
+ // FIXME: This shouldn't be necessary! :P
+ // is m_length reporting incorrectly?
+ // are we not outputting the last mp3-frame for some reason?
+ /*int remainingFramesRequested = frameCount - framesWritten;
+ int remainingFramesInFile = m_length - (m_readPos + framesWritten);
+ if (remainingFramesRequested > 0 && remainingFramesInFile > 0) {
+ int padLength = (remainingFramesRequested >
remainingFramesInFile) ? remainingFramesInFile : remainingFramesRequested;
+ for (int c = 0; c < m_channels; c++) {
+ //memset(d->outputBuffers[c] + framesWritten, 0,
padLength * sizeof(audio_sample_t));
+ }
+ framesWritten += padLength;
+ printf("padding: %d\n", padLength);
+ }
+
+ // Truncate so we don't return too many frames
+ if (framesWritten + m_readPos > m_length) {
+ printf("truncating by %d!\n", m_length - (framesWritten +
m_readPos));
+ framesWritten = m_length - m_readPos;
+ }*/
+
+ //printf("request: %d (returned: %d), now at: %lu (total: %lu)\n",
frameCount, framesWritten, m_readPos + framesWritten, m_length);
+
+ return framesWritten;
+}
+
+
+bool MadAudioReader::createPcmSamples(mad_synth* synth)
+{
+ audio_sample_t **writeBuffers = d->outputBuffers;
+ int offset = d->outputPos;
+ nframes_t nframes = synth->pcm.length;
+ bool overflow = false;
+ int i;
+
+ if (writeBuffers && (m_readPos + d->outputPos + nframes) > m_length) {
+ nframes = m_length - (m_readPos + offset);
+ //printf("!!!nframes: %lu, length: %lu, current: %lu\n",
nframes, m_length, d->outputPos + m_readPos);
+ }
+
+ // now create the output
+ for (i = 0; i < nframes; i++) {
+ if (overflow == false && d->outputPos + i >= d->outputSize) {
+ writeBuffers = d->overflowBuffers.data();
+ offset = 0 - i;
+ overflow = true;
+ }
+
+ /* Left channel */
+ writeBuffers[0][offset + i] =
mad_f_todouble(synth->pcm.samples[0][i]);
+
+ /* Right channel. If the decoded stream is monophonic then no
right channel
+ */
+ if (synth->pcm.channels == 2) {
+ writeBuffers[1][offset + i] =
mad_f_todouble(synth->pcm.samples[1][i]);
+ }
+ } // pcm conversion
+
+ if (overflow) {
+ d->overflowSize = i + offset;
+ d->overflowStart = 0;
+ d->outputPos -= offset; // i was stored here when we switched
to writing to overflow
+ //printf("written: %d (overflow: %u)\n", nframes -
d->overflowSize, d->overflowSize);
+ }
+ else {
+ d->outputPos += i;
+ //printf("written: %d (os=%lu)\n", i, d->overflowSize);
+ }
+
+ return true;
+}
+
+
Index: src/audiofileio/decode/MadAudioReader.h
===================================================================
RCS file: src/audiofileio/decode/MadAudioReader.h
diff -N src/audiofileio/decode/MadAudioReader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/MadAudioReader.h 31 Jul 2007 18:45:12 -0000
1.1
@@ -0,0 +1,54 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef MADAUDIOREADER_H
+#define MADAUDIOREADER_H
+
+#include <AbstractAudioReader.h>
+
+extern "C" {
+#include <mad.h>
+}
+
+
+class MadAudioReader : public AbstractAudioReader
+{
+public:
+ MadAudioReader(QString filename);
+ ~MadAudioReader();
+
+ static bool can_decode(QString filename);
+
+protected:
+ bool seek_private(nframes_t start);
+ nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
+
+ bool initDecoderInternal();
+ unsigned long countFrames();
+ bool createPcmSamples(mad_synth* synth);
+
+ static int MaxAllowedRecoverableErrors;
+
+ class MadDecoderPrivate;
+ MadDecoderPrivate* d;
+};
+
+#endif
Index: src/audiofileio/decode/ResampleAudioReader.cpp
===================================================================
RCS file: src/audiofileio/decode/ResampleAudioReader.cpp
diff -N src/audiofileio/decode/ResampleAudioReader.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/ResampleAudioReader.cpp 31 Jul 2007 18:45:12
-0000 1.1
@@ -0,0 +1,258 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "ResampleAudioReader.h"
+#include <QString>
+
+#define OVERFLOW_SIZE 1024
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+// On init, creates a child AudioReader for any filetype, and a samplerate
converter
+ResampleAudioReader::ResampleAudioReader(QString filename, int converter_type)
+ : AbstractAudioReader(filename)
+{
+ m_reader = AbstractAudioReader::create_audio_reader(filename);
+ if (!m_reader) {
+ PERROR("ResampleAudioReader: couldn't create AudioReader");
+ return;
+ }
+
+ m_channels = m_reader->get_num_channels();
+ m_rate = m_reader->get_file_rate();
+ m_length = m_reader->get_length();
+ m_outputRate = m_rate;
+
+ m_fileBuffers.resize(get_num_channels());
+ m_filePointers.resize(get_num_channels());
+ m_fileBufferLength = 0;
+
+ init(converter_type);
+}
+
+
+ResampleAudioReader::~ResampleAudioReader()
+{
+ while (m_srcStates.size()) {
+ src_delete(m_srcStates.back());
+ m_srcStates.pop_back();
+ }
+
+ if (m_reader) {
+ delete m_reader;
+ }
+
+ while (m_fileBuffers.size()) {
+ delete m_fileBuffers.back();
+ m_fileBuffers.pop_back();
+ }
+}
+
+
+void ResampleAudioReader::init(int converter_type)
+{
+ int error;
+
+ for (int c = 0; c < m_reader->get_num_channels(); c++) {
+ m_srcStates.append(src_new(converter_type, 1, &error));
+ if (!m_srcStates[c]) {
+ PERROR("ResampleAudioReader: couldn't create
libSampleRate SRC_STATE");
+ delete m_reader;
+ m_reader = 0;
+ return;
+ }
+ m_srcStates.append(src_new(converter_type, 1, &error));
+ if (!m_srcStates[c]) {
+ PERROR("ResampleAudioReader: couldn't create
libSampleRate SRC_STATE");
+ delete m_reader;
+ m_reader = 0;
+ return;
+ }
+ }
+
+ reset();
+ seek_private(0);
+}
+
+
+// Clear the samplerateconverter to a clean state (used on seek)
+void ResampleAudioReader::reset()
+{
+ for (int c = 0; c < m_reader->get_num_channels(); c++) {
+ src_reset(m_srcStates[c]);
+ }
+
+ m_srcData.end_of_input = 0;
+ m_overflowUsed = 0;
+}
+
+
+int ResampleAudioReader::get_output_rate()
+{
+ return m_outputRate;
+}
+
+
+void ResampleAudioReader::set_output_rate(int rate)
+{
+ if (!m_reader) {
+ return;
+ }
+ m_outputRate = rate;
+ m_length = file_to_song_frame(m_reader->get_length());
+}
+
+
+// if no conversion is necessary, pass the seek straight to the child
AudioReader,
+// otherwise convert and seek
+bool ResampleAudioReader::seek_private(nframes_t start)
+{
+ Q_ASSERT(m_reader);
+
+ if (m_outputRate == m_rate) {
+ return m_reader->seek(start);
+ }
+
+ reset();
+
+ return m_reader->seek(song_to_file_frame(start));
+}
+
+
+// If no conversion is necessary, pass the read straight to the child
AudioReader,
+// otherwise get data from childreader and use libsamplerate to convert
+nframes_t ResampleAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
+{
+ Q_ASSERT(m_reader);
+
+ // pass through if not changing sampleRate.
+ if (m_outputRate == m_rate) {
+ return m_reader->read(buffer, frameCount);
+ }
+
+ nframes_t bufferUsed;
+ nframes_t framesRead;
+
+ nframes_t fileCnt = song_to_file_frame(frameCount);
+
+ if (frameCount && !fileCnt) {
+ fileCnt = 1;
+ }
+
+ bufferUsed = m_overflowUsed;
+
+ if (!m_reader->eof()) {
+ // make sure that the reusable m_fileBuffers are big enough for
this read + OVERFLOW_SIZE
+ if ((uint)m_fileBufferLength < fileCnt + OVERFLOW_SIZE) {
+ for (int c = 0; c < m_channels; c++) {
+ if (m_fileBufferLength) {
+ delete m_fileBuffers[c];
+ }
+ m_fileBuffers[c] = new audio_sample_t[fileCnt +
OVERFLOW_SIZE];
+ }
+ m_fileBufferLength = fileCnt + OVERFLOW_SIZE;
+ }
+
+ for (int c = 0; c < m_channels; c++) {
+ m_filePointers[c] = m_fileBuffers[c] + m_overflowUsed;
+ }
+
+ bufferUsed += m_reader->read(m_filePointers.data(), fileCnt +
OVERFLOW_SIZE - m_overflowUsed);
+ //printf("Resampler: Read %lu of %lu (%lu)\n", bufferUsed,
fileCnt + OVERFLOW_SIZE - m_overflowUsed, m_reader->get_length());
+ }
+
+ if (m_reader->eof()) {
+ m_srcData.end_of_input = 1;
+ }
+
+ nframes_t framesToConvert = frameCount;
+ if (frameCount > m_length - m_readPos) {
+ framesToConvert = m_length - m_readPos;
+ }
+
+ for (int c = 0; c < m_channels; c++) {
+ // Set up sample rate converter struct for s.r.c. processing
+ m_srcData.data_in = m_fileBuffers[c];
+ m_srcData.input_frames = bufferUsed;
+ m_srcData.data_out = buffer[c];
+ m_srcData.output_frames = framesToConvert;
+ m_srcData.src_ratio = (double) m_outputRate / m_rate;
+ src_set_ratio(m_srcStates[c], m_srcData.src_ratio);
+
+ if (src_process(m_srcStates[c], &m_srcData)) {
+ PERROR("Resampler: src_process() error!");
+ return 0;
+ }
+ framesRead = m_srcData.output_frames_gen;
+ }
+
+ m_overflowUsed = bufferUsed - m_srcData.input_frames_used;
+
+ if (m_overflowUsed < 0) {
+ m_overflowUsed = 0;
+ }
+
+ if (m_srcData.input_frames_used < bufferUsed) {
+ for (int c = 0; c < m_channels; c++) {
+ memmove(m_fileBuffers[c], m_fileBuffers[c] +
m_srcData.input_frames_used, m_overflowUsed * sizeof(audio_sample_t));
+ }
+ }
+
+ // Pad end of file with 0s if necessary
+ if (framesRead == 0 && m_readPos < get_length()) {
+ int padLength = m_readPos;
+ for (int c = 0; c < m_channels; c++) {
+ memset(buffer[c] + framesRead, 0, padLength *
sizeof(audio_sample_t));
+ }
+ framesRead += padLength;
+ printf("Resampler: padding: %d\n", padLength);
+ }
+
+ // Truncate so we don't return too many samples
+ /*if (m_readPos + framesRead > get_length()) {
+ printf("Resampler: truncating: %d\n", framesRead -
(get_length() - m_readPos));
+ framesRead = get_length() - m_readPos;
+ }*/
+
+ //printf("framesRead: %lu of %lu (overflow: %lu) (at: %lu of %lu)\n",
framesRead, frameCount, m_overflowUsed, m_readPos + framesRead, get_length());
+
+ return framesRead;
+}
+
+
+nframes_t ResampleAudioReader::song_to_file_frame(nframes_t frame)
+{
+ Q_ASSERT(m_reader);
+
+ return (nframes_t)(frame * ((double) m_rate / m_outputRate));
+}
+
+
+nframes_t ResampleAudioReader::file_to_song_frame(nframes_t frame)
+{
+ Q_ASSERT(m_reader);
+
+ return (nframes_t)(frame * ((double) m_outputRate / m_rate));
+}
+
Index: src/audiofileio/decode/ResampleAudioReader.h
===================================================================
RCS file: src/audiofileio/decode/ResampleAudioReader.h
diff -N src/audiofileio/decode/ResampleAudioReader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/ResampleAudioReader.h 31 Jul 2007 18:45:12
-0000 1.1
@@ -0,0 +1,61 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef RESAMPLEAUDIOREADER_H
+#define RESAMPLEAUDIOREADER_H
+
+#include <AbstractAudioReader.h>
+#include <QVector>
+#include <samplerate.h>
+
+
+class ResampleAudioReader : public AbstractAudioReader
+{
+
+public:
+ ResampleAudioReader(QString filename, int converter_type);
+ ~ResampleAudioReader();
+
+ int get_output_rate();
+ void set_output_rate(int rate);
+
+protected:
+ void init(int converter_type);
+ void reset();
+
+ bool seek_private(nframes_t start);
+ nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
+
+ nframes_t song_to_file_frame(nframes_t frame);
+ nframes_t file_to_song_frame(nframes_t frame);
+
+ bool m_valid;
+ AbstractAudioReader* m_reader;
+ QVector<SRC_STATE*> m_srcStates;
+ SRC_DATA m_srcData;
+ QVector<audio_sample_t*> m_fileBuffers;
+ QVector<audio_sample_t*> m_filePointers;
+ long m_fileBufferLength;
+ long m_overflowUsed;
+ int m_outputRate;
+};
+
+#endif
Index: src/audiofileio/decode/SFAudioReader.cpp
===================================================================
RCS file: src/audiofileio/decode/SFAudioReader.cpp
diff -N src/audiofileio/decode/SFAudioReader.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/SFAudioReader.cpp 31 Jul 2007 18:45:13 -0000
1.1
@@ -0,0 +1,144 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "SFAudioReader.h"
+#include <QFile>
+#include <QString>
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+SFAudioReader::SFAudioReader(QString filename)
+ : AbstractAudioReader(filename)
+{
+ /* although libsndfile says we don't need to set this,
+ valgrind and source code shows us that we do.
+ Really? Look it up !
+ */
+ memset (&m_sfinfo, 0, sizeof(m_sfinfo));
+
+ if ((m_sf = sf_open (m_fileName.toUtf8().data(), SFM_READ, &m_sfinfo))
== 0) {
+ PERROR("Couldn't open soundfile (%s)",
m_fileName.toUtf8().data());
+ }
+
+ m_channels = m_sfinfo.channels;
+ m_length = m_sfinfo.frames;
+ m_rate = m_sfinfo.samplerate;
+
+ m_tmpBuffer = 0;
+ m_tmpBufferSize = 0;
+}
+
+
+SFAudioReader::~SFAudioReader()
+{
+ if (m_tmpBuffer) {
+ delete m_tmpBuffer;
+ }
+
+ if (m_sf) {
+ if (sf_close(m_sf)) {
+ qWarning("sf_close returned an error!");
+ }
+ }
+}
+
+
+bool SFAudioReader::can_decode(QString filename)
+{
+ SF_INFO infos;
+
+ /* although libsndfile says we don't need to set this,
+ valgrind and source code shows us that we do.
+ Really? Look it up !
+ */
+ memset (&infos, 0, sizeof(infos));
+
+ SNDFILE* sndfile = sf_open(QFile::encodeName(filename), SFM_READ,
&infos);
+
+ //is it supported by libsndfile?
+ if (!sndfile) {
+ return false;
+ }
+
+ sf_close(sndfile);
+
+ return true;
+}
+
+
+bool SFAudioReader::seek_private(nframes_t start)
+{
+ Q_ASSERT(m_sf);
+
+
+ if (start >= m_length) {
+ return false;
+ }
+
+ if (sf_seek (m_sf, (off_t) start, SEEK_SET) < 0) {
+ char errbuf[256];
+ sf_error_str (0, errbuf, sizeof (errbuf) - 1);
+ PERROR("ReadAudioSource: could not seek to frame %d within %s
(%s)", start, m_fileName.toUtf8().data(), errbuf);
+ return false;
+ }
+
+ return true;
+}
+
+
+nframes_t SFAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
+{
+ Q_ASSERT(m_sf);
+
+ // Make sure the temp buffer is big enough for this read
+ if (m_tmpBufferSize < frameCount) {
+ if (m_tmpBuffer) {
+ delete m_tmpBuffer;
+ }
+ m_tmpBuffer = new audio_sample_t[frameCount * m_channels];
+ }
+ nframes_t framesRead = sf_readf_float(m_sf, m_tmpBuffer, frameCount);
+
+ // De-interlace
+ switch (m_channels) {
+ case 1:
+ memcpy(buffer[0], m_tmpBuffer, framesRead *
sizeof(audio_sample_t));
+ break;
+ case 2:
+ for (int f = 0; f < framesRead; f++) {
+ buffer[0][f] = m_tmpBuffer[f * 2];
+ buffer[1][f] = m_tmpBuffer[f * 2 + 1];
+ }
+ break;
+ default:
+ for (int f = 0; f < framesRead; f++) {
+ for (int c = 0; c < m_channels; c++) {
+ buffer[c][f] = m_tmpBuffer[f *
m_channels + c];
+ }
+ }
+ }
+
+ return framesRead;
+}
+
Index: src/audiofileio/decode/SFAudioReader.h
===================================================================
RCS file: src/audiofileio/decode/SFAudioReader.h
diff -N src/audiofileio/decode/SFAudioReader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/SFAudioReader.h 31 Jul 2007 18:45:13 -0000
1.1
@@ -0,0 +1,47 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef SFAUDIOREADER_H
+#define SFAUDIOREADER_H
+
+#include <AbstractAudioReader.h>
+#include "sndfile.h"
+
+
+class SFAudioReader : public AbstractAudioReader
+{
+public:
+ SFAudioReader(QString filename);
+ ~SFAudioReader();
+
+ static bool can_decode(QString filename);
+
+protected:
+ bool seek_private(nframes_t start);
+ nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
+
+ SNDFILE* m_sf;
+ SF_INFO m_sfinfo;
+ audio_sample_t *m_tmpBuffer;
+ int m_tmpBufferSize;
+};
+
+#endif
Index: src/audiofileio/decode/VorbisAudioReader.cpp
===================================================================
RCS file: src/audiofileio/decode/VorbisAudioReader.cpp
diff -N src/audiofileio/decode/VorbisAudioReader.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/VorbisAudioReader.cpp 31 Jul 2007 18:45:13
-0000 1.1
@@ -0,0 +1,139 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "VorbisAudioReader.h"
+#include <QFile>
+#include <QString>
+
+#ifdef _WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+VorbisAudioReader::VorbisAudioReader(QString filename)
+ : AbstractAudioReader(filename)
+{
+ m_file = fopen(filename.toUtf8().data(), "rb");
+ if (!m_file) {
+ PERROR("Couldn't open file %s.", filename.toUtf8().data());
+ return;
+ }
+
+ if (ov_open(m_file, &m_vf, 0, 0) < 0) {
+ PERROR("Input does not appear to be an Ogg bitstream.");
+ fclose(m_file);
+ return;
+ }
+
+ ov_pcm_seek(&m_vf, 0);
+ m_vi = ov_info(&m_vf,-1);
+
+ m_channels = m_vi->channels;
+ m_length = ov_pcm_total(&m_vf, -1);
+ m_rate = m_vi->rate;
+}
+
+
+VorbisAudioReader::~VorbisAudioReader()
+{
+ if (m_file) {
+ ov_clear(&m_vf);
+ }
+}
+
+
+bool VorbisAudioReader::can_decode(QString filename)
+{
+ FILE* file = fopen(filename.toUtf8().data(), "rb");
+ if (!file) {
+ PERROR("Could not open file: %s.", filename.toUtf8().data());
+ return false;
+ }
+
+ OggVorbis_File of;
+
+ if (ov_test(file, &of, 0, 0)) {
+ fclose(file);
+ return false;
+ }
+
+ ov_clear(&of);
+
+ return true;
+}
+
+
+bool VorbisAudioReader::seek_private(nframes_t start)
+{
+ Q_ASSERT(m_file);
+
+ if (start >= m_length) {
+ return false;
+ }
+
+ if (int result = ov_pcm_seek(&m_vf, start) < 0) {
+ PERROR("VorbisAudioReader: could not seek to frame %d within %s
(%d)", start, m_fileName.toUtf8().data(), result);
+ return false;
+ }
+
+ return true;
+}
+
+
+nframes_t VorbisAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
+{
+ Q_ASSERT(m_file);
+
+ nframes_t totalFramesRead = 0;
+
+ while (totalFramesRead < frameCount) {
+ audio_sample_t** tmp;
+ int bs;
+ int framesRead = ov_read_float(&m_vf, &tmp, frameCount -
totalFramesRead, &bs);
+
+ if (framesRead == OV_HOLE) {
+ // Hole detected: recursive retry
+ PERROR("VorbisAudioReader: OV_HOLE");
+ return read(buffer, frameCount);
+ }
+ else if (framesRead == 0) {
+ /* EOF */
+ break;
+ } else if (framesRead < 0) {
+ /* error in the stream. */
+ PERROR("VorbisFile decoding error");
+ break;
+ }
+
+ for (int c=0; c < m_channels; c++) {
+ memcpy(buffer[c] + totalFramesRead, tmp[c], framesRead
* sizeof(audio_sample_t));
+ }
+ totalFramesRead += framesRead;
+ }
+
+ return totalFramesRead;
+}
+
Index: src/audiofileio/decode/VorbisAudioReader.h
===================================================================
RCS file: src/audiofileio/decode/VorbisAudioReader.h
diff -N src/audiofileio/decode/VorbisAudioReader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/VorbisAudioReader.h 31 Jul 2007 18:45:13 -0000
1.1
@@ -0,0 +1,48 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef VORBISAUDIOREADER_H
+#define VORBISAUDIOREADER_H
+
+#include "AbstractAudioReader.h"
+#include "vorbis/codec.h"
+#include "vorbis/vorbisfile.h"
+#include "stdio.h"
+
+
+class VorbisAudioReader : public AbstractAudioReader
+{
+public:
+ VorbisAudioReader(QString filename);
+ ~VorbisAudioReader();
+
+ static bool can_decode(QString filename);
+
+protected:
+ bool seek_private(nframes_t start);
+ nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
+
+ FILE* m_file;
+ OggVorbis_File m_vf;
+ vorbis_info* m_vi;
+};
+
+#endif
Index: src/audiofileio/decode/WPAudioReader.cpp
===================================================================
RCS file: src/audiofileio/decode/WPAudioReader.cpp
diff -N src/audiofileio/decode/WPAudioReader.cpp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/WPAudioReader.cpp 31 Jul 2007 18:45:13 -0000
1.1
@@ -0,0 +1,155 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#include "WPAudioReader.h"
+#include <QString>
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+WPAudioReader::WPAudioReader(QString filename)
+ : AbstractAudioReader(filename)
+{
+ char error[80];
+
+ m_wp = WavpackOpenFileInput(m_fileName.toUtf8().data(), error,
OPEN_2CH_MAX, 1);
+
+ if (m_wp == 0) {
+ PERROR("Couldn't open soundfile (%s) %s",
filename.toUtf8().data(), error);
+ }
+
+ m_isFloat = ((WavpackGetMode(m_wp) & MODE_FLOAT) != 0);
+ m_bitsPerSample = WavpackGetBitsPerSample(m_wp);
+ m_channels = WavpackGetReducedChannels(m_wp);
+ m_length = WavpackGetNumSamples(m_wp);
+ m_rate = WavpackGetSampleRate(m_wp);
+
+ m_tmpBuffer = 0;
+ m_tmpBufferSize = 0;
+}
+
+
+WPAudioReader::~WPAudioReader()
+{
+ if (m_tmpBuffer) {
+ delete m_tmpBuffer;
+ }
+
+ if (m_wp) {
+ WavpackCloseFile(m_wp);
+ }
+}
+
+
+bool WPAudioReader::can_decode(QString filename)
+{
+ char error[80];
+
+ WavpackContext *wp = WavpackOpenFileInput(filename.toUtf8().data(),
error, OPEN_2CH_MAX, 1);
+
+ if (wp == 0) {
+ return false;
+ }
+
+ WavpackCloseFile(wp);
+
+ return true;
+}
+
+
+bool WPAudioReader::seek_private(nframes_t start)
+{
+ Q_ASSERT(m_wp);
+
+
+ if (start >= m_length) {
+ return false;
+ }
+
+ if (!WavpackSeekSample(m_wp, start)) {
+ PERROR("could not seek to frame %d within %s", start,
m_fileName.toUtf8().data());
+ return false;
+ }
+
+ return true;
+}
+
+
+nframes_t WPAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
+{
+ Q_ASSERT(m_wp);
+
+ // Make sure the temp buffer is big enough for this read
+ if (m_tmpBufferSize < frameCount) {
+ if (m_tmpBuffer) {
+ delete m_tmpBuffer;
+ }
+ m_tmpBuffer = new int32_t[frameCount * m_channels];
+ }
+ nframes_t framesRead = WavpackUnpackSamples(m_wp, m_tmpBuffer,
frameCount);
+
+ // De-interlace
+ if (m_isFloat) {
+ switch (m_channels) {
+ case 1:
+ memcpy(buffer[0], m_tmpBuffer, framesRead *
sizeof(audio_sample_t));
+ break;
+ case 2:
+ for (int f = 0; f < framesRead; f++) {
+ buffer[0][f] = ((float*)m_tmpBuffer)[f
* 2];
+ buffer[1][f] = ((float*)m_tmpBuffer)[f
* 2 + 1];
+ }
+ break;
+ default:
+ for (int f = 0; f < framesRead; f++) {
+ for (int c = 0; c < m_channels; c++) {
+ buffer[c][f] =
((float*)m_tmpBuffer)[f * m_channels + c];
+ }
+ }
+ }
+ }
+ else {
+ switch (m_channels) {
+ case 1:
+ for (int f = 0; f < framesRead; f++) {
+ buffer[0][f] =
(float)((float)m_tmpBuffer[f]/ (float)((uint)1<<(m_bitsPerSample-1)));
+ }
+ break;
+ case 2:
+ for (int f = 0; f < framesRead; f++) {
+ buffer[0][f] =
(float)((float)m_tmpBuffer[f * 2]/ (float)((uint)1<<(m_bitsPerSample-1)));
+ buffer[1][f] =
(float)((float)m_tmpBuffer[f * 2 + 1]/ (float)((uint)1<<(m_bitsPerSample-1)));
+ }
+ break;
+ default:
+ for (int f = 0; f < framesRead; f++) {
+ for (int c = 0; c < m_channels; c++) {
+ buffer[c][f] =
(float)((float)m_tmpBuffer[f + m_channels + c]/
(float)((uint)1<<(m_bitsPerSample-1)));
+ }
+ }
+ }
+ }
+
+ return framesRead;
+}
+
Index: src/audiofileio/decode/WPAudioReader.h
===================================================================
RCS file: src/audiofileio/decode/WPAudioReader.h
diff -N src/audiofileio/decode/WPAudioReader.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ src/audiofileio/decode/WPAudioReader.h 31 Jul 2007 18:45:13 -0000
1.1
@@ -0,0 +1,48 @@
+/*
+Copyright (C) 2007 Ben Levitt
+
+This file is part of Traverso
+
+Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+
+*/
+
+#ifndef WPAUDIOREADER_H
+#define WPAUDIOREADER_H
+
+#include <AbstractAudioReader.h>
+#include "wavpack/wavpack.h"
+
+
+class WPAudioReader : public AbstractAudioReader
+{
+public:
+ WPAudioReader(QString filename);
+ ~WPAudioReader();
+
+ static bool can_decode(QString filename);
+
+protected:
+ bool seek_private(nframes_t start);
+ nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
+
+ WavpackContext* m_wp;
+ bool m_isFloat;
+ int m_bitsPerSample;
+ int32_t *m_tmpBuffer;
+ int m_tmpBufferSize;
+};
+
+#endif
Index: src/core/AbstractAudioReader.cpp
===================================================================
RCS file: src/core/AbstractAudioReader.cpp
diff -N src/core/AbstractAudioReader.cpp
--- src/core/AbstractAudioReader.cpp 25 Jul 2007 17:06:16 -0000 1.15
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,153 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#include "AbstractAudioReader.h"
-#include "SFAudioReader.h"
-#include "FlacAudioReader.h"
-#include "MadAudioReader.h"
-#include "WPAudioReader.h"
-#include "VorbisAudioReader.h"
-#include "ResampleAudioReader.h"
-
-#include <QString>
-
-// Always put me below _all_ includes, this is needed
-// in case we run with memory leak detection enabled!
-#include "Debugger.h"
-
-
-AbstractAudioReader::AbstractAudioReader(const QString& filename)
- : QObject(0)
-{
- m_fileName = filename;
- m_readPos = 0;
-}
-
-
-AbstractAudioReader::~AbstractAudioReader()
-{
-}
-
-
-// Read cnt frames starting at start from the AudioReader, into dst
-// uses seek() and read() from AudioReader subclass
-nframes_t AbstractAudioReader::read_from(audio_sample_t** buffer, nframes_t
start, nframes_t count)
-{
-// printf("read_from:: before_seek from %d, framepos is %d\n", start,
m_readPos);
-
- if (!seek(start)) {
- return 0;
- }
-
- return read(buffer, count);
-}
-
-
-int AbstractAudioReader::get_num_channels()
-{
- return m_channels;
-}
-
-
-nframes_t AbstractAudioReader::get_length()
-{
- return m_length;
-}
-
-
-int AbstractAudioReader::get_file_rate()
-{
- return m_rate;
-}
-
-
-bool AbstractAudioReader::eof()
-{
- return (m_readPos >= m_length);
-}
-
-
-nframes_t AbstractAudioReader::pos()
-{
- return m_readPos;
-}
-
-
-bool AbstractAudioReader::seek(nframes_t start)
-{
- if (m_readPos != start) {
- if (!seek_private(start)) {
- return false;
- }
- m_readPos = start;
- }
-
- return true;
-}
-
-
-nframes_t AbstractAudioReader::read(audio_sample_t** buffer, nframes_t count)
-{
- if (count && m_readPos < m_length) {
- // printf("read_from:: after_seek from %d, framepos is %d\n",
start, m_readPos);
- nframes_t framesRead = read_private(buffer, count);
-
- m_readPos += framesRead;
-
- return framesRead;
- }
-
- return 0;
-}
-
-
-// Static method used by other classes to get an AudioReader for the correct
file type
-AbstractAudioReader* AbstractAudioReader::create_audio_reader(const QString&
filename)
-{
- AbstractAudioReader* newReader;
-
- if (FlacAudioReader::can_decode(filename)) {
- newReader = new FlacAudioReader(filename);
- }
- else if (VorbisAudioReader::can_decode(filename)) {
- newReader = new VorbisAudioReader(filename);
- }
- else if (WPAudioReader::can_decode(filename)) {
- newReader = new WPAudioReader(filename);
- }
- else if (SFAudioReader::can_decode(filename)) {
- newReader = new SFAudioReader(filename);
- }
- else if (MadAudioReader::can_decode(filename)) {
- newReader = new MadAudioReader(filename);
- }
- else {
- return 0;
- }
-
- if (newReader->get_num_channels() <= 0) {
- PERROR("new reader has 0 channels!");
- return 0;
- }
-
- return newReader;
-}
-
Index: src/core/AbstractAudioReader.h
===================================================================
RCS file: src/core/AbstractAudioReader.h
diff -N src/core/AbstractAudioReader.h
--- src/core/AbstractAudioReader.h 25 Jul 2007 17:06:16 -0000 1.13
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,63 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#ifndef ABSTRACTAUDIOREADER_H
-#define ABSTRACTAUDIOREADER_H
-
-#include <QObject>
-
-#include "defines.h"
-
-class QString;
-
-class AbstractAudioReader : public QObject
-{
- Q_OBJECT
-
-public:
- AbstractAudioReader(const QString& filename);
- ~AbstractAudioReader();
-
- int get_num_channels();
- nframes_t get_length();
- int get_file_rate();
- bool eof();
- nframes_t pos();
-
- nframes_t read_from(audio_sample_t** buffer, nframes_t start, nframes_t
count);
- bool seek(nframes_t start);
- nframes_t read(audio_sample_t** buffer, nframes_t frameCount);
-
- static AbstractAudioReader* create_audio_reader(const QString&
filename);
-
-protected:
- virtual bool seek_private(nframes_t start) = 0;
- virtual nframes_t read_private(audio_sample_t** buffer, nframes_t
frameCount) = 0;
-
- QString m_fileName;
-
- nframes_t m_readPos;
- nframes_t m_channels;
- nframes_t m_length;
- nframes_t m_rate;
-};
-
-#endif
Index: src/core/FlacAudioReader.cpp
===================================================================
RCS file: src/core/FlacAudioReader.cpp
diff -N src/core/FlacAudioReader.cpp
--- src/core/FlacAudioReader.cpp 25 Jul 2007 17:06:16 -0000 1.13
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,572 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
- * Based on the FLAC decoder module for K3b.
- * Based on the Ogg Vorbis module for same.
- * Copyright (C) 1998-2007 Sebastian Trueg <address@hidden>
- * Copyright (C) 2003-2004 John Steele Scott <address@hidden>
-
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#include "FlacAudioReader.h"
-#include <QFile>
-#include <QString>
-
-#include "FLAC/export.h"
-
-#if !defined FLAC_API_VERSION_CURRENT || FLAC_API_VERSION_CURRENT < 6
-#define LEGACY_FLAC
-#include "FLAC/seekable_stream_decoder.h"
-#else
-#undef LEGACY_FLAC
-#include "FLAC/stream_decoder.h"
-#endif
-
-
-// Always put me below _all_ includes, this is needed
-// in case we run with memory leak detection enabled!
-#include "Debugger.h"
-
-
-class FlacPrivate
-{
- public:
- FlacPrivate(QString filename)
- {
- internalBuffer = 0;
- bufferSize = 0;
- bufferUsed = 0;
- bufferStart = 0;
- open(filename);
- }
-
-
- ~FlacPrivate()
- {
- cleanup();
- }
-
-
- bool open(QString filename)
- {
- file = new QFile(filename);
- if (!file->open(QIODevice::ReadOnly)) {
- return false;
- }
-
-#ifdef LEGACY_FLAC
- flac = FLAC__seekable_stream_decoder_new();
-
- FLAC__seekable_stream_decoder_set_read_callback(flac,
FlacPrivate::read_callback);
- FLAC__seekable_stream_decoder_set_seek_callback(flac,
FlacPrivate::seek_callback);
- FLAC__seekable_stream_decoder_set_tell_callback(flac,
FlacPrivate::tell_callback);
- FLAC__seekable_stream_decoder_set_length_callback(flac,
FlacPrivate::length_callback);
- FLAC__seekable_stream_decoder_set_eof_callback(flac,
FlacPrivate::eof_callback);
- FLAC__seekable_stream_decoder_set_write_callback(flac,
FlacPrivate::write_callback);
-
FLAC__seekable_stream_decoder_set_metadata_callback(flac,
FlacPrivate::metadata_callback);
- FLAC__seekable_stream_decoder_set_error_callback(flac,
FlacPrivate::error_callback);
- FLAC__seekable_stream_decoder_set_client_data(flac,
this);
-
- FLAC__seekable_stream_decoder_init(flac);
-
FLAC__seekable_stream_decoder_process_until_end_of_metadata(flac);
-#else
- flac = FLAC__stream_decoder_new();
-
- FLAC__stream_decoder_init_stream(flac,
- FlacPrivate::read_callback,
- FlacPrivate::seek_callback,
- FlacPrivate::tell_callback,
- FlacPrivate::length_callback,
- FlacPrivate::eof_callback,
- FlacPrivate::write_callback,
- FlacPrivate::metadata_callback,
- FlacPrivate::error_callback,
- this);
-
-
FLAC__stream_decoder_process_until_end_of_metadata(flac);
-#endif
- return true;
- }
-
-
- bool is_valid() { return (flac != 0); }
-#ifdef LEGACY_FLAC
- bool flush() { return
FLAC__seekable_stream_decoder_flush(flac); }
- bool finish() { return
FLAC__seekable_stream_decoder_finish(flac); }
- bool reset() { return
FLAC__seekable_stream_decoder_reset(flac); }
- bool process_single() { return
FLAC__seekable_stream_decoder_process_single(flac); }
- FLAC__SeekableStreamDecoderState get_state() { return
FLAC__seekable_stream_decoder_get_state(flac); }
-#else
- bool flush() { return FLAC__stream_decoder_flush(flac); }
- bool finish() { return FLAC__stream_decoder_finish(flac); }
- bool reset() { return FLAC__stream_decoder_reset(flac); }
- bool process_single() { return
FLAC__stream_decoder_process_single(flac); }
- FLAC__StreamDecoderState get_state() { return
FLAC__stream_decoder_get_state(flac); }
-#endif
-
-
- void cleanup()
- {
- if (internalBuffer) {
- delete internalBuffer;
- }
- file->close();
- delete file;
-
- finish();
-
-#ifdef LEGACY_FLAC
- FLAC__seekable_stream_decoder_delete(flac);
-#else
- FLAC__stream_decoder_delete(flac);
-#endif
- }
-
-
- bool seek(nframes_t start)
- {
-#ifdef LEGACY_FLAC
- return
FLAC__seekable_stream_decoder_seek_absolute(flac, start);
-#else
- return FLAC__stream_decoder_seek_absolute(flac, start);
-#endif
- }
-
- uint m_channels;
- uint m_rate;
- uint m_bitsPerSample;
- uint m_samples;
-
- audio_sample_t *internalBuffer;
- int bufferSize;
- int bufferUsed;
- int bufferStart;
-
- protected:
-#ifdef LEGACY_FLAC
- static FLAC__SeekableStreamDecoderReadStatus
read_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[],
unsigned *bytes, void *client_data);
- static FLAC__SeekableStreamDecoderSeekStatus
seek_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64
absolute_byte_offset, void *client_data);
- static FLAC__SeekableStreamDecoderTellStatus
tell_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64
*absolute_byte_offset, void *client_data);
- static FLAC__SeekableStreamDecoderLengthStatus
length_callback(const FLAC__SeekableStreamDecoder *decoder, FLAC__uint64
*stream_length, void *client_data);
- static FLAC__bool eof_callback(const
FLAC__SeekableStreamDecoder *decoder, void *client_data);
- static void error_callback(const FLAC__SeekableStreamDecoder
*decoder, FLAC__StreamDecoderErrorStatus s, void *client_data){ printf("!!! %d
!!!\n", s); };
- static void metadata_callback(const FLAC__SeekableStreamDecoder
*decoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
- static FLAC__StreamDecoderWriteStatus write_callback(const
FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const
FLAC__int32 * const buffer[], void *client_data);
-#else
- static FLAC__StreamDecoderReadStatus read_callback(const
FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void
*client_data);
- static FLAC__StreamDecoderSeekStatus seek_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void
*client_data);
- static FLAC__StreamDecoderTellStatus tell_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void
*client_data);
- static FLAC__StreamDecoderLengthStatus length_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data);
- static FLAC__bool eof_callback(const FLAC__StreamDecoder
*decoder, void *client_data);
- static void error_callback(const FLAC__StreamDecoder *decoder,
FLAC__StreamDecoderErrorStatus s, void *client_data){ printf("!!! %d !!!\n",
s); };
- static void metadata_callback(const FLAC__StreamDecoder
*decoder, const ::FLAC__StreamMetadata *metadata, void *client_data);
- static FLAC__StreamDecoderWriteStatus write_callback(const
FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *
const buffer[], void *client_data);
-#endif
-
- QFile *file;
-#ifdef LEGACY_FLAC
- FLAC__SeekableStreamDecoder *flac;
-#else
- FLAC__StreamDecoder *flac;
-#endif
-};
-
-
-#ifdef LEGACY_FLAC
-FLAC__StreamDecoderWriteStatus FlacPrivate::write_callback(const
FLAC__SeekableStreamDecoder *decoder, const FLAC__Frame *frame, const
FLAC__int32 * const buffer[], void *client_data)
-#else
-FLAC__StreamDecoderWriteStatus FlacPrivate::write_callback(const
FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *
const buffer[], void *client_data)
-#endif
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- unsigned i, c, pos = 0;
- int frames = frame->header.blocksize;
-
- if (fp->bufferUsed > 0) {
- // This shouldn't be happening
- PERROR("internalBuffer is already non-empty");
- }
-
- if (fp->bufferSize < frames * frame->header.channels) {
- if (fp->internalBuffer) {
- delete fp->internalBuffer;
- }
- fp->internalBuffer = new audio_sample_t[frames *
frame->header.channels];
- fp->bufferSize = frames * frame->header.channels;
- }
-
- for (i=0; i < frames; i++) {
- // in FLAC channel 0 is left, 1 is right
- for (c=0; c < frame->header.channels; c++) {
- audio_sample_t value =
(audio_sample_t)((float)buffer[c][i] /
(float)((uint)1<<(frame->header.bits_per_sample-1)));
- fp->internalBuffer[pos++] = value;
- }
- }
-
- fp->bufferUsed = frames * frame->header.channels;
-
- return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
-}
-
-
-#ifdef LEGACY_FLAC
-FLAC__SeekableStreamDecoderReadStatus FlacPrivate::read_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__byte buffer[], unsigned *bytes,
void *client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- long retval = fp->file->read((char *)buffer, (*bytes));
- if(retval == -1) {
- return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR;
- } else {
- (*bytes) = retval;
- return FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK;
- }
-}
-#else
-FLAC__StreamDecoderReadStatus FlacPrivate::read_callback(const
FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void
*client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- long retval = fp->file->read((char *)buffer, (*bytes));
- if(retval == -1) {
- return FLAC__STREAM_DECODER_READ_STATUS_ABORT;
- } else {
- (*bytes) = retval;
- return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE;
- }
-}
-#endif
-
-#ifdef LEGACY_FLAC
-FLAC__SeekableStreamDecoderSeekStatus FlacPrivate::seek_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void
*client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- if(!fp->file->seek(absolute_byte_offset))
- return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR;
- else
- return FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK;
-}
-#else
-FLAC__StreamDecoderSeekStatus FlacPrivate::seek_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void
*client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- if(!fp->file->seek(absolute_byte_offset))
- return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
- else
- return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
-}
-#endif
-
-#ifdef LEGACY_FLAC
-FLAC__SeekableStreamDecoderTellStatus FlacPrivate::tell_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void
*client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- (*absolute_byte_offset) = fp->file->pos();
- return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
-}
-#else
-FLAC__StreamDecoderTellStatus FlacPrivate::tell_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void
*client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- (*absolute_byte_offset) = fp->file->pos();
- return FLAC__STREAM_DECODER_TELL_STATUS_OK;
-}
-#endif
-
-#ifdef LEGACY_FLAC
-FLAC__SeekableStreamDecoderLengthStatus FlacPrivate::length_callback(const
FLAC__SeekableStreamDecoder *decoder, FLAC__uint64 *stream_length, void
*client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- (*stream_length) = fp->file->size();
- return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
-}
-#else
-FLAC__StreamDecoderLengthStatus FlacPrivate::length_callback(const
FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data)
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- (*stream_length) = fp->file->size();
- return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
-}
-#endif
-
-
-#ifdef LEGACY_FLAC
-void FlacPrivate::metadata_callback(const FLAC__SeekableStreamDecoder
*decoder, const FLAC__StreamMetadata *metadata, void *client_data)
-#else
-void FlacPrivate::metadata_callback(const FLAC__StreamDecoder *decoder, const
FLAC__StreamMetadata *metadata, void *client_data)
-#endif
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- switch (metadata->type)
- {
- case FLAC__METADATA_TYPE_STREAMINFO:
- fp->m_channels = metadata->data.stream_info.channels;
- fp->m_rate = metadata->data.stream_info.sample_rate;
- fp->m_bitsPerSample =
metadata->data.stream_info.bits_per_sample;
- fp->m_samples =
metadata->data.stream_info.total_samples;
- break;
- case FLAC__METADATA_TYPE_VORBIS_COMMENT:
- //comments = new
FLAC::Metadata::VorbisComment((FLAC__StreamMetadata *)metadata, true);
- break;
- default:
- break;
- }
-}
-
-
-#ifdef LEGACY_FLAC
-FLAC__bool FlacPrivate::eof_callback(const FLAC__SeekableStreamDecoder
*decoder, void *client_data)
-#else
-FLAC__bool FlacPrivate::eof_callback(const FLAC__StreamDecoder *decoder, void
*client_data)
-#endif
-{
- FlacPrivate *fp = (FlacPrivate*)client_data;
-
- return fp->file->atEnd();
-}
-
-
-
-
-FlacAudioReader::FlacAudioReader(QString filename)
- : AbstractAudioReader(filename)
-{
- m_flac = new FlacPrivate(filename);
-
- if (m_flac) {
- m_channels = m_flac->m_channels;
- m_length = m_flac->m_samples;
- m_rate = m_flac->m_rate;
- }
-}
-
-
-FlacAudioReader::~FlacAudioReader()
-{
- if (m_flac) {
- delete m_flac;
- }
-}
-
-
-bool FlacAudioReader::can_decode(QString filename)
-{
- // buffer large enough to read an ID3 tag header
- char buf[10];
-
- // Note: since file is created on the stack it will be closed
automatically
- // by its destructor when this method (i.e. canDecode) returns.
- QFile f(filename);
-
- if (!f.open(QIODevice::ReadOnly)) {
- PERROR("Could not open file %s", filename.toUtf8().data());
- return false;
- }
-
- // look for a fLaC magic number or ID3 tag header
- if (10 != f.read(buf, 10)) {
- //PERROR("File too small to be a FLAC file: %s",
QS_C(filename));
- return false;
- }
-
- if (0 == memcmp(buf, "ID3", 3)) {
- // Found ID3 tag, try and seek past it.
- //kdDebug() << "(K3bFLACDecorder) File " << filename << ":
found ID3 tag" << endl;
-
- // See www.id3.org for details of the header, note that the
size field
- // unpacks to 7-bit bytes, then the +10 is for the header
itself.
- int pos;
- pos = ((buf[6]<<21)|(buf[7]<<14)|(buf[8]<<7)|buf[9]) + 10;
-
- //kdDebug() << "(K3bFLACDecoder) " << filename << ": seeking to
"
- // << pos << endl;
- if (!f.seek(pos)) {
- //PERROR("Couldn't seek to %d in file: %s", pos,
QS_C(filename));
- return false;
- }
- else {
- // seek was okay, try and read magic number into buf
- if (4 != f.read(buf, 4)) {
- //PERROR("File has ID3 tag but nothing else:
%s", QS_C(filename));
- return false;
- }
- }
- }
-
- if (memcmp(buf, "fLaC", 4) != 0) {
- //PERROR("Not a flac file: %s", QS_C(filename));
- return false;
- }
-
- f.close();
-
- FlacPrivate flac(filename);
-
- bool valid = flac.is_valid();
-
- flac.finish();
-
- //PERROR("Return: Is%s a flac file: %s", ((valid) ? "" : " not"),
QS_C(filename));
- return valid;
-}
-
-
-bool FlacAudioReader::seek_private(nframes_t start)
-{
- Q_ASSERT(m_flac);
-
- if (start >= get_length()) {
- PERROR("FlacAudioReader: could not seek to frame %d within %s,
it's past the end.", start, m_fileName.toUtf8().data());
- return false;
- }
-
- m_flac->bufferUsed = 0;
- m_flac->bufferStart = 0;
-
- m_flac->flush();
-
- if (!m_flac->seek(start)) {
- PERROR("FlacAudioReader: could not seek to frame %d within %s",
start, m_fileName.toUtf8().data());
- return false;
- }
-
- return true;
-}
-
-
-nframes_t FlacAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
-{
- Q_ASSERT(m_flac);
-
- nframes_t framesToCopy;
- nframes_t framesAvailable;
- nframes_t framesCoppied = 0;
-
- while (framesCoppied < frameCount) {
- if (m_flac->bufferUsed == 0) {
- // want more data
-#ifdef LEGACY_FLAC
- if (m_flac->get_state() ==
FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM) {
- //printf("flac file finish\n");
- m_flac->flush();
- m_flac->reset();
- break;
- }
- else if(m_flac->get_state() ==
FLAC__SEEKABLE_STREAM_DECODER_OK) {
- //printf("process\n");
- if (!m_flac->process_single()) {
- PERROR("process_single() error\n");
- m_flac->reset();
- seek(m_readPos);
- return 0;
- }
- }
- else {
- PERROR("flac_state() = %d\n",
int(m_flac->get_state()));
- m_flac->reset();
- seek(m_readPos);
- return 0;
- }
-#else
- if (m_flac->get_state() ==
FLAC__STREAM_DECODER_END_OF_STREAM) {
- //printf("flac file finish\n");
- m_flac->flush();
- m_flac->reset();
- break;
- }
- else if(m_flac->get_state() <
FLAC__STREAM_DECODER_END_OF_STREAM) {
- //printf("process\n");
- if (!m_flac->process_single()) {
- PERROR("process_single() error\n");
- m_flac->reset();
- seek(m_readPos);
- return 0;
- }
- }
- else {
- PERROR("flac_state() = %d\n",
int(m_flac->get_state()));
- m_flac->reset();
- seek(m_readPos);
- return 0;
- }
-#endif
- }
-
- framesAvailable = (m_flac->bufferUsed - m_flac->bufferStart) /
get_num_channels() ;
- framesToCopy = (frameCount - framesCoppied < framesAvailable) ?
frameCount - framesCoppied : framesAvailable;
- switch (get_num_channels()) {
- case 1:
- memcpy(buffer[0] + framesCoppied,
m_flac->internalBuffer + m_flac->bufferStart, framesToCopy);
- break;
- case 2:
- for (int i = 0; i < framesToCopy; i++) {
- buffer[0][framesCoppied + i] =
m_flac->internalBuffer[m_flac->bufferStart + i * 2];
- buffer[1][framesCoppied + i] =
m_flac->internalBuffer[m_flac->bufferStart + i * 2 + 1];
- }
- break;
- default:
- for (int i = 0; i < framesToCopy; i++) {
- for (int c = 0; c < get_num_channels();
c++) {
- buffer[c][framesCoppied + i] =
m_flac->internalBuffer[m_flac->bufferStart + i * get_num_channels() + c];
- }
- }
- break;
- }
-
- if(framesToCopy == framesAvailable) {
- m_flac->bufferUsed = 0;
- m_flac->bufferStart = 0;
- }
- else {
- m_flac->bufferStart += framesToCopy *
get_num_channels();
- }
- framesCoppied += framesToCopy;
-
- //printf("samplesCoppied = %d (%d, %d)\n", samplesCoppied,
m_flac->bufferStart, m_flac->buferSize);
- }
-
- // Pad end of file with 0s if necessary. (Shouldn't be necessary...)
- /*int remainingFramesRequested = frameCount - framesCoppied;
- int remainingFramesInFile = get_length() - (m_readPos + framesCoppied);
- if (framesCoppied == 0 && remainingFramesInFile > 0) {
- int padLength = (remainingFramesRequested >
remainingFramesInFile) ? remainingFramesInFile : remainingFramesRequested;
- PERROR("padLength: %d", padLength);
- for (int c = 0; c < get_num_channels(); c++) {
- memset(buffer[c] + framesCoppied, 0, padLength *
sizeof(audio_sample_t));
- }
- framesCoppied += padLength;
- }
- if (framesCoppied > frameCount) {
- PERROR("Truncating");
- framesCoppied = frameCount;
- }*/
-
- //printf("copied %d of %d. nextFrame: %lu of %lu\n", framesCoppied,
frameCount, m_readPos, m_length); fflush(stdout);
-
- return framesCoppied;
-}
-
Index: src/core/FlacAudioReader.h
===================================================================
RCS file: src/core/FlacAudioReader.h
diff -N src/core/FlacAudioReader.h
--- src/core/FlacAudioReader.h 24 Jul 2007 17:57:05 -0000 1.5
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,45 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#ifndef FLACAUDIOREADER_H
-#define FLACAUDIOREADER_H
-
-#include "AbstractAudioReader.h"
-
-
-class FlacPrivate;
-
-class FlacAudioReader : public AbstractAudioReader
-{
-public:
- FlacAudioReader(QString filename);
- ~FlacAudioReader();
-
- static bool can_decode(QString filename);
-
-protected:
- bool seek_private(nframes_t start);
- nframes_t read_private(audio_sample_t** buffer, nframes_t sampleCount);
-
- FlacPrivate *m_flac;
-};
-
-#endif
Index: src/core/MadAudioReader.cpp
===================================================================
RCS file: src/core/MadAudioReader.cpp
diff -N src/core/MadAudioReader.cpp
--- src/core/MadAudioReader.cpp 25 Jul 2007 17:06:16 -0000 1.16
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,885 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
- * This file based on the mp3 decoding plugin of the K3b project.
- * Copyright (C) 1998-2007 Sebastian Trueg <address@hidden>
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#include "MadAudioReader.h"
-#include <QFile>
-#include <QString>
-#include <QVector>
-
-// Always put me below _all_ includes, this is needed
-// in case we run with memory leak detection enabled!
-#include "Debugger.h"
-
-
-
-
-static const int INPUT_BUFFER_SIZE = 5*8192;
-
-class K3bMad
-{
-public:
- K3bMad();
- ~K3bMad();
-
- bool open(const QString& filename);
-
- /**
- * @return true if the mad stream contains data
- * false if there is no data left or an error occurred.
- * In the latter case inputError() returns true.
- */
- bool fillStreamBuffer();
-
- /**
- * Skip id3 tags.
- *
- * This will reset the input file.
- */
- bool skipTag();
-
- /**
- * Find first frame and seek to the beginning of that frame.
- * This is used to skip the junk that many mp3 files start with.
- */
- bool seekFirstHeader();
-
- bool eof() const;
- bool inputError() const;
-
- /**
- * Current position in theinput file. This does NOT
- * care about the status of the mad stream. Use streamPos()
- * in that case.
- */
- qint64 inputPos() const;
-
- /**
- * Current absolut position of the decoder stream.
- */
- qint64 streamPos() const;
- bool inputSeek(qint64 pos);
-
- void initMad();
- void cleanup();
-
- bool decodeNextFrame();
- bool findNextHeader();
- bool checkFrameHeader(mad_header* header) const;
-
- mad_stream* madStream;
- mad_frame* madFrame;
- mad_synth* madSynth;
- mad_timer_t* madTimer;
-
-private:
- QFile m_inputFile;
- bool m_madStructuresInitialized;
- unsigned char* m_inputBuffer;
- bool m_bInputError;
-
- int m_channels;
- int m_sampleRate;
-};
-
-
-K3bMad::K3bMad()
- : m_madStructuresInitialized(false),
- m_bInputError(false)
-{
- madStream = new mad_stream;
- madFrame = new mad_frame;
- madSynth = new mad_synth;
- madTimer = new mad_timer_t;
-
- //
- // we allocate additional MAD_BUFFER_GUARD bytes to always be able to
append the
- // zero bytes needed for decoding the last frame.
- //
- m_inputBuffer = new unsigned char[INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD];
-}
-
-
-K3bMad::~K3bMad()
-{
- cleanup();
-
- delete madStream;
- delete madFrame;
- delete madSynth;
- delete madTimer;
-
- delete [] m_inputBuffer;
-}
-
-
-bool K3bMad::open(const QString& filename)
-{
- cleanup();
-
- m_bInputError = false;
- m_channels = m_sampleRate = 0;
-
- m_inputFile.setFileName(filename);
-
- if (!m_inputFile.open(QIODevice::ReadOnly)) {
- PERROR("could not open file %s",
m_inputFile.fileName().toUtf8().data());
- return false;
- }
-
- initMad();
-
- memset(m_inputBuffer, 0, INPUT_BUFFER_SIZE+MAD_BUFFER_GUARD);
-
- return true;
-}
-
-
-bool K3bMad::inputError() const
-{
- return m_bInputError;
-}
-
-
-bool K3bMad::fillStreamBuffer()
-{
- /* The input bucket must be filled if it becomes empty or if
- * it's the first execution of the loop.
- */
- if (madStream->buffer == 0 || madStream->error == MAD_ERROR_BUFLEN) {
- if (eof()) {
- return false;
- }
-
- long readSize, remaining;
- unsigned char* readStart;
-
- if (madStream->next_frame != 0) {
- remaining = madStream->bufend - madStream->next_frame;
- memmove(m_inputBuffer, madStream->next_frame,
remaining);
- readStart = m_inputBuffer + remaining;
- readSize = INPUT_BUFFER_SIZE - remaining;
- }
- else {
- readSize = INPUT_BUFFER_SIZE;
- readStart = m_inputBuffer;
- remaining = 0;
- }
-
- // Fill-in the buffer.
- long result = m_inputFile.read((char*)readStart, readSize);
- if (result < 0) {
- //kdDebug() << "(K3bMad) read error on bitstream)" <<
endl;
- m_bInputError = true;
- return false;
- }
- else if (result == 0) {
- //kdDebug() << "(K3bMad) end of input stream" << endl;
- return false;
- }
- else {
- readStart += result;
-
- if (eof()) {
- //kdDebug() << "(K3bMad::fillStreamBuffer)
MAD_BUFFER_GUARD" << endl;
- memset(readStart, 0, MAD_BUFFER_GUARD);
- result += MAD_BUFFER_GUARD;
- }
-
- // Pipe the new buffer content to libmad's stream
decoder facility.
- mad_stream_buffer(madStream, m_inputBuffer, result +
remaining);
- madStream->error = MAD_ERROR_NONE;
- }
- }
-
- return true;
-}
-
-
-bool K3bMad::skipTag()
-{
- // skip the tag at the beginning of the file
- m_inputFile.seek(0);
-
- //
- // now check if the file starts with an id3 tag and skip it if so
- //
- char buf[4096];
- int bufLen = 4096;
- if (m_inputFile.read(buf, bufLen) < bufLen) {
- //kdDebug() << "(K3bMad) unable to read " << bufLen << " bytes
from "
- // << m_inputFile.name() << endl;
- return false;
- }
-
- if ((buf[0] == 'I' && buf[1] == 'D' && buf[2] == '3') &&
- ((unsigned short)buf[3] < 0xff && (unsigned short)buf[4] < 0xff)) {
- // do we have a footer?
- bool footer = (buf[5] & 0x10);
-
- // the size is saved as a synched int meaning bit 7 is always
cleared to 0
- unsigned int size =
- ( (buf[6] & 0x7f) << 21 ) |
- ( (buf[7] & 0x7f) << 14 ) |
- ( (buf[8] & 0x7f) << 7) |
- (buf[9] & 0x7f);
- unsigned int offset = size + 10;
-
- if (footer) {
- offset += 10;
- }
-
- // skip the id3 tag
- if (!m_inputFile.seek(offset)) {
- PERROR("Couldn't seek to %u in %s", offset,
m_inputFile.fileName().toUtf8().data());
- return false;
- }
- }
- else {
- // reset file
- return m_inputFile.seek(0);
- }
-
- return true;
-}
-
-
-bool K3bMad::seekFirstHeader()
-{
- //
- // A lot of mp3 files start with a lot of junk which confuses mad.
- // We "allow" an mp3 file to start with at most 1 KB of junk. This is
just
- // some random value since we do not want to search the hole file. That
would
- // take way to long for non-mp3 files.
- //
- bool headerFound = findNextHeader();
- qint64 inputPos = streamPos();
- while (!headerFound &&
- !m_inputFile.atEnd() &&
- streamPos() <= inputPos+1024) {
- headerFound = findNextHeader();
- }
-
- // seek back to the begin of the frame
- if (headerFound) {
- int streamSize = madStream->bufend - madStream->buffer;
- int bytesToFrame = madStream->this_frame - madStream->buffer;
- m_inputFile.seek(m_inputFile.pos() - streamSize + bytesToFrame);
-
- //kdDebug() << "(K3bMad) found first header at " <<
m_inputFile.pos() << endl;
- }
-
- // reset the stream to make sure mad really starts decoding at out seek
position
- mad_stream_finish(madStream);
- mad_stream_init(madStream);
-
- return headerFound;
-}
-
-
-bool K3bMad::eof() const
-{
- return m_inputFile.atEnd();
-}
-
-
-qint64 K3bMad::inputPos() const
-{
- return m_inputFile.pos();
-}
-
-
-qint64 K3bMad::streamPos() const
-{
- return inputPos() - (madStream->bufend - madStream->this_frame + 1);
-}
-
-
-bool K3bMad::inputSeek(qint64 pos)
-{
- return m_inputFile.seek(pos);
-}
-
-
-void K3bMad::initMad()
-{
- if (!m_madStructuresInitialized) {
- mad_stream_init(madStream);
- mad_timer_set(madTimer, 0, 0, 0);
- mad_frame_init(madFrame);
- mad_synth_init(madSynth);
-
- m_madStructuresInitialized = true;
- }
-}
-
-
-void K3bMad::cleanup()
-{
- if (m_inputFile.isOpen()) {
- //kdDebug() << "(K3bMad) cleanup at offset: "
- // << "Input file at: " << m_inputFile.pos() << " "
- // << "Input file size: " << m_inputFile.size() << "
"
- // << "stream pos: "
- // << ( m_inputFile.pos() - (madStream->bufend -
madStream->this_frame + 1) )
- // << endl;
- m_inputFile.close();
- }
-
- if (m_madStructuresInitialized) {
- mad_frame_finish(madFrame);
- mad_synth_finish(madSynth);
- mad_stream_finish(madStream);
- }
-
- m_madStructuresInitialized = false;
-}
-
-
-//
-// LOSTSYNC could happen when mad encounters the id3 tag...
-//
-bool K3bMad::findNextHeader()
-{
- if (!fillStreamBuffer()) {
- return false;
- }
-
- //
- // MAD_RECOVERABLE == true: frame was read, decoding failed (about to
skip frame)
- // MAD_RECOVERABLE == false: frame was not read, need data
- //
-
- if (mad_header_decode( &madFrame->header, madStream ) < 0) {
- if (MAD_RECOVERABLE(madStream->error) ||
- madStream->error == MAD_ERROR_BUFLEN) {
- return findNextHeader();
- }
- else
- // kdDebug() << "(K3bMad::findNextHeader) error: " <<
mad_stream_errorstr( madStream ) << endl;
-
- // FIXME probably we should not do this here since we don't do
it
- // in the frame decoding
- // if(!checkFrameHeader(&madFrame->header))
- // return findNextHeader();
-
- return false;
- }
-
- if (!m_channels) {
- m_channels = MAD_NCHANNELS(&madFrame->header);
- m_sampleRate = madFrame->header.samplerate;
- }
-
- mad_timer_add(madTimer, madFrame->header.duration);
-
- return true;
-}
-
-
-bool K3bMad::decodeNextFrame()
-{
- if (!fillStreamBuffer()) {
- return false;
- }
-
- if (mad_frame_decode(madFrame, madStream) < 0) {
- if (MAD_RECOVERABLE(madStream->error) ||
- madStream->error == MAD_ERROR_BUFLEN) {
- return decodeNextFrame();
- }
-
- return false;
- }
-
- if (!m_channels) {
- m_channels = MAD_NCHANNELS(&madFrame->header);
- m_sampleRate = madFrame->header.samplerate;
- }
-
- mad_timer_add(madTimer, madFrame->header.duration);
-
- return true;
-}
-
-
-//
-// This is from the arts mad decoder
-//
-bool K3bMad::checkFrameHeader(mad_header* header) const
-{
- int frameSize = MAD_NSBSAMPLES(header) * 32;
-
- if (frameSize <= 0) {
- return false;
- }
-
- if (m_channels && m_channels != MAD_NCHANNELS(header)) {
- return false;
- }
-
- return true;
-}
-
-
-
-class MadAudioReader::MadDecoderPrivate
-{
-public:
- MadDecoderPrivate()
- {
- outputBuffers = 0;
- outputPos = 0;
- outputSize = 0;
- overflowSize = 0;
- overflowStart = 0;
-
- mad_header_init( &firstHeader );
- }
-
- K3bMad* handle;
-
- QVector<unsigned long long> seekPositions;
-
- bool bOutputFinished;
-
- audio_sample_t** outputBuffers;
- nframes_t outputPos;
- nframes_t outputSize;
-
- QVector<audio_sample_t*> overflowBuffers;
- nframes_t overflowSize;
- nframes_t overflowStart;
-
- // the first frame header for technical info
- mad_header firstHeader;
- bool vbr;
-};
-
-
-MadAudioReader::MadAudioReader(QString filename)
- : AbstractAudioReader(filename)
-{
- d = new MadDecoderPrivate();
- d->handle = new K3bMad();
-
- initDecoderInternal();
-
- switch( d->firstHeader.mode ) {
- case MAD_MODE_SINGLE_CHANNEL:
- m_channels = 1;
- case MAD_MODE_DUAL_CHANNEL:
- case MAD_MODE_JOINT_STEREO:
- case MAD_MODE_STEREO:
- m_channels = 2;
- }
-
- m_length = countFrames();
-
- if (m_length <= 0) {
- d->handle->cleanup();
- delete d->handle;
- delete d;
- d = 0;
- return;
- }
-
- m_rate = d->firstHeader.samplerate;
-
- for (int c = 0; c < m_channels; c++) {
- d->overflowBuffers.append(new audio_sample_t[1152]);
- }
-
- seek_private(0);
-}
-
-
-MadAudioReader::~MadAudioReader()
-{
- if (d) {
- d->handle->cleanup();
- delete d->handle;
- while (d->overflowBuffers.size()) {
- delete d->overflowBuffers.back();
- d->overflowBuffers.pop_back();
- }
- delete d;
- }
-}
-
-
-bool MadAudioReader::can_decode(QString filename)
-{
- //
- // HACK:
- //
- // I am simply no good at this and this detection code is no good as
well
- // It always takes waves for mp3 files so we introduce this hack to
- // filter out wave files. :(
- //
- QFile f(filename);
- if (!f.open( QIODevice::ReadOnly)) {
- return false;
- }
-
- char buffer[12];
- if (f.read(buffer, 12) != 12) {
- return false;
- }
- if (!qstrncmp(buffer, "RIFF", 4) && !qstrncmp(buffer + 8, "WAVE", 4)) {
- return false;
- }
- f.close();
-
-
- K3bMad handle;
- if (!handle.open(filename)) {
- return false;
- }
- handle.skipTag();
- if (!handle.seekFirstHeader()) {
- return false;
- }
- if (handle.findNextHeader()) {
- int c = MAD_NCHANNELS(&handle.madFrame->header);
- int layer = handle.madFrame->header.layer;
- unsigned int s = handle.madFrame->header.samplerate;
-
- //
- // find 4 more mp3 headers (random value since 2 was not enough)
- // This way we get most of the mp3 files while sorting out
- // for example wave files.
- //
- int cnt = 1;
- while (handle.findNextHeader()) {
- // compare the found headers
- if (MAD_NCHANNELS(&handle.madFrame->header) == c &&
- handle.madFrame->header.layer == layer &&
- handle.madFrame->header.samplerate == s) {
- // only support layer III for now since
otherwise some wave files
- // are taken for layer I
- if (++cnt >= 5) {
- //stdout << "(MadDecoder) valid mpeg 1
layer " << layer
- //<< " file with " << c << " channels
and a samplerate of "
- //<< s << endl;
- return (layer == MAD_LAYER_III);
- }
- }
- else {
- break;
- }
- }
- }
-
- //PERROR("unsupported format: %s",QS_C(filename));
-
- return false;
-}
-
-
-bool MadAudioReader::seek_private(nframes_t start)
-{
- Q_ASSERT(d);
-
- if (start >= m_length) {
- return false;
- }
-
- //
- // we need to reset the complete mad stuff
- //
- if (!initDecoderInternal()) {
- return false;
- }
-
- //
- // search a position
- // This is all hacking, I don't really know what I am doing here... ;)
- //
- double mp3FrameSecs =
static_cast<double>(d->firstHeader.duration.seconds) +
static_cast<double>(d->firstHeader.duration.fraction) /
static_cast<double>(MAD_TIMER_RESOLUTION);
-
- double posSecs = static_cast<double>(start) / m_rate;
-
- // seekPosition to seek after frame i
- unsigned int frame = static_cast<unsigned int>(posSecs / mp3FrameSecs);
- nframes_t frameOffset = (nframes_t)(start - (frame * mp3FrameSecs *
m_rate + 0.5));
-
- // K3b source: Rob said: 29 frames is the theoretically max frame
reservoir limit
- // (whatever that means...) it seems that mad needs at most 29 frames
to get ready
- //
- // Ben says: It looks like Rob (the author of MAD) implies here:
- // http://www.mars.org/mailman/public/mad-dev/2001-August/000321.html
- // that 3 frames (1 + 2 extra) is enough... seems to work fine...
- unsigned int frameReservoirProtect = (frame > 3 ? 3 : frame);
-
- frame -= frameReservoirProtect;
-
- // seek in the input file behind the already decoded data
- d->handle->inputSeek( d->seekPositions[frame] );
-
- // decode some frames ignoring MAD_ERROR_BADDATAPTR errors
- unsigned int i = 1;
- while (i <= frameReservoirProtect) {
- d->handle->fillStreamBuffer();
- if (mad_frame_decode( d->handle->madFrame,
d->handle->madStream)) {
- if (MAD_RECOVERABLE( d->handle->madStream->error)) {
- if (d->handle->madStream->error ==
MAD_ERROR_BUFLEN) {
- continue;
- }
- else if (d->handle->madStream->error !=
MAD_ERROR_BADDATAPTR) {
- //kdDebug() << "(K3bMadDecoder)
Seeking: recoverable mad error ("
- //<<
mad_stream_errorstr(d->handle->madStream) << ")" << endl;
- continue;
- }
- else {
- //kdDebug() << "(K3bMadDecoder)
Seeking: ignoring ("
- //<<
mad_stream_errorstr(d->handle->madStream) << ")" << endl;
- }
- }
- else {
- return false;
- }
- }
-
- if (i == frameReservoirProtect) { // synth only the last frame
(Rob said so ;)
- mad_synth_frame( d->handle->madSynth,
d->handle->madFrame );
- }
-
- ++i;
- }
-
- d->overflowStart = 0;
- d->overflowSize = 0;
-
- // Seek to exact traverso frame, within this mp3 frame
- if (frameOffset > 0) {
- //printf("seekOffset: %lu (start: %lu)\n", frameOffset, start);
- d->outputBuffers = 0; // Zeros so that we write to overflow
- d->outputSize = 0;
- d->outputPos = 0;
- createPcmSamples(d->handle->madSynth);
- d->overflowStart = frameOffset;
- d->overflowSize -= frameOffset;
- }
-
- return true;
-}
-
-
-bool MadAudioReader::initDecoderInternal()
-{
- d->handle->cleanup();
-
- d->bOutputFinished = false;
-
- if (!d->handle->open(m_fileName)) {
- return false;
- }
-
- if (!d->handle->skipTag()) {
- return false;
- }
-
- if (!d->handle->seekFirstHeader()) {
- return false;
- }
-
- return true;
-}
-
-
-unsigned long MadAudioReader::countFrames()
- {
- //kdDebug() << "(K3bMadDecoder::countFrames)" << endl;
-
- unsigned long frames = 0;
- bool error = false;
- d->vbr = false;
- bool bFirstHeaderSaved = false;
-
- d->seekPositions.clear();
-
- while (!error && d->handle->findNextHeader()) {
- if (!bFirstHeaderSaved) {
- bFirstHeaderSaved = true;
- d->firstHeader = d->handle->madFrame->header;
- }
- else if (d->handle->madFrame->header.bitrate !=
d->firstHeader.bitrate) {
- d->vbr = true;
- }
- //
- // position in stream: position in file minus the not yet used
buffer
- //
- unsigned long long seekPos = d->handle->inputPos() -
- (d->handle->madStream->bufend -
d->handle->madStream->this_frame + 1);
-
- // save the number of bytes to be read to decode i-1 frames at
position i
- // in other words: when seeking to seekPos the next decoded
frame will be i
- d->seekPositions.append(seekPos);
- }
-
- if (!d->handle->inputError() && !error) {
- frames = d->firstHeader.samplerate *
(d->handle->madTimer->seconds + (unsigned long)(
-
(float)d->handle->madTimer->fraction/(float)MAD_TIMER_RESOLUTION));
- //kdDebug() << "(K3bMadDecoder) length of track " << seconds <<
endl;
- }
-
- d->handle->cleanup();
-
- //kdDebug() << "(K3bMadDecoder::countFrames) end" << endl;
-
- return frames;
-}
-
-
-nframes_t MadAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
-{
- d->outputBuffers = buffer;
- d->outputSize = frameCount;
- d->outputPos = 0;
-
- bool bOutputBufferFull = false;
-
- // Deal with existing overflow
- if (d->overflowSize > 0) {
- if (d->overflowSize < frameCount) {
- //printf("output all %d overflow samples\n",
d->overflowSize);
- for (int c = 0; c < m_channels; c++) {
- memcpy(d->outputBuffers[c],
d->overflowBuffers[c] + d->overflowStart, d->overflowSize *
sizeof(audio_sample_t));
- }
- d->outputPos += d->overflowSize;
- d->overflowSize = 0;
- d->overflowStart = 0;
- }
- else {
- //printf("output %d overflow frames, returned from
overflow\n", frameCount);
- for (int c = 0; c < m_channels; c++) {
- memcpy(d->outputBuffers[c],
d->overflowBuffers[c] + d->overflowStart, frameCount * sizeof(audio_sample_t));
- }
- d->overflowSize -= frameCount;
- d->overflowStart += frameCount;
- return frameCount;
- }
- }
-
- while (!bOutputBufferFull && d->handle->fillStreamBuffer()) {
- // a mad_synth contains of the data of one mad_frame
- // one mad_frame represents a mp3-frame which is always 1152
samples
- // for us that means we need 1152 samples per channel of output
buffer
- // for every frame
- if (d->outputPos >= d->outputSize) {
- bOutputBufferFull = true;
- }
- else if (d->handle->decodeNextFrame()) {
- //
- // Once decoded the frame is synthesized to PCM
samples. No errors
- // are reported by mad_synth_frame();
- //
- mad_synth_frame( d->handle->madSynth,
d->handle->madFrame );
-
- // this fills the output buffer
- if (!createPcmSamples(d->handle->madSynth)) {
- PERROR("createPcmSamples");
- return 0;
- }
- }
- else if (d->handle->inputError()) {
- PERROR("inputError");
- return 0;
- }
- }
-
- nframes_t framesWritten = d->outputPos;
-
- // Pad end with zeros if necessary
- // FIXME: This shouldn't be necessary! :P
- // is m_length reporting incorrectly?
- // are we not outputting the last mp3-frame for some reason?
- /*int remainingFramesRequested = frameCount - framesWritten;
- int remainingFramesInFile = m_length - (m_readPos + framesWritten);
- if (remainingFramesRequested > 0 && remainingFramesInFile > 0) {
- int padLength = (remainingFramesRequested >
remainingFramesInFile) ? remainingFramesInFile : remainingFramesRequested;
- for (int c = 0; c < m_channels; c++) {
- //memset(d->outputBuffers[c] + framesWritten, 0,
padLength * sizeof(audio_sample_t));
- }
- framesWritten += padLength;
- printf("padding: %d\n", padLength);
- }
-
- // Truncate so we don't return too many frames
- if (framesWritten + m_readPos > m_length) {
- printf("truncating by %d!\n", m_length - (framesWritten +
m_readPos));
- framesWritten = m_length - m_readPos;
- }*/
-
- //printf("request: %d (returned: %d), now at: %lu (total: %lu)\n",
frameCount, framesWritten, m_readPos + framesWritten, m_length);
-
- return framesWritten;
-}
-
-
-bool MadAudioReader::createPcmSamples(mad_synth* synth)
-{
- audio_sample_t **writeBuffers = d->outputBuffers;
- int offset = d->outputPos;
- nframes_t nframes = synth->pcm.length;
- bool overflow = false;
- int i;
-
- if (writeBuffers && (m_readPos + d->outputPos + nframes) > m_length) {
- nframes = m_length - (m_readPos + offset);
- //printf("!!!nframes: %lu, length: %lu, current: %lu\n",
nframes, m_length, d->outputPos + m_readPos);
- }
-
- // now create the output
- for (i = 0; i < nframes; i++) {
- if (overflow == false && d->outputPos + i >= d->outputSize) {
- writeBuffers = d->overflowBuffers.data();
- offset = 0 - i;
- overflow = true;
- }
-
- /* Left channel */
- writeBuffers[0][offset + i] =
mad_f_todouble(synth->pcm.samples[0][i]);
-
- /* Right channel. If the decoded stream is monophonic then no
right channel
- */
- if (synth->pcm.channels == 2) {
- writeBuffers[1][offset + i] =
mad_f_todouble(synth->pcm.samples[1][i]);
- }
- } // pcm conversion
-
- if (overflow) {
- d->overflowSize = i + offset;
- d->overflowStart = 0;
- d->outputPos -= offset; // i was stored here when we switched
to writing to overflow
- //printf("written: %d (overflow: %u)\n", nframes -
d->overflowSize, d->overflowSize);
- }
- else {
- d->outputPos += i;
- //printf("written: %d (os=%lu)\n", i, d->overflowSize);
- }
-
- return true;
-}
-
-
Index: src/core/MadAudioReader.h
===================================================================
RCS file: src/core/MadAudioReader.h
diff -N src/core/MadAudioReader.h
--- src/core/MadAudioReader.h 24 Jul 2007 17:57:05 -0000 1.6
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,54 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#ifndef MADAUDIOREADER_H
-#define MADAUDIOREADER_H
-
-#include <AbstractAudioReader.h>
-
-extern "C" {
-#include <mad.h>
-}
-
-
-class MadAudioReader : public AbstractAudioReader
-{
-public:
- MadAudioReader(QString filename);
- ~MadAudioReader();
-
- static bool can_decode(QString filename);
-
-protected:
- bool seek_private(nframes_t start);
- nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
-
- bool initDecoderInternal();
- unsigned long countFrames();
- bool createPcmSamples(mad_synth* synth);
-
- static int MaxAllowedRecoverableErrors;
-
- class MadDecoderPrivate;
- MadDecoderPrivate* d;
-};
-
-#endif
Index: src/core/ResampleAudioReader.cpp
===================================================================
RCS file: src/core/ResampleAudioReader.cpp
diff -N src/core/ResampleAudioReader.cpp
--- src/core/ResampleAudioReader.cpp 25 Jul 2007 17:06:16 -0000 1.15
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,258 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#include "ResampleAudioReader.h"
-#include <QString>
-
-#define OVERFLOW_SIZE 1024
-
-// Always put me below _all_ includes, this is needed
-// in case we run with memory leak detection enabled!
-#include "Debugger.h"
-
-
-// On init, creates a child AudioReader for any filetype, and a samplerate
converter
-ResampleAudioReader::ResampleAudioReader(QString filename, int converter_type)
- : AbstractAudioReader(filename)
-{
- m_reader = AbstractAudioReader::create_audio_reader(filename);
- if (!m_reader) {
- PERROR("ResampleAudioReader: couldn't create AudioReader");
- return;
- }
-
- m_channels = m_reader->get_num_channels();
- m_rate = m_reader->get_file_rate();
- m_length = m_reader->get_length();
- m_outputRate = m_rate;
-
- m_fileBuffers.resize(get_num_channels());
- m_filePointers.resize(get_num_channels());
- m_fileBufferLength = 0;
-
- init(converter_type);
-}
-
-
-ResampleAudioReader::~ResampleAudioReader()
-{
- while (m_srcStates.size()) {
- src_delete(m_srcStates.back());
- m_srcStates.pop_back();
- }
-
- if (m_reader) {
- delete m_reader;
- }
-
- while (m_fileBuffers.size()) {
- delete m_fileBuffers.back();
- m_fileBuffers.pop_back();
- }
-}
-
-
-void ResampleAudioReader::init(int converter_type)
-{
- int error;
-
- for (int c = 0; c < m_reader->get_num_channels(); c++) {
- m_srcStates.append(src_new(converter_type, 1, &error));
- if (!m_srcStates[c]) {
- PERROR("ResampleAudioReader: couldn't create
libSampleRate SRC_STATE");
- delete m_reader;
- m_reader = 0;
- return;
- }
- m_srcStates.append(src_new(converter_type, 1, &error));
- if (!m_srcStates[c]) {
- PERROR("ResampleAudioReader: couldn't create
libSampleRate SRC_STATE");
- delete m_reader;
- m_reader = 0;
- return;
- }
- }
-
- reset();
- seek_private(0);
-}
-
-
-// Clear the samplerateconverter to a clean state (used on seek)
-void ResampleAudioReader::reset()
-{
- for (int c = 0; c < m_reader->get_num_channels(); c++) {
- src_reset(m_srcStates[c]);
- }
-
- m_srcData.end_of_input = 0;
- m_overflowUsed = 0;
-}
-
-
-int ResampleAudioReader::get_output_rate()
-{
- return m_outputRate;
-}
-
-
-void ResampleAudioReader::set_output_rate(int rate)
-{
- if (!m_reader) {
- return;
- }
- m_outputRate = rate;
- m_length = file_to_song_frame(m_reader->get_length());
-}
-
-
-// if no conversion is necessary, pass the seek straight to the child
AudioReader,
-// otherwise convert and seek
-bool ResampleAudioReader::seek_private(nframes_t start)
-{
- Q_ASSERT(m_reader);
-
- if (m_outputRate == m_rate) {
- return m_reader->seek(start);
- }
-
- reset();
-
- return m_reader->seek(song_to_file_frame(start));
-}
-
-
-// If no conversion is necessary, pass the read straight to the child
AudioReader,
-// otherwise get data from childreader and use libsamplerate to convert
-nframes_t ResampleAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
-{
- Q_ASSERT(m_reader);
-
- // pass through if not changing sampleRate.
- if (m_outputRate == m_rate) {
- return m_reader->read(buffer, frameCount);
- }
-
- nframes_t bufferUsed;
- nframes_t framesRead;
-
- nframes_t fileCnt = song_to_file_frame(frameCount);
-
- if (frameCount && !fileCnt) {
- fileCnt = 1;
- }
-
- bufferUsed = m_overflowUsed;
-
- if (!m_reader->eof()) {
- // make sure that the reusable m_fileBuffers are big enough for
this read + OVERFLOW_SIZE
- if ((uint)m_fileBufferLength < fileCnt + OVERFLOW_SIZE) {
- for (int c = 0; c < m_channels; c++) {
- if (m_fileBufferLength) {
- delete m_fileBuffers[c];
- }
- m_fileBuffers[c] = new audio_sample_t[fileCnt +
OVERFLOW_SIZE];
- }
- m_fileBufferLength = fileCnt + OVERFLOW_SIZE;
- }
-
- for (int c = 0; c < m_channels; c++) {
- m_filePointers[c] = m_fileBuffers[c] + m_overflowUsed;
- }
-
- bufferUsed += m_reader->read(m_filePointers.data(), fileCnt +
OVERFLOW_SIZE - m_overflowUsed);
- //printf("Resampler: Read %lu of %lu (%lu)\n", bufferUsed,
fileCnt + OVERFLOW_SIZE - m_overflowUsed, m_reader->get_length());
- }
-
- if (m_reader->eof()) {
- m_srcData.end_of_input = 1;
- }
-
- nframes_t framesToConvert = frameCount;
- if (frameCount > m_length - m_readPos) {
- framesToConvert = m_length - m_readPos;
- }
-
- for (int c = 0; c < m_channels; c++) {
- // Set up sample rate converter struct for s.r.c. processing
- m_srcData.data_in = m_fileBuffers[c];
- m_srcData.input_frames = bufferUsed;
- m_srcData.data_out = buffer[c];
- m_srcData.output_frames = framesToConvert;
- m_srcData.src_ratio = (double) m_outputRate / m_rate;
- src_set_ratio(m_srcStates[c], m_srcData.src_ratio);
-
- if (src_process(m_srcStates[c], &m_srcData)) {
- PERROR("Resampler: src_process() error!");
- return 0;
- }
- framesRead = m_srcData.output_frames_gen;
- }
-
- m_overflowUsed = bufferUsed - m_srcData.input_frames_used;
-
- if (m_overflowUsed < 0) {
- m_overflowUsed = 0;
- }
-
- if (m_srcData.input_frames_used < bufferUsed) {
- for (int c = 0; c < m_channels; c++) {
- memmove(m_fileBuffers[c], m_fileBuffers[c] +
m_srcData.input_frames_used, m_overflowUsed * sizeof(audio_sample_t));
- }
- }
-
- // Pad end of file with 0s if necessary
- if (framesRead == 0 && m_readPos < get_length()) {
- int padLength = m_readPos;
- for (int c = 0; c < m_channels; c++) {
- memset(buffer[c] + framesRead, 0, padLength *
sizeof(audio_sample_t));
- }
- framesRead += padLength;
- printf("Resampler: padding: %d\n", padLength);
- }
-
- // Truncate so we don't return too many samples
- /*if (m_readPos + framesRead > get_length()) {
- printf("Resampler: truncating: %d\n", framesRead -
(get_length() - m_readPos));
- framesRead = get_length() - m_readPos;
- }*/
-
- //printf("framesRead: %lu of %lu (overflow: %lu) (at: %lu of %lu)\n",
framesRead, frameCount, m_overflowUsed, m_readPos + framesRead, get_length());
-
- return framesRead;
-}
-
-
-nframes_t ResampleAudioReader::song_to_file_frame(nframes_t frame)
-{
- Q_ASSERT(m_reader);
-
- return (nframes_t)(frame * ((double) m_rate / m_outputRate));
-}
-
-
-nframes_t ResampleAudioReader::file_to_song_frame(nframes_t frame)
-{
- Q_ASSERT(m_reader);
-
- return (nframes_t)(frame * ((double) m_outputRate / m_rate));
-}
-
Index: src/core/ResampleAudioReader.h
===================================================================
RCS file: src/core/ResampleAudioReader.h
diff -N src/core/ResampleAudioReader.h
--- src/core/ResampleAudioReader.h 24 Jul 2007 17:57:06 -0000 1.11
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,61 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#ifndef RESAMPLEAUDIOREADER_H
-#define RESAMPLEAUDIOREADER_H
-
-#include <AbstractAudioReader.h>
-#include <QVector>
-#include <samplerate.h>
-
-
-class ResampleAudioReader : public AbstractAudioReader
-{
-
-public:
- ResampleAudioReader(QString filename, int converter_type);
- ~ResampleAudioReader();
-
- int get_output_rate();
- void set_output_rate(int rate);
-
-protected:
- void init(int converter_type);
- void reset();
-
- bool seek_private(nframes_t start);
- nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
-
- nframes_t song_to_file_frame(nframes_t frame);
- nframes_t file_to_song_frame(nframes_t frame);
-
- bool m_valid;
- AbstractAudioReader* m_reader;
- QVector<SRC_STATE*> m_srcStates;
- SRC_DATA m_srcData;
- QVector<audio_sample_t*> m_fileBuffers;
- QVector<audio_sample_t*> m_filePointers;
- long m_fileBufferLength;
- long m_overflowUsed;
- int m_outputRate;
-};
-
-#endif
Index: src/core/SFAudioReader.cpp
===================================================================
RCS file: src/core/SFAudioReader.cpp
diff -N src/core/SFAudioReader.cpp
--- src/core/SFAudioReader.cpp 25 Jul 2007 17:06:16 -0000 1.9
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,144 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#include "SFAudioReader.h"
-#include <QFile>
-#include <QString>
-
-// Always put me below _all_ includes, this is needed
-// in case we run with memory leak detection enabled!
-#include "Debugger.h"
-
-
-SFAudioReader::SFAudioReader(QString filename)
- : AbstractAudioReader(filename)
-{
- /* although libsndfile says we don't need to set this,
- valgrind and source code shows us that we do.
- Really? Look it up !
- */
- memset (&m_sfinfo, 0, sizeof(m_sfinfo));
-
- if ((m_sf = sf_open (m_fileName.toUtf8().data(), SFM_READ, &m_sfinfo))
== 0) {
- PERROR("Couldn't open soundfile (%s)",
m_fileName.toUtf8().data());
- }
-
- m_channels = m_sfinfo.channels;
- m_length = m_sfinfo.frames;
- m_rate = m_sfinfo.samplerate;
-
- m_tmpBuffer = 0;
- m_tmpBufferSize = 0;
-}
-
-
-SFAudioReader::~SFAudioReader()
-{
- if (m_tmpBuffer) {
- delete m_tmpBuffer;
- }
-
- if (m_sf) {
- if (sf_close(m_sf)) {
- qWarning("sf_close returned an error!");
- }
- }
-}
-
-
-bool SFAudioReader::can_decode(QString filename)
-{
- SF_INFO infos;
-
- /* although libsndfile says we don't need to set this,
- valgrind and source code shows us that we do.
- Really? Look it up !
- */
- memset (&infos, 0, sizeof(infos));
-
- SNDFILE* sndfile = sf_open(QFile::encodeName(filename), SFM_READ,
&infos);
-
- //is it supported by libsndfile?
- if (!sndfile) {
- return false;
- }
-
- sf_close(sndfile);
-
- return true;
-}
-
-
-bool SFAudioReader::seek_private(nframes_t start)
-{
- Q_ASSERT(m_sf);
-
-
- if (start >= m_length) {
- return false;
- }
-
- if (sf_seek (m_sf, (off_t) start, SEEK_SET) < 0) {
- char errbuf[256];
- sf_error_str (0, errbuf, sizeof (errbuf) - 1);
- PERROR("ReadAudioSource: could not seek to frame %d within %s
(%s)", start, m_fileName.toUtf8().data(), errbuf);
- return false;
- }
-
- return true;
-}
-
-
-nframes_t SFAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
-{
- Q_ASSERT(m_sf);
-
- // Make sure the temp buffer is big enough for this read
- if (m_tmpBufferSize < frameCount) {
- if (m_tmpBuffer) {
- delete m_tmpBuffer;
- }
- m_tmpBuffer = new audio_sample_t[frameCount * m_channels];
- }
- nframes_t framesRead = sf_readf_float(m_sf, m_tmpBuffer, frameCount);
-
- // De-interlace
- switch (m_channels) {
- case 1:
- memcpy(buffer[0], m_tmpBuffer, framesRead *
sizeof(audio_sample_t));
- break;
- case 2:
- for (int f = 0; f < framesRead; f++) {
- buffer[0][f] = m_tmpBuffer[f * 2];
- buffer[1][f] = m_tmpBuffer[f * 2 + 1];
- }
- break;
- default:
- for (int f = 0; f < framesRead; f++) {
- for (int c = 0; c < m_channels; c++) {
- buffer[c][f] = m_tmpBuffer[f *
m_channels + c];
- }
- }
- }
-
- return framesRead;
-}
-
Index: src/core/SFAudioReader.h
===================================================================
RCS file: src/core/SFAudioReader.h
diff -N src/core/SFAudioReader.h
--- src/core/SFAudioReader.h 24 Jul 2007 17:57:06 -0000 1.6
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,47 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#ifndef SFAUDIOREADER_H
-#define SFAUDIOREADER_H
-
-#include <AbstractAudioReader.h>
-#include "sndfile.h"
-
-
-class SFAudioReader : public AbstractAudioReader
-{
-public:
- SFAudioReader(QString filename);
- ~SFAudioReader();
-
- static bool can_decode(QString filename);
-
-protected:
- bool seek_private(nframes_t start);
- nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
-
- SNDFILE* m_sf;
- SF_INFO m_sfinfo;
- audio_sample_t *m_tmpBuffer;
- int m_tmpBufferSize;
-};
-
-#endif
Index: src/core/VorbisAudioReader.cpp
===================================================================
RCS file: src/core/VorbisAudioReader.cpp
diff -N src/core/VorbisAudioReader.cpp
--- src/core/VorbisAudioReader.cpp 30 Jul 2007 22:57:37 -0000 1.12
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,139 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#include "VorbisAudioReader.h"
-#include <QFile>
-#include <QString>
-
-#ifdef _WIN32
-#include <io.h>
-#include <fcntl.h>
-#endif
-
-// Always put me below _all_ includes, this is needed
-// in case we run with memory leak detection enabled!
-#include "Debugger.h"
-
-
-VorbisAudioReader::VorbisAudioReader(QString filename)
- : AbstractAudioReader(filename)
-{
- m_file = fopen(filename.toUtf8().data(), "rb");
- if (!m_file) {
- PERROR("Couldn't open file %s.", filename.toUtf8().data());
- return;
- }
-
- if (ov_open(m_file, &m_vf, 0, 0) < 0) {
- PERROR("Input does not appear to be an Ogg bitstream.");
- fclose(m_file);
- return;
- }
-
- ov_pcm_seek(&m_vf, 0);
- m_vi = ov_info(&m_vf,-1);
-
- m_channels = m_vi->channels;
- m_length = ov_pcm_total(&m_vf, -1);
- m_rate = m_vi->rate;
-}
-
-
-VorbisAudioReader::~VorbisAudioReader()
-{
- if (m_file) {
- ov_clear(&m_vf);
- }
-}
-
-
-bool VorbisAudioReader::can_decode(QString filename)
-{
- FILE* file = fopen(filename.toUtf8().data(), "rb");
- if (!file) {
- PERROR("Could not open file: %s.", filename.toUtf8().data());
- return false;
- }
-
- OggVorbis_File of;
-
- if (ov_test(file, &of, 0, 0)) {
- fclose(file);
- return false;
- }
-
- ov_clear(&of);
-
- return true;
-}
-
-
-bool VorbisAudioReader::seek_private(nframes_t start)
-{
- Q_ASSERT(m_file);
-
- if (start >= m_length) {
- return false;
- }
-
- if (int result = ov_pcm_seek(&m_vf, start) < 0) {
- PERROR("VorbisAudioReader: could not seek to frame %d within %s
(%d)", start, m_fileName.toUtf8().data(), result);
- return false;
- }
-
- return true;
-}
-
-
-nframes_t VorbisAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
-{
- Q_ASSERT(m_file);
-
- nframes_t totalFramesRead = 0;
-
- while (totalFramesRead < frameCount) {
- audio_sample_t** tmp;
- int bs;
- int framesRead = ov_read_float(&m_vf, &tmp, frameCount -
totalFramesRead, &bs);
-
- if (framesRead == OV_HOLE) {
- // Hole detected: recursive retry
- PERROR("VorbisAudioReader: OV_HOLE");
- return read(buffer, frameCount);
- }
- else if (framesRead == 0) {
- /* EOF */
- break;
- } else if (framesRead < 0) {
- /* error in the stream. */
- PERROR("VorbisFile decoding error");
- break;
- }
-
- for (int c=0; c < m_channels; c++) {
- memcpy(buffer[c] + totalFramesRead, tmp[c], framesRead
* sizeof(audio_sample_t));
- }
- totalFramesRead += framesRead;
- }
-
- return totalFramesRead;
-}
-
Index: src/core/VorbisAudioReader.h
===================================================================
RCS file: src/core/VorbisAudioReader.h
diff -N src/core/VorbisAudioReader.h
--- src/core/VorbisAudioReader.h 24 Jul 2007 17:57:06 -0000 1.7
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,48 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#ifndef VORBISAUDIOREADER_H
-#define VORBISAUDIOREADER_H
-
-#include "AbstractAudioReader.h"
-#include "vorbis/codec.h"
-#include "vorbis/vorbisfile.h"
-#include "stdio.h"
-
-
-class VorbisAudioReader : public AbstractAudioReader
-{
-public:
- VorbisAudioReader(QString filename);
- ~VorbisAudioReader();
-
- static bool can_decode(QString filename);
-
-protected:
- bool seek_private(nframes_t start);
- nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
-
- FILE* m_file;
- OggVorbis_File m_vf;
- vorbis_info* m_vi;
-};
-
-#endif
Index: src/core/WPAudioReader.cpp
===================================================================
RCS file: src/core/WPAudioReader.cpp
diff -N src/core/WPAudioReader.cpp
--- src/core/WPAudioReader.cpp 25 Jul 2007 17:06:16 -0000 1.6
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,155 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#include "WPAudioReader.h"
-#include <QString>
-
-// Always put me below _all_ includes, this is needed
-// in case we run with memory leak detection enabled!
-#include "Debugger.h"
-
-
-WPAudioReader::WPAudioReader(QString filename)
- : AbstractAudioReader(filename)
-{
- char error[80];
-
- m_wp = WavpackOpenFileInput(m_fileName.toUtf8().data(), error,
OPEN_2CH_MAX, 1);
-
- if (m_wp == 0) {
- PERROR("Couldn't open soundfile (%s) %s",
filename.toUtf8().data(), error);
- }
-
- m_isFloat = ((WavpackGetMode(m_wp) & MODE_FLOAT) != 0);
- m_bitsPerSample = WavpackGetBitsPerSample(m_wp);
- m_channels = WavpackGetReducedChannels(m_wp);
- m_length = WavpackGetNumSamples(m_wp);
- m_rate = WavpackGetSampleRate(m_wp);
-
- m_tmpBuffer = 0;
- m_tmpBufferSize = 0;
-}
-
-
-WPAudioReader::~WPAudioReader()
-{
- if (m_tmpBuffer) {
- delete m_tmpBuffer;
- }
-
- if (m_wp) {
- WavpackCloseFile(m_wp);
- }
-}
-
-
-bool WPAudioReader::can_decode(QString filename)
-{
- char error[80];
-
- WavpackContext *wp = WavpackOpenFileInput(filename.toUtf8().data(),
error, OPEN_2CH_MAX, 1);
-
- if (wp == 0) {
- return false;
- }
-
- WavpackCloseFile(wp);
-
- return true;
-}
-
-
-bool WPAudioReader::seek_private(nframes_t start)
-{
- Q_ASSERT(m_wp);
-
-
- if (start >= m_length) {
- return false;
- }
-
- if (!WavpackSeekSample(m_wp, start)) {
- PERROR("could not seek to frame %d within %s", start,
m_fileName.toUtf8().data());
- return false;
- }
-
- return true;
-}
-
-
-nframes_t WPAudioReader::read_private(audio_sample_t** buffer, nframes_t
frameCount)
-{
- Q_ASSERT(m_wp);
-
- // Make sure the temp buffer is big enough for this read
- if (m_tmpBufferSize < frameCount) {
- if (m_tmpBuffer) {
- delete m_tmpBuffer;
- }
- m_tmpBuffer = new int32_t[frameCount * m_channels];
- }
- nframes_t framesRead = WavpackUnpackSamples(m_wp, m_tmpBuffer,
frameCount);
-
- // De-interlace
- if (m_isFloat) {
- switch (m_channels) {
- case 1:
- memcpy(buffer[0], m_tmpBuffer, framesRead *
sizeof(audio_sample_t));
- break;
- case 2:
- for (int f = 0; f < framesRead; f++) {
- buffer[0][f] = ((float*)m_tmpBuffer)[f
* 2];
- buffer[1][f] = ((float*)m_tmpBuffer)[f
* 2 + 1];
- }
- break;
- default:
- for (int f = 0; f < framesRead; f++) {
- for (int c = 0; c < m_channels; c++) {
- buffer[c][f] =
((float*)m_tmpBuffer)[f * m_channels + c];
- }
- }
- }
- }
- else {
- switch (m_channels) {
- case 1:
- for (int f = 0; f < framesRead; f++) {
- buffer[0][f] =
(float)((float)m_tmpBuffer[f]/ (float)((uint)1<<(m_bitsPerSample-1)));
- }
- break;
- case 2:
- for (int f = 0; f < framesRead; f++) {
- buffer[0][f] =
(float)((float)m_tmpBuffer[f * 2]/ (float)((uint)1<<(m_bitsPerSample-1)));
- buffer[1][f] =
(float)((float)m_tmpBuffer[f * 2 + 1]/ (float)((uint)1<<(m_bitsPerSample-1)));
- }
- break;
- default:
- for (int f = 0; f < framesRead; f++) {
- for (int c = 0; c < m_channels; c++) {
- buffer[c][f] =
(float)((float)m_tmpBuffer[f + m_channels + c]/
(float)((uint)1<<(m_bitsPerSample-1)));
- }
- }
- }
- }
-
- return framesRead;
-}
-
Index: src/core/WPAudioReader.h
===================================================================
RCS file: src/core/WPAudioReader.h
diff -N src/core/WPAudioReader.h
--- src/core/WPAudioReader.h 24 Jul 2007 17:57:06 -0000 1.4
+++ /dev/null 1 Jan 1970 00:00:00 -0000
@@ -1,48 +0,0 @@
-/*
-Copyright (C) 2007 Ben Levitt
-
-This file is part of Traverso
-
-Traverso 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-
-*/
-
-#ifndef WPAUDIOREADER_H
-#define WPAUDIOREADER_H
-
-#include <AbstractAudioReader.h>
-#include "wavpack/wavpack.h"
-
-
-class WPAudioReader : public AbstractAudioReader
-{
-public:
- WPAudioReader(QString filename);
- ~WPAudioReader();
-
- static bool can_decode(QString filename);
-
-protected:
- bool seek_private(nframes_t start);
- nframes_t read_private(audio_sample_t** buffer, nframes_t frameCount);
-
- WavpackContext* m_wp;
- bool m_isFloat;
- int m_bitsPerSample;
- int32_t *m_tmpBuffer;
- int m_tmpBufferSize;
-};
-
-#endif
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Traverso-commit] traverso traverso.pro src/core/core.pro src/tra...,
Ben Levitt <=