[Top][All Lists]
[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
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/08
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/09
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr...,
Ben Levitt <=
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/15
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/18
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/19
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/20
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/24
- [Traverso-commit] traverso/src/core AbstractAudioReader.cpp Abstr..., Ben Levitt, 2007/07/25