traverso-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr...


From: Ben Levitt
Subject: [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr...
Date: Fri, 13 Jul 2007 07:41:03 +0000

CVSROOT:        /sources/traverso
Module name:    traverso
Changes by:     Ben Levitt <benjie>     07/07/13 07:41:03

Modified files:
        src/core       : AbstractAudioReader.cpp AbstractAudioReader.h 
                         AudioClip.cpp MadAudioReader.cpp 
                         MadAudioReader.h MonoReader.cpp MonoReader.h 
                         Peak.cpp ResampleAudioReader.cpp 
                         ResampleAudioReader.h VorbisAudioReader.cpp 
                         VorbisAudioReader.h core.pro 
Added files:
        src/core       : FlacAudioReader.cpp FlacAudioReader.h 

Log message:
        - Add FlacAudioReader as a present for Remon
        - Robustness fixes to Peak, AudioClip (be more forgiving of short 
reads, errors from 
        ReadSource)
        - Remove is_compressed() from AudioReader classes, MonoReader
        - Lots of little fixes to Mad, Vorbis
        - Fixes to ResampeAudioReader

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/AbstractAudioReader.cpp?cvsroot=traverso&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/AbstractAudioReader.h?cvsroot=traverso&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/AudioClip.cpp?cvsroot=traverso&r1=1.111&r2=1.112
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/MadAudioReader.cpp?cvsroot=traverso&r1=1.2&r2=1.3
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/MadAudioReader.h?cvsroot=traverso&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/MonoReader.cpp?cvsroot=traverso&r1=1.19&r2=1.20
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/MonoReader.h?cvsroot=traverso&r1=1.5&r2=1.6
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/Peak.cpp?cvsroot=traverso&r1=1.33&r2=1.34
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/ResampleAudioReader.cpp?cvsroot=traverso&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/ResampleAudioReader.h?cvsroot=traverso&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/VorbisAudioReader.cpp?cvsroot=traverso&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/VorbisAudioReader.h?cvsroot=traverso&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/core.pro?cvsroot=traverso&r1=1.31&r2=1.32
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/FlacAudioReader.cpp?cvsroot=traverso&rev=1.1
http://cvs.savannah.gnu.org/viewcvs/traverso/src/core/FlacAudioReader.h?cvsroot=traverso&rev=1.1

Patches:
Index: AbstractAudioReader.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/core/AbstractAudioReader.cpp,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- AbstractAudioReader.cpp     9 Jul 2007 20:38:53 -0000       1.4
+++ AbstractAudioReader.cpp     13 Jul 2007 07:41:02 -0000      1.5
@@ -21,6 +21,7 @@
 
 #include "AbstractAudioReader.h"
 #include "SFAudioReader.h"
+#include "FlacAudioReader.h"
 #include "MadAudioReader.h"
 #include "VorbisAudioReader.h"
 #include "ResampleAudioReader.h"
@@ -75,6 +76,9 @@
        else if (MadAudioReader::can_decode(filename)) {
                newReader = new MadAudioReader(filename);
        }
+       else if (FlacAudioReader::can_decode(filename)) {
+               newReader = new FlacAudioReader(filename);
+       }
        else if (SFAudioReader::can_decode(filename)) {
                newReader = new SFAudioReader(filename);
        }

Index: AbstractAudioReader.h
===================================================================
RCS file: /sources/traverso/traverso/src/core/AbstractAudioReader.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- AbstractAudioReader.h       9 Jul 2007 20:24:21 -0000       1.4
+++ AbstractAudioReader.h       13 Jul 2007 07:41:02 -0000      1.5
@@ -39,7 +39,6 @@
        virtual int get_num_channels() = 0;
        virtual nframes_t get_length() = 0;
        virtual int get_rate() = 0;
-       virtual bool is_compressed() = 0;
        int read_from(audio_sample_t* dst, nframes_t start, nframes_t cnt);
        virtual bool seek(nframes_t start) = 0;
        virtual int read(audio_sample_t* dst, int sampleCount) = 0;

Index: AudioClip.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/core/AudioClip.cpp,v
retrieving revision 1.111
retrieving revision 1.112
diff -u -b -r1.111 -r1.112
--- AudioClip.cpp       28 Jun 2007 15:03:55 -0000      1.111
+++ AudioClip.cpp       13 Jul 2007 07:41:02 -0000      1.112
@@ -436,7 +436,7 @@
                read_frames = m_readSource->file_read(channel, mixdown, 
mix_pos, nframes, m_song->readbuffer);
        }
 
-       if (read_frames == 0) {
+       if (read_frames <= 0) {
                return 0;
        }
 

Index: MadAudioReader.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/core/MadAudioReader.cpp,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -b -r1.2 -r1.3
--- MadAudioReader.cpp  9 Jul 2007 03:38:03 -0000       1.2
+++ MadAudioReader.cpp  13 Jul 2007 07:41:02 -0000      1.3
@@ -1,8 +1,9 @@
 /*
 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
-(Most of this Mp3 Reading code borrowed from K3b...)
 
 Traverso is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
@@ -324,7 +325,7 @@
 {
        if (!m_madStructuresInitialized) {
                mad_stream_init(madStream);
-               mad_timer_reset(madTimer);
+               mad_timer_set(madTimer, 0, 0, 0);
                mad_frame_init(madFrame);
                mad_synth_init(madSynth);
                
@@ -582,7 +583,7 @@
                }
        }
        
-       PERROR("unsupported format: %s",QS_C(filename));
+       //PERROR("unsupported format: %s",QS_C(filename));
        
        return false;
 }
@@ -615,13 +616,6 @@
 }
 
 
-// Should this exist?  Should we just be smarter in MonoReader so we don't 
need this?
-bool MadAudioReader::is_compressed()
-{
-       return false;
-}
-
-
 bool MadAudioReader::seek(nframes_t start)
 {
        Q_ASSERT(d);
@@ -837,18 +831,18 @@
        int remainingSamplesInFile = get_length() * get_num_channels() - 
(m_nextFrame * get_num_channels() + samplesWritten);
        if (remainingSamplesRequested > 0 && remainingSamplesInFile > 0) {
                int padLength = (remainingSamplesRequested > 
remainingSamplesInFile) ? remainingSamplesInFile : remainingSamplesRequested;
-               memset(d->outputPointer, 0, padLength);
+               memset(d->outputPointer, 0, padLength * sizeof(audio_sample_t));
                samplesWritten += padLength;
                //printf("remainingSamplesRequested: %d, 
remainingSamplesInFile: %d (using: %d)\n", remainingSamplesRequested, 
remainingSamplesInFile, padLength);
        }       
        
-       //if (samplesWritten) printf("at: %lu (total: %lu), request: %d 
(returned: %d)\n", m_nextFrame, m_frames, sampleCount/get_num_channels(), 
samplesWritten/get_num_channels());
-       
        // Truncate so we don't return too many samples
-       if (samplesWritten > remainingSamplesInFile) {
+       else if (samplesWritten > remainingSamplesInFile) {
                samplesWritten = remainingSamplesInFile;
        }
        
+       //if (samplesWritten) printf("at: %lu (total: %lu), request: %d 
(returned: %d)\n", m_nextFrame, m_frames, sampleCount/get_num_channels(), 
samplesWritten/get_num_channels());
+       
        m_nextFrame += samplesWritten / get_num_channels();
        return samplesWritten;
 }

Index: MadAudioReader.h
===================================================================
RCS file: /sources/traverso/traverso/src/core/MadAudioReader.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- MadAudioReader.h    8 Jul 2007 23:16:56 -0000       1.1
+++ MadAudioReader.h    13 Jul 2007 07:41:02 -0000      1.2
@@ -38,7 +38,6 @@
        int get_num_channels();
        nframes_t get_length();
        int get_rate();
-       bool is_compressed();
        bool seek(nframes_t start);
        int read(audio_sample_t* dst, int sampleCount);
 

Index: MonoReader.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/core/MonoReader.cpp,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -b -r1.19 -r1.20
--- MonoReader.cpp      7 Jul 2007 22:00:13 -0000       1.19
+++ MonoReader.cpp      13 Jul 2007 07:41:02 -0000      1.20
@@ -84,7 +84,6 @@
        m_syncInProgress = 0;
        m_clip = 0;
        m_bufferUnderRunDetected = m_wasActivated = 0;
-       m_isCompressedFile = false;
 
 
        //
@@ -114,10 +113,6 @@
        m_length = m_audioReader->get_length();
        m_source->m_rate = m_audioReader->get_rate();
 
-       if ( m_audioReader->is_compressed() ) {
-               m_isCompressedFile = true;
-       }
-       
        m_peak = new Peak(m_source, m_channelNumber);
        
        return 1;
@@ -265,11 +260,6 @@
        
        if (seeking) {
                toRead = writeSpace;
-               // For whatever reason, but FLAC crashes when refilling the 
-               // buffer completely in one round! :-(
-               if (m_isCompressedFile) {
-                       toRead = writeSpace / 2;
-               }
 //             printf("doing a full seek buffer fill\n");
        } else if (m_syncInProgress) {
                // Currently, we fill the buffer completely.
@@ -364,20 +354,9 @@
 
        float size = config().get_property("Hardware", "readbuffersize", 
1.0).toDouble();
 
-       if (m_isCompressedFile) {
-               size *= 2;
-               if (size > 3.0) {
-                       size = 3.0;
-               }
-       }
-
        m_bufferSize = (int) (size * audiodevice().get_sample_rate());
 
-       if ( ! m_isCompressedFile) {
                m_chunkSize = m_bufferSize / DiskIO::bufferdividefactor;
-       } else {
-               m_chunkSize = m_bufferSize / (DiskIO::bufferdividefactor / 2);
-       }
 
        m_buffer = new RingBufferNPT<float>(m_bufferSize);
 

Index: MonoReader.h
===================================================================
RCS file: /sources/traverso/traverso/src/core/MonoReader.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- MonoReader.h        6 Jul 2007 22:13:32 -0000       1.5
+++ MonoReader.h        13 Jul 2007 07:41:02 -0000      1.6
@@ -79,7 +79,6 @@
        volatile size_t m_wasActivated;
        volatile size_t m_bufferUnderRunDetected;
        bool            m_syncInProgress;
-       bool            m_isCompressedFile;
        int             m_prio;
        
        AudioClip*      m_clip;

Index: Peak.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/core/Peak.cpp,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -b -r1.33 -r1.34
--- Peak.cpp    27 Jun 2007 17:51:45 -0000      1.33
+++ Peak.cpp    13 Jul 2007 07:41:03 -0000      1.34
@@ -97,7 +97,7 @@
        m_file = fopen(m_fileName.toUtf8().data(),"rb");
        
        if (! m_file) {
-               PERROR("Couldn't open peak file for reading! (%s)", 
m_fileName.toAscii().data());
+               //PERROR("Couldn't open peak file for reading! (%s)", 
m_fileName.toAscii().data());
                return -1;
        }
        
@@ -293,17 +293,30 @@
                
        // Micro view mode
        } else {
-               nframes_t readFrames, toRead;
-               toRead = pixelcount * zoomStep[zoomLevel];
+               nframes_t toRead = pixelcount * zoomStep[zoomLevel];
                audio_sample_t buf[toRead];
                audio_sample_t readbuffer[toRead*2];
 
-               if ( (readFrames = m_source->file_read(m_channel, buf, 
startPos, toRead, readbuffer)) != toRead) {
-                       PWARN("Unable to read nframes %d (only %d available)", 
toRead, readFrames);
-                       if (readFrames == 0) {
+               nframes_t readFrames = 0;
+               nframes_t totalReadFrames = 0;
+               int counter = 0;
+               int p = 0;
+               
+               do {
+                       readFrames = m_source->file_read(m_channel, buf + 
totalReadFrames, startPos + totalReadFrames, toRead - totalReadFrames, 
readbuffer);
+                       if (readFrames <= 0) {
+                               PERROR("readFrames < 0");
+                               break;
+                       }
+                       totalReadFrames += readFrames;
+               } while (totalReadFrames < toRead);
+               
+               if ( totalReadFrames != toRead) {
+                       PWARN("Unable to read nframes %d (only %d available)", 
toRead, totalReadFrames);
+                       if (totalReadFrames == 0) {
                                return NO_PEAKDATA_FOUND;
                        }
-                       pixelcount = readFrames / zoomStep[zoomLevel];
+                       pixelcount = totalReadFrames / zoomStep[zoomLevel];
                }
 
                int count = 0;
@@ -573,7 +586,6 @@
 
        nframes_t bufferSize = 65536;
 
-       int cycles = m_source->get_nframes() / bufferSize;
        int counter = 0;
        int p = 0;
 
@@ -582,10 +594,9 @@
                return ret;
        }
 
-       if (cycles == 0) {
+       if (m_source->get_nframes() < bufferSize) {
                bufferSize = 64;
-               cycles = m_source->get_nframes() / bufferSize;
-               if (cycles == 0) {
+               if (m_source->get_nframes() < bufferSize) {
                        qDebug("source length is too short to display one pixel 
of the audio wave form in macro view");
                        return ret;
                }
@@ -601,17 +612,20 @@
                }
                
                readFrames = m_source->file_read(m_channel, buf, 
totalReadFrames, bufferSize, readbuffer);
+               if (readFrames <= 0) {
+                       PERROR("readFrames < 0 during peak building");
+                       break;
+               }
                process(buf, readFrames);
                totalReadFrames += readFrames;
-               counter++;
-               p = (int) (counter*100) / cycles;
+               p = (int) ((float)totalReadFrames / 
((float)m_source->get_nframes() / 100.0));
                
                if ( p > m_progress) {
                        emit progress(p - m_progress);
                        m_progress = p;
                }
                
-       } while(totalReadFrames != m_source->get_nframes());
+       } while (totalReadFrames < m_source->get_nframes());
 
 
        if (finish_processing() < 0) {

Index: ResampleAudioReader.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/core/ResampleAudioReader.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- ResampleAudioReader.cpp     8 Jul 2007 23:16:56 -0000       1.3
+++ ResampleAudioReader.cpp     13 Jul 2007 07:41:03 -0000      1.4
@@ -106,16 +106,6 @@
 }
 
 
-// Still not sure if this is going to be necessary...
-bool ResampleAudioReader::is_compressed()
-{
-       if (m_realReader) {
-               return m_realReader->is_compressed();
-       }
-       return false;
-}
-
-
 // if no conversion is necessary, pass the seek straight to the child 
AudioReader,
 // otherwise convert and seek
 bool ResampleAudioReader::seek(nframes_t start)
@@ -138,14 +128,21 @@
 // otherwise get data from childreader and use libsamplerate to convert
 int ResampleAudioReader::read(audio_sample_t* dst, int sampleCount)
 {
+       uint samplesRead;
        Q_ASSERT(m_realReader);
 
+       // pass through if not changing sampleRate.
        if (audiodevice().get_sample_rate() == m_realReader->get_rate()) {
-               return m_realReader->read(dst, sampleCount);
+               samplesRead = m_realReader->read(dst, sampleCount);
+               m_nextFrame += samplesRead / get_num_channels();
+               return samplesRead;
        }
        
-       // The +1 means decode a tiny bit extra from the file to make sure we 
can get enough resampled data
-       nframes_t fileCnt = (song_to_file_frame(sampleCount / 
get_num_channels()) +1) * get_num_channels();
+       nframes_t fileCnt = (song_to_file_frame(sampleCount / 
get_num_channels())) * get_num_channels();
+       
+       if (sampleCount && fileCnt / get_num_channels() < 1) {
+               fileCnt = get_num_channels();
+       }
        
        // make sure that the reusable m_fileBuffer is big enough for this read
        if (m_fileBufferLength < fileCnt) {
@@ -156,16 +153,11 @@
                m_fileBufferLength = fileCnt;
        }
        
-       int samplesRead;
        samplesRead = m_realReader->read(m_fileBuffer, fileCnt);
        
-       if (samplesRead == fileCnt) {
-               m_nextFrame += sampleCount / get_num_channels();
-       }
-       else {
-               m_nextFrame += file_to_song_frame(samplesRead) / 
get_num_channels();
-       }
+       //printf("Resampler: sampleCount %lu, fileCnt %lu, returned %lu\n", 
sampleCount/get_num_channels(), fileCnt/get_num_channels(), 
samplesRead/get_num_channels()); fflush(stdout);
        
+       // Set up sample rate converter struct for s.r.c. processing
        m_srcData.data_in = m_fileBuffer;
        m_srcData.input_frames = samplesRead / get_num_channels();
        m_srcData.data_out = dst;
@@ -174,11 +166,33 @@
        src_set_ratio(m_srcState, m_srcData.src_ratio);
        
        if (src_process(m_srcState, &m_srcData)) {
-               PERROR("src_process() error!");
+               PERROR("Resampler: src_process() error!");
                return 0;
        }
        
-       return m_srcData.output_frames_gen * get_num_channels();
+       samplesRead = m_srcData.output_frames_gen * get_num_channels();
+       
+       // Pad end of file with 0s if necessary
+       int remainingSamplesRequested = sampleCount - samplesRead;
+       int remainingSamplesInFile = get_length() * get_num_channels() - 
m_nextFrame * get_num_channels() - samplesRead;
+       
+       if (samplesRead == 0 && remainingSamplesRequested > 0 && 
remainingSamplesInFile > 0) {
+               int padLength = (remainingSamplesRequested > 
remainingSamplesInFile) ? remainingSamplesInFile : remainingSamplesRequested;
+               memset(dst+(samplesRead * sizeof(audio_sample_t)), 0, padLength 
* sizeof(audio_sample_t));
+               samplesRead += padLength;
+               printf("Resampler: padding: %d\n", padLength);
+       }       
+       
+       // Truncate so we don't return too many samples
+       if (samplesRead > remainingSamplesInFile) {
+               printf("Resampler: truncating: %d\n", samplesRead - 
remainingSamplesInFile);
+               samplesRead = remainingSamplesInFile;
+       }
+       
+       m_nextFrame += samplesRead / get_num_channels();
+       
+       //printf("Resampler: req: %d, got: %d\n", sampleCount, samplesRead);
+       return samplesRead;
 }
 
 

Index: ResampleAudioReader.h
===================================================================
RCS file: /sources/traverso/traverso/src/core/ResampleAudioReader.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- ResampleAudioReader.h       8 Jul 2007 23:16:56 -0000       1.3
+++ ResampleAudioReader.h       13 Jul 2007 07:41:03 -0000      1.4
@@ -35,7 +35,6 @@
        int get_num_channels();
        nframes_t get_length();
        int get_rate();
-       bool is_compressed();
        bool seek(nframes_t start);
        int read(audio_sample_t* dst, int sampleCount);
 

Index: VorbisAudioReader.cpp
===================================================================
RCS file: /sources/traverso/traverso/src/core/VorbisAudioReader.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- VorbisAudioReader.cpp       8 Jul 2007 23:16:56 -0000       1.3
+++ VorbisAudioReader.cpp       13 Jul 2007 07:41:03 -0000      1.4
@@ -37,7 +37,7 @@
 VorbisAudioReader::VorbisAudioReader(QString filename)
  : AbstractAudioReader(filename)
 {
-       m_file = fopen(QFile::encodeName(filename).data(), "rb");
+       m_file = fopen(filename.toUtf8().data(), "rb");
        if (!m_file) {
                PERROR("Couldn't open file %s.", QS_C(filename));
                return;
@@ -64,7 +64,7 @@
 
 bool VorbisAudioReader::can_decode(QString filename)
 {
-       FILE* file = fopen(QFile::encodeName(filename).data(), "rb");
+       FILE* file = fopen(filename.toUtf8().data(), "rb");
        if (!file) {
                PERROR("Could not open file: %s.", QS_C(filename));
                return false;
@@ -110,13 +110,6 @@
 }
 
 
-// Should this exist?  Should we just be smarter in MonoReader so we don't 
need this?
-bool VorbisAudioReader::is_compressed()
-{
-       return false;
-}
-
-
 bool VorbisAudioReader::seek(nframes_t start)
 {
        Q_ASSERT(m_file);

Index: VorbisAudioReader.h
===================================================================
RCS file: /sources/traverso/traverso/src/core/VorbisAudioReader.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- VorbisAudioReader.h 8 Jul 2007 23:16:57 -0000       1.3
+++ VorbisAudioReader.h 13 Jul 2007 07:41:03 -0000      1.4
@@ -37,7 +37,6 @@
        int get_num_channels();
        nframes_t get_length();
        int get_rate();
-       bool is_compressed();
        bool seek(nframes_t start);
        int read(audio_sample_t* dst, int sampleCount);
 

Index: core.pro
===================================================================
RCS file: /sources/traverso/traverso/src/core/core.pro,v
retrieving revision 1.31
retrieving revision 1.32
diff -u -b -r1.31 -r1.32
--- core.pro    8 Jul 2007 23:16:57 -0000       1.31
+++ core.pro    13 Jul 2007 07:41:03 -0000      1.32
@@ -53,6 +53,7 @@
        Themer.cpp \
        AbstractAudioReader.cpp \
        SFAudioReader.cpp \
+       FlacAudioReader.cpp \
        ResampleAudioReader.cpp \
        VorbisAudioReader.cpp \
        MadAudioReader.cpp
@@ -102,6 +103,7 @@
        Themer.h \
        AbstractAudioReader.h \
        SFAudioReader.h \
+       FlacAudioReader.h \
        ResampleAudioReader.h \
        VorbisAudioReader.h \
        MadAudioReader.h

Index: FlacAudioReader.cpp
===================================================================
RCS file: FlacAudioReader.cpp
diff -N FlacAudioReader.cpp
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ FlacAudioReader.cpp 13 Jul 2007 07:41:02 -0000      1.1
@@ -0,0 +1,455 @@
+/*
+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 "Utils.h"
+
+#include "FLAC++/decoder.h"
+
+#if !defined FLACPP_API_VERSION_CURRENT || FLACPP_API_VERSION_CURRENT < 6
+#define LEGACY_FLAC
+#else
+#undef LEGACY_FLAC
+#endif
+
+
+// Always put me below _all_ includes, this is needed
+// in case we run with memory leak detection enabled!
+#include "Debugger.h"
+
+
+class FlacPrivate
+#ifdef LEGACY_FLAC
+  : public FLAC::Decoder::SeekableStream
+#else
+  : public FLAC::Decoder::Stream
+#endif
+{
+       public:
+               FlacPrivate(QString filename);
+               ~FlacPrivate();
+               
+               bool open(QString filename) {
+                       file = new QFile(filename);
+                       if (!file->open(QIODevice::ReadOnly)) {
+                               return false;
+                       }
+                       
+                       init();
+                       process_until_end_of_metadata();
+                       return true;
+               }
+               
+               void cleanup() {
+                       delete internalBuffer;
+                       file->close();
+                       delete file;
+                       finish();
+               }
+               
+               
+               bool seek(nframes_t start);
+               int read(audio_sample_t* dst, int sampleCount);
+               
+               uint m_channels;
+               uint m_rate;
+               uint m_bitsPerSample;
+               uint m_samples;
+               
+               QVector<audio_sample_t> *internalBuffer;
+               int                     bufferStart;
+               
+       protected:
+#ifdef LEGACY_FLAC
+               virtual FLAC__SeekableStreamDecoderReadStatus 
read_callback(FLAC__byte buffer[], unsigned *bytes);
+               virtual FLAC__SeekableStreamDecoderSeekStatus 
seek_callback(FLAC__uint64 absolute_byte_offset);
+               virtual FLAC__SeekableStreamDecoderTellStatus 
tell_callback(FLAC__uint64 *absolute_byte_offset);
+               virtual FLAC__SeekableStreamDecoderLengthStatus 
length_callback(FLAC__uint64 *stream_length);
+#else
+               virtual FLAC__StreamDecoderReadStatus read_callback(FLAC__byte 
buffer[], size_t *bytes);
+               virtual FLAC__StreamDecoderSeekStatus 
seek_callback(FLAC__uint64 absolute_byte_offset);
+               virtual FLAC__StreamDecoderTellStatus 
tell_callback(FLAC__uint64 *absolute_byte_offset);
+               virtual FLAC__StreamDecoderLengthStatus 
length_callback(FLAC__uint64 *stream_length);
+#endif
+               virtual bool eof_callback();
+               virtual void error_callback(FLAC__StreamDecoderErrorStatus s){ 
printf("!!! %d !!!\n", s); };
+               virtual void metadata_callback(const ::FLAC__StreamMetadata 
*metadata);
+               virtual ::FLAC__StreamDecoderWriteStatus write_callback(const 
::FLAC__Frame *frame, const FLAC__int32 * const buffer[]);
+               
+               QFile           *file;
+};
+
+
+FlacPrivate::FlacPrivate(QString filename)
+#ifdef LEGACY_FLAC
+                       : FLAC::Decoder::SeekableStream()
+#else
+                       : FLAC::Decoder::Stream()
+#endif
+{
+       internalBuffer = new QVector<audio_sample_t>();
+       bufferStart = 0;
+       open(filename);
+       process_until_end_of_metadata();
+}
+
+
+FlacPrivate::~FlacPrivate()
+{
+       cleanup();
+}
+
+
+bool FlacPrivate::seek(nframes_t start)
+{
+       return seek_absolute(start);
+}
+
+
+FLAC__StreamDecoderWriteStatus FlacPrivate::write_callback(const FLAC__Frame 
*frame, const FLAC__int32 * const buffer[]) {
+       unsigned i, c, pos = 0;
+       unsigned frames = frame->header.blocksize;
+       
+       internalBuffer->resize(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)));
+                       internalBuffer->data()[++pos] = value;
+               }
+       }
+       
+       return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
+}
+
+
+#ifdef LEGACY_FLAC
+FLAC__SeekableStreamDecoderReadStatus FlacPrivate::read_callback(FLAC__byte 
buffer[],                                                                       
      unsigned *bytes) {
+  long retval =  file->read((char *)buffer, (*bytes));
+  if(-1 == retval) {
+    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(FLAC__byte buffer[],  
                                                                           
size_t *bytes) {
+  long retval =  file->read((char *)buffer, (*bytes));
+  if(-1 == retval) {
+    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(FLAC__uint64 absolute_byte_offset) {
+  if(!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(FLAC__uint64 absolute_byte_offset) {
+  if(file->seek(absolute_byte_offset) == FALSE)
+    return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR;
+  else
+    return FLAC__STREAM_DECODER_SEEK_STATUS_OK;
+}
+#endif
+
+#ifdef LEGACY_FLAC
+FLAC__SeekableStreamDecoderTellStatus 
+FlacPrivate::tell_callback(FLAC__uint64 *absolute_byte_offset) {
+  (*absolute_byte_offset) = file->pos();
+  return FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK;
+}
+#else
+FLAC__StreamDecoderTellStatus 
+FlacPrivate::tell_callback(FLAC__uint64 *absolute_byte_offset) {
+  (*absolute_byte_offset) = file->pos();
+  return FLAC__STREAM_DECODER_TELL_STATUS_OK;
+}
+#endif
+
+#ifdef LEGACY_FLAC
+FLAC__SeekableStreamDecoderLengthStatus 
+FlacPrivate::length_callback(FLAC__uint64 *stream_length) {
+  (*stream_length) = file->size();
+  return FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK;
+}
+#else
+FLAC__StreamDecoderLengthStatus 
+FlacPrivate::length_callback(FLAC__uint64 *stream_length) {
+  (*stream_length) = file->size();
+  return FLAC__STREAM_DECODER_LENGTH_STATUS_OK;
+}
+#endif
+
+
+void FlacPrivate::metadata_callback(const FLAC__StreamMetadata *metadata) {
+  switch (metadata->type) {
+  case FLAC__METADATA_TYPE_STREAMINFO:
+    m_channels = metadata->data.stream_info.channels;
+    m_rate = metadata->data.stream_info.sample_rate;
+    m_bitsPerSample = metadata->data.stream_info.bits_per_sample;
+    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;
+  }
+}
+
+
+bool FlacPrivate::eof_callback() {
+  return file->atEnd();
+}
+
+
+
+
+FlacAudioReader::FlacAudioReader(QString filename)
+ : AbstractAudioReader(filename)
+{
+       m_flac = new FlacPrivate(filename);
+}
+
+
+FlacAudioReader::~FlacAudioReader()
+{
+       if (m_flac) {
+               m_flac->finish();
+       }
+}
+
+
+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", QS_C(filename));
+               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;
+}
+
+
+int FlacAudioReader::get_num_channels()
+{
+       if (m_flac) {
+               return m_flac->m_channels;
+       }
+       return 0;
+}
+
+
+nframes_t FlacAudioReader::get_length()
+{
+       if (m_flac) {
+               // Is this returning one frame too long?
+               return m_flac->m_samples;
+       }
+       return 0;
+}
+
+
+int FlacAudioReader::get_rate()
+{
+       if (m_flac) {
+               return m_flac->m_rate;
+       }
+       return 0;
+}
+
+
+bool FlacAudioReader::seek(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, QS_C(m_fileName));
+               return false;
+       }
+       
+       m_flac->internalBuffer->resize(0);
+       m_flac->bufferStart = 0;
+       
+       if (!m_flac->seek(start)) {
+               PERROR("FlacAudioReader: could not seek to frame %d within %s", 
start, QS_C(m_fileName));
+               return false;
+       }
+       
+       m_nextFrame = start;
+
+       return true;
+}
+
+
+int FlacAudioReader::read(audio_sample_t* dst, int sampleCount)
+{
+       Q_ASSERT(m_flac);
+       
+       int samplesToCopy;
+       int samplesAvailable;
+       int samplesCoppied = 0;
+       
+       while (samplesCoppied < sampleCount) {
+               if (m_flac->internalBuffer->size() == 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->finish();
+                               m_flac->init();
+                               break;
+                       }
+                       else if(m_flac->get_state() == 
FLAC__SEEKABLE_STREAM_DECODER_OK) {
+                               //printf("process1\n");
+                               if (!m_flac->process_single()) {
+                                       PERROR("process_single() error\n");
+                                       return -1;
+                               }
+                       }
+                       else {
+                               PERROR("flac_state() = %d\n", 
m_flac->get_state());
+                               return -1;
+                       }
+#else
+                       if (m_flac->get_state() == 
FLAC__STREAM_DECODER_END_OF_STREAM) {
+                               //printf("flac file finish\n");
+                               m_flac->finish();
+                               m_flac->init();
+                               break;
+                       }
+                       else if(m_flac->get_state() < 
FLAC__STREAM_DECODER_END_OF_STREAM) {
+                               if (!m_flac->process_single()) {
+                                       PERROR("process_single() error\n");
+                                       return -1;
+                               }
+                       }
+                       else {
+                               PERROR("flac_state() = %d\n", 
m_flac->get_state());
+                               return -1;
+                       }
+#endif
+               }
+               
+               samplesAvailable = m_flac->internalBuffer->size() - 
m_flac->bufferStart;
+               samplesToCopy = (sampleCount - samplesCoppied < 
samplesAvailable) ? sampleCount - samplesCoppied : samplesAvailable;
+               for (int i = 0; i < samplesToCopy; i++) {
+                       dst[samplesCoppied + i] = 
m_flac->internalBuffer->at(m_flac->bufferStart + i);
+               }
+               
+               if(samplesToCopy == samplesAvailable) {
+                       m_flac->internalBuffer->resize(0);
+                       m_flac->bufferStart = 0;
+               }
+               else {
+                       m_flac->bufferStart += samplesToCopy;
+               }
+               samplesCoppied += samplesToCopy;
+               
+               //printf("samplesCoppied = %d (%d, %d)\n", samplesCoppied, 
m_flac->bufferStart, m_flac->internalBuffer->size());
+       }
+       
+       // Pad end of file with 0s if necessary.  (Shouldn't be necessary...)
+       /*int remainingSamplesRequested = sampleCount - samplesCoppied;
+       int remainingSamplesInFile = get_length() * get_num_channels() - 
(m_nextFrame * get_num_channels() + samplesCoppied);
+       if (samplesCoppied == 0 && remainingSamplesInFile > 0) {
+               int padLength = (remainingSamplesRequested > 
remainingSamplesInFile) ? remainingSamplesInFile : remainingSamplesRequested;
+               printf("padLength: %d\n", padLength);
+               memset(dst + sampleCount - padLength, 0, padLength * 
sizeof(audio_sample_t));
+               samplesCoppied += remainingSamplesInFile;
+       }*/
+       
+       m_nextFrame += samplesCoppied / get_num_channels();
+       
+       //printf("copied %d of %d.  nextFrame: %lu of %lu\n", samplesCoppied, 
sampleCount, m_nextFrame, get_length());
+       
+       return samplesCoppied;
+}
+

Index: FlacAudioReader.h
===================================================================
RCS file: FlacAudioReader.h
diff -N FlacAudioReader.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ FlacAudioReader.h   13 Jul 2007 07:41:02 -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 FLACAUDIOREADER_H
+#define FLACAUDIOREADER_H
+
+#include "AbstractAudioReader.h"
+
+
+class FlacPrivate;
+
+class FlacAudioReader : public AbstractAudioReader
+{
+public:
+       FlacAudioReader(QString filename);
+       ~FlacAudioReader();
+
+       int get_num_channels();
+       nframes_t get_length();
+       int get_rate();
+       bool seek(nframes_t start);
+       int read(audio_sample_t* dst, int sampleCount);
+       
+       static bool can_decode(QString filename);
+
+protected:
+       FlacPrivate *m_flac;
+};
+
+#endif




reply via email to

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