annotate data/fileio/OggVorbisFileReader.cpp @ 631:3a5ee4b6c9ad

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