svcore  1.9
OggVorbisFileReader.cpp
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7  This file copyright 2006 Chris Cannam.
8 
9  This program is free software; you can redistribute it and/or
10  modify it under the terms of the GNU General Public License as
11  published by the Free Software Foundation; either version 2 of the
12  License, or (at your option) any later version. See the file
13  COPYING included with this distribution for more information.
14 */
15 
16 #ifdef HAVE_OGGZ
17 #ifdef HAVE_FISHSOUND
18 
19 #include "OggVorbisFileReader.h"
20 
21 #include "base/ProgressReporter.h"
22 #include "base/Profiler.h"
23 #include "system/System.h"
24 
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <cmath>
29 
30 #include <QFileInfo>
31 
32 //static int instances = 0;
33 
35  DecodeMode decodeMode,
36  CacheMode mode,
37  int targetRate,
38  bool normalised,
39  ProgressReporter *reporter) :
40  CodedAudioFileReader(mode, targetRate, normalised),
41  m_source(source),
42  m_path(source.getLocalFilename()),
43  m_reporter(reporter),
44  m_fileSize(0),
45  m_bytesRead(0),
46  m_commentsRead(false),
47  m_cancelled(false),
48  m_completion(0),
49  m_decodeThread(0)
50 {
51  m_channelCount = 0;
52  m_fileRate = 0;
53 
54 // SVDEBUG << "OggVorbisFileReader::OggVorbisFileReader(" << m_path << "): now have " << (++instances) << " instances" << endl;
55 
56  Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
57 
58  QFileInfo info(m_path);
59  m_fileSize = info.size();
60 
61  if (!(m_oggz = oggz_open(m_path.toLocal8Bit().data(), OGGZ_READ))) {
62  m_error = QString("File %1 is not an OGG file.").arg(m_path);
63  return;
64  }
65 
66  FishSoundInfo fsinfo;
67  m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
68 
69  fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
70  oggz_set_read_callback(m_oggz, -1, (OggzReadPacket)readPacket, this);
71 
72  if (decodeMode == DecodeAtOnce) {
73 
74  if (m_reporter) {
75  connect(m_reporter, SIGNAL(cancelled()), this, SLOT(cancelled()));
77  (tr("Decoding %1...").arg(QFileInfo(m_path).fileName()));
78  }
79 
80  while (oggz_read(m_oggz, 1024) > 0);
81 
82  fish_sound_delete(m_fishSound);
83  m_fishSound = 0;
84  oggz_close(m_oggz);
85  m_oggz = 0;
86 
88  endSerialised();
89 
90  } else {
91 
93 
94  while (oggz_read(m_oggz, 1024) > 0 &&
95  (m_channelCount == 0 || m_fileRate == 0 || m_sampleRate == 0));
96 
97  if (m_channelCount > 0) {
98  m_decodeThread = new DecodeThread(this);
100  }
101  }
102 }
103 
105 {
106 // SVDEBUG << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path << "): now have " << (--instances) << " instances" << endl;
107  if (m_decodeThread) {
108  m_cancelled = true;
109  m_decodeThread->wait();
110  delete m_decodeThread;
111  }
112 }
113 
114 void
116 {
117  m_cancelled = true;
118 }
119 
120 void
122 {
124  m_reader->m_completion = 1;
125  m_reader->startSerialised("OggVorbisFileReader::Decode");
126  }
127 
128  while (oggz_read(m_reader->m_oggz, 1024) > 0);
129 
130  fish_sound_delete(m_reader->m_fishSound);
131  m_reader->m_fishSound = 0;
132  oggz_close(m_reader->m_oggz);
133  m_reader->m_oggz = 0;
134 
136  m_reader->m_completion = 100;
137 
139 }
140 
141 int
142 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
143 {
144  OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
145  FishSound *fs = reader->m_fishSound;
146 
147  fish_sound_prepare_truncation(fs, packet->granulepos, packet->e_o_s);
148  fish_sound_decode(fs, packet->packet, packet->bytes);
149 
150  reader->m_bytesRead += packet->bytes;
151 
152  // The number of bytes read by this function is smaller than
153  // the file size because of the packet headers
154  int p = lrint(double(reader->m_bytesRead) * 114 /
155  double(reader->m_fileSize));
156  if (p > 99) p = 99;
157  reader->m_completion = p;
158  reader->progress(p);
159 
160  if (reader->m_fileSize > 0 && reader->m_reporter) {
161  reader->m_reporter->setProgress(p);
162  }
163 
164  if (reader->m_cancelled) return 1;
165  return 0;
166 }
167 
168 int
169 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
170  void *data)
171 {
172  OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
173 
174  if (!reader->m_commentsRead) {
175  const FishSoundComment *comment;
176  comment = fish_sound_comment_first_byname(fs, "TITLE");
177  if (comment && comment->value) {
178  reader->m_title = QString::fromUtf8(comment->value);
179  }
180  comment = fish_sound_comment_first_byname(fs, "ARTIST");
181  if (comment && comment->value) {
182  reader->m_maker = QString::fromUtf8(comment->value);
183  }
184  comment = fish_sound_comment_first(fs);
185  while (comment) {
186  reader->m_tags[QString::fromUtf8(comment->name).toUpper()] =
187  QString::fromUtf8(comment->value);
188  comment = fish_sound_comment_next(fs, comment);
189  }
190  reader->m_commentsRead = true;
191  }
192 
193  if (reader->m_channelCount == 0) {
194  FishSoundInfo fsinfo;
195  fish_sound_command(fs, FISH_SOUND_GET_INFO,
196  &fsinfo, sizeof(FishSoundInfo));
197  reader->m_fileRate = fsinfo.samplerate;
198  reader->m_channelCount = fsinfo.channels;
199  reader->initialiseDecodeCache();
200  }
201 
202  if (nframes > 0) {
203  reader->addSamplesToDecodeCache(frames, nframes);
204  }
205 
206  if (reader->m_cancelled) return 1;
207  return 0;
208 }
209 
210 void
211 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
212 {
213  extensions.insert("ogg");
214  extensions.insert("oga");
215 }
216 
217 bool
219 {
220  std::set<QString> extensions;
221  getSupportedExtensions(extensions);
222  return (extensions.find(extension.toLower()) != extensions.end());
223 }
224 
225 bool
227 {
228  return (type == "application/ogg");
229 }
230 
231 bool
233 {
234  return (supportsExtension(source.getExtension()) ||
236 }
237 
238 #endif
239 #endif
QString getExtension() const
Return the file extension for this file, if any.
Definition: FileSource.cpp:619
void start()
Definition: Thread.cpp:34
OggVorbisFileReader(FileSource source, DecodeMode decodeMode, CacheMode cacheMode, int targetRate=0, bool normalised=false, ProgressReporter *reporter=0)
static void getSupportedExtensions(std::set< QString > &extensions)
DecodeThread * m_decodeThread
void addSamplesToDecodeCache(float **samples, int nframes)
static int readPacket(OGGZ *, ogg_packet *, long, void *)
FileSource is a class used to refer to the contents of a file that may be either local or at a remote...
Definition: FileSource.h:59
virtual void setProgress(int percentage)=0
static bool supportsContentType(QString type)
bool isDecodeCacheInitialised() const
QString getContentType() const
Return the MIME content type of this file, if known.
Definition: FileSource.cpp:613
virtual void setMessage(QString text)=0
void startSerialised(QString id)
static int acceptFrames(FishSound *, float **, long, void *)
ProgressReporter * m_reporter
static bool supports(FileSource &source)
static bool supportsExtension(QString ext)
Profile point instance class.
Definition: Profiler.h:86