traverso-commit
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]