File indexing completed on 2024-05-12 16:23:35

0001 /***************************************************************************
0002  *   Copyright (C) 2005-2008 by Bjoern Erik Nilsen & Fredrik Berg Kjoelstad*
0003  *   bjoern.nilsen@bjoernen.com & fredrikbk@hotmail.com                    *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 #include "oggvorbis.h"
0021 
0022 #include <assert.h>
0023 #include <stdio.h>
0024 #include <stdlib.h>
0025 #include <cerrno>
0026 #include <new>
0027 
0028 #include <vorbis/codec.h>
0029 
0030 #include "errorhandler.h"
0031 #include "workspacefile.h"
0032 #include "src/foundation/logger.h"
0033 #include "src/foundation/uiexception.h"
0034 
0035 
0036 class FileCloser {
0037     FILE* h;
0038 public:
0039     FileCloser(FILE* fh) : h(fh) {
0040     }
0041     FILE* release() {
0042         FILE* r = h;
0043         h = 0;
0044         return r;
0045     }
0046     ~FileCloser() {
0047         if (h) {
0048             fclose(h);
0049         }
0050     }
0051 };
0052 
0053 OggVorbis::OggVorbis() {
0054     oggFile = NULL;
0055 }
0056 
0057 
0058 OggVorbis::~OggVorbis() {
0059     close();
0060 }
0061 
0062 
0063 void OggVorbis::setFilename(WorkspaceFile& file, ErrorHandler& e) {
0064     assert(file.path() != NULL);
0065 
0066     // Opens the file and tests for vorbis-ness
0067     FILE *f = fopen(file.path(), "r");
0068     FileCloser fcloser(f);
0069     if (f) {
0070         close();
0071         oggFile = (OggVorbis_File*)malloc( sizeof(OggVorbis_File) );
0072         if (oggFile == NULL) {
0073             throw std::bad_alloc();
0074         }
0075 
0076         if ( ov_test(f, oggFile, NULL, 0) < 0 ) {
0077             Logger::get().logDebug("Not a valid oggfile");
0078             free(oggFile);
0079             oggFile = NULL;
0080             e.error( UiException(UiException::invalidAudioFormat) );
0081             return;
0082         }
0083         // For some reason, ov_test does not necessarily take
0084         // ownership of our file handle. We must only release
0085         // ownership if oggFile has taken it.
0086         if (oggFile->datasource == f)
0087             fcloser.release();
0088         this->filename.swap(file);
0089     } else {
0090         int err = errno;
0091         if (err == ENOMEM) {
0092             throw std::bad_alloc();
0093         }
0094         Logger::get().logDebug("Cannot open file '%s' for reading", file.path());
0095         e.error( UiException(UiException::couldNotOpenFile) );
0096     }
0097 }
0098 
0099 
0100 int OggVorbis::open() {
0101     FILE *f = fopen(filename.path(), "r");
0102     FileCloser fcloser(f);
0103     if (f) {
0104         close();
0105         oggFile = (OggVorbis_File*)malloc( sizeof(OggVorbis_File) );
0106         if (oggFile == NULL) {
0107             throw std::bad_alloc();
0108         }
0109         if ( ov_open(f, oggFile, NULL, 0) == 0 ) {
0110             fcloser.release();
0111             return 0;
0112         }
0113         free(oggFile);
0114         oggFile = NULL;
0115     }
0116     return -1;
0117 }
0118 
0119 
0120 void OggVorbis::reset() {
0121     if (oggFile) {
0122         ov_raw_seek(oggFile, 0);
0123     }
0124 }
0125 
0126 
0127 int OggVorbis::close() {
0128     if (oggFile) {
0129         ov_clear(oggFile);
0130         free(oggFile);
0131         oggFile = NULL;
0132         return 0;
0133     }
0134     return -1;
0135 }
0136 
0137 
0138 int OggVorbis::fillBuffer(char *audioBuffer, int numBytes) {
0139     assert(audioBuffer != NULL);
0140     if (oggFile) {
0141         int dummy;
0142         int ret = ov_read(oggFile, audioBuffer, numBytes,
0143                 littleEndian, wordsAre16Bit, wordsAreSigned, &dummy);
0144         if (ret < 0) {
0145             Logger logger = Logger::get();
0146             switch (ret) {
0147             case OV_HOLE:
0148                 logger.logWarning("Hole in the vorbis audio data");
0149                 break;
0150             case OV_EBADLINK:
0151                 logger.logWarning("Invalid link or stream section in vorbis audio data");
0152                 break;
0153             case OV_EINVAL:
0154                 logger.logWarning("Corrupt initial headers for vorbis audio data");
0155                 break;
0156             default:
0157                 logger.logWarning("Unknown error in vorbis audio data");
0158                 break;
0159             }
0160             return 0;
0161         }
0162         return ret;
0163     }
0164     return 0;
0165 }
0166 
0167 
0168 int OggVorbis::add16bit(int16_t* audioBuffer, int) {
0169     assert(audioBuffer);
0170     return 0;
0171 }
0172 
0173 
0174 const char* OggVorbis::getSoundPath() const {
0175     return filename.path();
0176 }
0177 
0178 const char* OggVorbis::getBasename() const {
0179     return filename.basename();
0180 }
0181