annotate data/fileio/OggVorbisFileReader.cpp @ 295:a2dc34ce146a

* Window should be centred on its nominal time. I'm not sure what the reasoning was behind the previous formulations of these two lines.
author Chris Cannam
date Thu, 06 Sep 2007 15:14:47 +0000
parents 92e8dbde73cd
children c022976d18e8
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@148 20 #include "base/Profiler.h"
Chris@150 21 #include "system/System.h"
Chris@148 22
Chris@148 23 #include <sys/types.h>
Chris@148 24 #include <sys/stat.h>
Chris@148 25 #include <sys/mman.h>
Chris@148 26 #include <fcntl.h>
Chris@148 27 #include <cmath>
Chris@148 28
Chris@148 29 #include <QApplication>
Chris@148 30 #include <QFileInfo>
Chris@148 31 #include <QProgressDialog>
Chris@148 32
Chris@148 33 static int instances = 0;
Chris@148 34
Chris@290 35 OggVorbisFileReader::OggVorbisFileReader(QString path,
Chris@263 36 DecodeMode decodeMode,
Chris@148 37 CacheMode mode) :
Chris@148 38 CodedAudioFileReader(mode),
Chris@148 39 m_path(path),
Chris@148 40 m_progress(0),
Chris@148 41 m_fileSize(0),
Chris@148 42 m_bytesRead(0),
Chris@271 43 m_commentsRead(false),
Chris@263 44 m_cancelled(false),
Chris@265 45 m_completion(0),
Chris@263 46 m_decodeThread(0)
Chris@148 47 {
Chris@148 48 m_frameCount = 0;
Chris@148 49 m_channelCount = 0;
Chris@148 50 m_sampleRate = 0;
Chris@148 51
Chris@290 52 std::cerr << "OggVorbisFileReader::OggVorbisFileReader(" << path.toLocal8Bit().data() << "): now have " << (++instances) << " instances" << std::endl;
Chris@148 53
Chris@148 54 Profiler profiler("OggVorbisFileReader::OggVorbisFileReader", true);
Chris@148 55
Chris@290 56 QFileInfo info(path);
Chris@148 57 m_fileSize = info.size();
Chris@148 58
Chris@290 59 if (!(m_oggz = oggz_open(path.toLocal8Bit().data(), OGGZ_READ))) {
Chris@290 60 m_error = QString("File %1 is not an OGG file.").arg(path);
Chris@148 61 return;
Chris@148 62 }
Chris@148 63
Chris@148 64 FishSoundInfo fsinfo;
Chris@148 65 m_fishSound = fish_sound_new(FISH_SOUND_DECODE, &fsinfo);
Chris@148 66
Chris@148 67 fish_sound_set_decoded_callback(m_fishSound, acceptFrames, this);
Chris@263 68 oggz_set_read_callback(m_oggz, -1, readPacket, this);
Chris@148 69
Chris@263 70 if (decodeMode == DecodeAtOnce) {
Chris@263 71
Chris@148 72 m_progress = new QProgressDialog
Chris@290 73 (QObject::tr("Decoding %1...").arg(QFileInfo(path).fileName()),
Chris@148 74 QObject::tr("Stop"), 0, 100);
Chris@148 75 m_progress->hide();
Chris@148 76
Chris@263 77 while (oggz_read(m_oggz, 1024) > 0);
Chris@263 78
Chris@263 79 fish_sound_delete(m_fishSound);
Chris@263 80 m_fishSound = 0;
Chris@263 81 oggz_close(m_oggz);
Chris@263 82 m_oggz = 0;
Chris@148 83
Chris@263 84 if (isDecodeCacheInitialised()) finishDecodeCache();
Chris@148 85
Chris@281 86 delete m_progress;
Chris@281 87 m_progress = 0;
Chris@148 88
Chris@263 89 } else {
Chris@263 90
Chris@263 91 while (oggz_read(m_oggz, 1024) > 0 &&
Chris@263 92 m_channelCount == 0);
Chris@263 93
Chris@263 94 if (m_channelCount > 0) {
Chris@263 95 m_decodeThread = new DecodeThread(this);
Chris@263 96 m_decodeThread->start();
Chris@263 97 }
Chris@148 98 }
Chris@148 99 }
Chris@148 100
Chris@148 101 OggVorbisFileReader::~OggVorbisFileReader()
Chris@148 102 {
Chris@290 103 std::cerr << "OggVorbisFileReader::~OggVorbisFileReader(" << m_path.toLocal8Bit().data() << "): now have " << (--instances) << " instances" << std::endl;
Chris@263 104 if (m_decodeThread) {
Chris@265 105 m_cancelled = true;
Chris@263 106 m_decodeThread->wait();
Chris@263 107 delete m_decodeThread;
Chris@263 108 }
Chris@148 109 }
Chris@148 110
Chris@263 111 void
Chris@263 112 OggVorbisFileReader::DecodeThread::run()
Chris@263 113 {
Chris@263 114 while (oggz_read(m_reader->m_oggz, 1024) > 0);
Chris@263 115
Chris@263 116 fish_sound_delete(m_reader->m_fishSound);
Chris@263 117 m_reader->m_fishSound = 0;
Chris@263 118 oggz_close(m_reader->m_oggz);
Chris@263 119 m_reader->m_oggz = 0;
Chris@263 120
Chris@263 121 if (m_reader->isDecodeCacheInitialised()) m_reader->finishDecodeCache();
Chris@265 122 m_reader->m_completion = 100;
Chris@263 123 }
Chris@263 124
Chris@148 125 int
Chris@148 126 OggVorbisFileReader::readPacket(OGGZ *, ogg_packet *packet, long, void *data)
Chris@148 127 {
Chris@148 128 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 129 FishSound *fs = reader->m_fishSound;
Chris@148 130
Chris@148 131 fish_sound_prepare_truncation(fs, packet->granulepos, packet->e_o_s);
Chris@148 132 fish_sound_decode(fs, packet->packet, packet->bytes);
Chris@148 133
Chris@148 134 reader->m_bytesRead += packet->bytes;
Chris@265 135
Chris@265 136 // The number of bytes read by this function is smaller than
Chris@265 137 // the file size because of the packet headers
Chris@265 138 int progress = lrint(double(reader->m_bytesRead) * 114 /
Chris@265 139 double(reader->m_fileSize));
Chris@265 140 if (progress > 99) progress = 99;
Chris@265 141 reader->m_completion = progress;
Chris@148 142
Chris@148 143 if (reader->m_fileSize > 0 && reader->m_progress) {
Chris@148 144 if (progress > reader->m_progress->value()) {
Chris@148 145 reader->m_progress->setValue(progress);
Chris@148 146 reader->m_progress->show();
Chris@148 147 reader->m_progress->raise();
Chris@148 148 qApp->processEvents();
Chris@148 149 if (reader->m_progress->wasCanceled()) {
Chris@148 150 reader->m_cancelled = true;
Chris@148 151 }
Chris@148 152 }
Chris@265 153 }
Chris@148 154
Chris@148 155 if (reader->m_cancelled) return 1;
Chris@148 156 return 0;
Chris@148 157 }
Chris@148 158
Chris@148 159 int
Chris@148 160 OggVorbisFileReader::acceptFrames(FishSound *fs, float **frames, long nframes,
Chris@148 161 void *data)
Chris@148 162 {
Chris@148 163 OggVorbisFileReader *reader = (OggVorbisFileReader *)data;
Chris@148 164
Chris@271 165 if (!reader->m_commentsRead) {
Chris@271 166 const FishSoundComment *comment = fish_sound_comment_first_byname
Chris@271 167 (fs, "TITLE");
Chris@271 168 if (comment && comment->value) {
Chris@290 169 reader->m_title = QString::fromUtf8(comment->value);
Chris@271 170 }
Chris@271 171 reader->m_commentsRead = true;
Chris@271 172 }
Chris@271 173
Chris@148 174 if (reader->m_channelCount == 0) {
Chris@148 175 FishSoundInfo fsinfo;
Chris@148 176 fish_sound_command(fs, FISH_SOUND_GET_INFO,
Chris@148 177 &fsinfo, sizeof(FishSoundInfo));
Chris@148 178 reader->m_channelCount = fsinfo.channels;
Chris@148 179 reader->m_sampleRate = fsinfo.samplerate;
Chris@148 180 reader->initialiseDecodeCache();
Chris@148 181 }
Chris@148 182
Chris@148 183 if (nframes > 0) {
Chris@148 184
Chris@148 185 reader->m_frameCount += nframes;
Chris@148 186
Chris@148 187 for (long i = 0; i < nframes; ++i) {
Chris@148 188 for (size_t c = 0; c < reader->m_channelCount; ++c) {
Chris@148 189 reader->addSampleToDecodeCache(frames[c][i]);
Chris@148 190 }
Chris@148 191 }
Chris@148 192
Chris@148 193 MUNLOCK_SAMPLEBLOCK(reader->m_data);
Chris@148 194 }
Chris@148 195
Chris@148 196 if (reader->m_cancelled) return 1;
Chris@148 197 return 0;
Chris@148 198 }
Chris@148 199
Chris@157 200 void
Chris@290 201 OggVorbisFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 202 {
Chris@157 203 extensions.insert("ogg");
Chris@157 204 }
Chris@157 205
Chris@148 206 #endif
Chris@148 207 #endif