Audio file loading backend libsndfile!
authorJoerg Mueller <nexyon@gmail.com>
Fri, 21 Aug 2009 19:39:28 +0000 (19:39 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Fri, 21 Aug 2009 19:39:28 +0000 (19:39 +0000)
14 files changed:
CMake/macros.cmake
CMakeLists.txt
intern/audaspace/CMakeLists.txt
intern/audaspace/ffmpeg/AUD_FFMPEGFactory.cpp
intern/audaspace/ffmpeg/AUD_FFMPEGFactory.h
intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
intern/audaspace/intern/AUD_C-API.cpp
intern/audaspace/intern/AUD_FileFactory.cpp [new file with mode: 0644]
intern/audaspace/intern/AUD_FileFactory.h [new file with mode: 0644]
intern/audaspace/sndfile/AUD_SndFileFactory.cpp [new file with mode: 0644]
intern/audaspace/sndfile/AUD_SndFileFactory.h [new file with mode: 0644]
intern/audaspace/sndfile/AUD_SndFileReader.cpp [new file with mode: 0644]
intern/audaspace/sndfile/AUD_SndFileReader.h [new file with mode: 0644]

index 9ba33df..6a33750 100644 (file)
@@ -70,6 +70,9 @@ MACRO(SETUP_LIBDIRS)
   IF(WITH_JACK)
     LINK_DIRECTORIES(${JACK_LIBPATH})
   ENDIF(WITH_JACK)
+  IF(WITH_SNDFILE)
+    LINK_DIRECTORIES(${SNDFILE_LIBPATH})
+  ENDIF(WITH_SNDFILE)
   IF(WITH_FFTW3)
     LINK_DIRECTORIES(${FFTW3_LIBPATH})
   ENDIF(WITH_FFTW3)
@@ -118,6 +121,9 @@ MACRO(SETUP_LIBLINKS
   IF(WITH_JACK)
     TARGET_LINK_LIBRARIES(${target} ${JACK_LIB})
   ENDIF(WITH_JACK)
+  IF(WITH_SNDFILE)
+    TARGET_LINK_LIBRARIES(${target} ${SNDFILE_LIB})
+  ENDIF(WITH_SNDFILE)
   IF(WITH_SDL)
     TARGET_LINK_LIBRARIES(${target} ${SDL_LIBRARY})
   ENDIF(WITH_SDL)
index 9db2511..749284d 100644 (file)
@@ -70,6 +70,7 @@ OPTION(WITH_OPENMP        "Enable OpenMP (has to be supported by the compiler)"
 OPTION(WITH_WEBPLUGIN     "Enable Web Plugin (Unix only)" OFF)
 OPTION(WITH_FFTW3         "Enable FFTW3 support" OFF)
 OPTION(WITH_JACK          "Enable Jack Support (http://www.jackaudio.org)" OFF)
+OPTION(WITH_SNDFILE       "Enable libsndfile Support (http://www.mega-nerd.com/libsndfile)" OFF)
 OPTION(WITH_CXX_GUARDEDALLOC "Enable GuardedAlloc for C++ memory allocation" OFF)
 OPTION(WITH_INSTALL       "Install accompanying scripts and language files needed to run blender" ON)
 
@@ -109,6 +110,13 @@ IF(UNIX AND NOT APPLE)
     SET(JACK_LIBPATH ${JACK}/lib)
   ENDIF(WITH_JACK)
 
+  IF(WITH_SNDFILE)
+       SET(SNDFILE /usr)
+       SET(SNDFILE_INC ${SNDFILE}/include)
+       SET(SNDFILE_LIB sndfile)
+       SET(SNDFILE_LIBPATH ${SNDFILE}/lib)
+  ENDIF(WITH_SNDFILE)
+
   FIND_LIBRARY(INTL_LIBRARY
     NAMES intl
     PATHS
@@ -247,6 +255,13 @@ IF(WIN32)
     SET(JACK_LIBPATH ${JACK}/lib)
   ENDIF(WITH_JACK)
 
+  IF(WITH_SNDFILE)
+       SET(SNDFILE ${LIBDIR}/sndfile)
+       SET(SNDFILE_INC ${SNDFILE}/include)
+       SET(SNDFILE_LIB sndfile)
+       SET(SNDFILE_LIBPATH ${SNDFILE}/lib)
+  ENDIF(WITH_SNDFILE)
+
   IF(CMAKE_CL_64)
     SET(PNG_LIBRARIES libpng)
   ELSE(CMAKE_CL_64)
@@ -392,6 +407,13 @@ IF(APPLE)
     SET(JACK_LIBPATH ${JACK}/lib)
   ENDIF(WITH_JACK)
 
+  IF(WITH_SNDFILE)
+       SET(SNDFILE /usr)
+       SET(SNDFILE_INC ${SNDFILE}/include)
+       SET(SNDFILE_LIB sndfile)
+       SET(SNDFILE_LIBPATH ${SNDFILE}/lib)
+  ENDIF(WITH_SNDFILE)
+
   SET(PYTHON_VERSION 3.1)
 
   IF(PYTHON_VERSION MATCHES 3.1)
index 940a4b2..1b48de3 100644 (file)
@@ -53,6 +53,12 @@ IF(WITH_JACK)
   ADD_DEFINITIONS(-DWITH_JACK)
 ENDIF(WITH_JACK)
 
-SET(SRC ${SRC} ${FFMPEGSRC} ${SDLSRC} ${OPENALSRC} ${JACKSRC})
+IF(WITH_SNDFILE)
+  SET(INC ${INC} sndfile ${SNDFILE_INC})
+  FILE(GLOB SNDFILESRC sndfile/*.cpp)
+  ADD_DEFINITIONS(-DWITH_SNDFILE)
+ENDIF(WITH_SNDFILE)
+
+SET(SRC ${SRC} ${FFMPEGSRC} ${SNDFILESRC} ${SDLSRC} ${OPENALSRC} ${JACKSRC})
 
 BLENDERLIB(bf_audaspace "${SRC}" "${INC}")
index 5f9006b..f67c819 100644 (file)
 
 #include "AUD_FFMPEGFactory.h"
 #include "AUD_FFMPEGReader.h"
-#include "AUD_Space.h"
-
-extern "C" {
-#include <libavformat/avformat.h>
-}
+#include "AUD_Buffer.h"
 
 AUD_FFMPEGFactory::AUD_FFMPEGFactory(const char* filename)
 {
-       if(filename != 0)
+       if(filename != NULL)
        {
                m_filename = new char[strlen(filename)+1]; AUD_NEW("string")
                strcpy(m_filename, filename);
        }
        else
-               m_filename = 0;
-       m_buffer = 0;
-       m_size = 0;
+               m_filename = NULL;
 }
 
 AUD_FFMPEGFactory::AUD_FFMPEGFactory(unsigned char* buffer, int size)
 {
-       m_filename = 0;
-       m_buffer = (unsigned char*)av_malloc(size); AUD_NEW("buffer")
-       m_size = size;
-       memcpy(m_buffer, buffer, size);
+       m_filename = NULL;
+       m_buffer = AUD_Reference<AUD_Buffer>(new AUD_Buffer(size));
+       memcpy(m_buffer.get()->getBuffer(), buffer, size);
 }
 
 AUD_FFMPEGFactory::~AUD_FFMPEGFactory()
@@ -58,31 +51,15 @@ AUD_FFMPEGFactory::~AUD_FFMPEGFactory()
        {
                delete[] m_filename; AUD_DELETE("string")
        }
-       if(m_buffer)
-       {
-               av_free(m_buffer); AUD_DELETE("buffer")
-       }
 }
 
 AUD_IReader* AUD_FFMPEGFactory::createReader()
 {
-       try
-       {
-               AUD_IReader* reader;
-               if(m_filename)
-                       reader = new AUD_FFMPEGReader(m_filename);
-               else
-                       reader = new AUD_FFMPEGReader(m_buffer, m_size);
-               AUD_NEW("reader")
-               return reader;
-       }
-       catch(AUD_Exception e)
-       {
-               // return 0 if ffmpeg cannot read the file
-               if(e.error == AUD_ERROR_FFMPEG)
-                       return 0;
-               // but throw an exception if the file doesn't exist
-               else
-                       throw;
-       }
+       AUD_IReader* reader;
+       if(m_filename)
+               reader = new AUD_FFMPEGReader(m_filename);
+       else
+               reader = new AUD_FFMPEGReader(m_buffer);
+       AUD_NEW("reader")
+       return reader;
 }
index 0a9fcc2..2256030 100644 (file)
@@ -27,6 +27,8 @@
 #define AUD_FFMPEGFACTORY
 
 #include "AUD_IFactory.h"
+#include "AUD_Reference.h"
+class AUD_Buffer;
 
 /**
  * This factory reads a sound file via ffmpeg.
@@ -44,12 +46,7 @@ private:
        /**
         * The buffer to read from.
         */
-       unsigned char* m_buffer;
-
-       /**
-        * The size of the buffer.
-        */
-       int m_size;
+       AUD_Reference<AUD_Buffer> m_buffer;
 
 public:
        /**
index b79375c..de0e473 100644 (file)
@@ -158,21 +158,22 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(const char* filename)
        AUD_NEW("buffer")
 }
 
-AUD_FFMPEGReader::AUD_FFMPEGReader(unsigned char* buffer, int size)
+AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer)
 {
        m_position = 0;
        m_pkgbuf_left = 0;
        m_byteiocontext = (ByteIOContext*)av_mallocz(sizeof(ByteIOContext));
        AUD_NEW("byteiocontext")
+       m_membuffer = buffer;
 
-       if(init_put_byte(m_byteiocontext, buffer, size, 0,
+       if(init_put_byte(m_byteiocontext, buffer.get()->getBuffer(), buffer.get()->getSize(), 0,
                                         NULL, NULL, NULL, NULL) != 0)
                AUD_THROW(AUD_ERROR_FILE);
 
        AVProbeData probe_data;
        probe_data.filename = "";
-       probe_data.buf = buffer;
-       probe_data.buf_size = size;
+       probe_data.buf = buffer.get()->getBuffer();
+       probe_data.buf_size = buffer.get()->getSize();
        AVInputFormat* fmt = av_probe_input_format(&probe_data, 1);
 
        // open stream
index 645f5f3..6e30393 100644 (file)
@@ -27,7 +27,9 @@
 #define AUD_FFMPEGREADER
 
 #include "AUD_IReader.h"
+#include "AUD_Reference.h"
 class AUD_Buffer;
+
 struct AVCodecContext;
 extern "C" {
 #include <libavformat/avformat.h>
@@ -89,6 +91,11 @@ private:
         */
        int m_stream;
 
+       /**
+        * The memory file to read from, only saved to keep the buffer alive.
+        */
+       AUD_Reference<AUD_Buffer> m_membuffer;
+
        /**
         * Decodes a packet into the given buffer.
         * \param packet The AVPacket to decode.
@@ -109,11 +116,10 @@ public:
        /**
         * Creates a new reader.
         * \param buffer The buffer to read from.
-        * \param size The size of the buffer.
         * \exception AUD_Exception Thrown if the buffer specified cannot be read
         *                          with ffmpeg.
         */
-       AUD_FFMPEGReader(unsigned char* buffer, int size);
+       AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer);
 
        /**
         * Destroys the reader and closes the file.
index d2c8e94..9481e21 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "AUD_NULLDevice.h"
 #include "AUD_I3DDevice.h"
+#include "AUD_FileFactory.h"
 #include "AUD_StreamBufferFactory.h"
 #include "AUD_DelayFactory.h"
 #include "AUD_LimiterFactory.h"
@@ -48,7 +49,6 @@
 #endif
 
 #ifdef WITH_FFMPEG
-#include "AUD_FFMPEGFactory.h"
 extern "C" {
 #include <libavformat/avformat.h>
 }
@@ -187,21 +187,13 @@ AUD_SoundInfo AUD_getInfo(AUD_Sound* sound)
 AUD_Sound* AUD_load(const char* filename)
 {
        assert(filename);
-#ifdef WITH_FFMPEG
-       return new AUD_FFMPEGFactory(filename);
-#else
-       return NULL;
-#endif
+       return new AUD_FileFactory(filename);
 }
 
 AUD_Sound* AUD_loadBuffer(unsigned char* buffer, int size)
 {
        assert(buffer);
-#ifdef WITH_FFMPEG
-       return new AUD_FFMPEGFactory(buffer, size);
-#else
-       return NULL;
-#endif
+       return new AUD_FileFactory(buffer, size);
 }
 
 AUD_Sound* AUD_bufferSound(AUD_Sound* sound)
diff --git a/intern/audaspace/intern/AUD_FileFactory.cpp b/intern/audaspace/intern/AUD_FileFactory.cpp
new file mode 100644 (file)
index 0000000..a1f81f4
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * $Id: AUD_FFMPEGFactory.cpp 22328 2009-08-09 23:23:19Z gsrb3d $
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#include "AUD_FileFactory.h"
+#include "AUD_Buffer.h"
+
+#include <cstring>
+
+#ifdef WITH_FFMPEG
+#include "AUD_FFMPEGReader.h"
+#endif
+#ifdef WITH_SNDFILE
+#include "AUD_SndFileReader.h"
+#endif
+
+AUD_FileFactory::AUD_FileFactory(const char* filename)
+{
+       if(filename != NULL)
+       {
+               m_filename = new char[strlen(filename)+1]; AUD_NEW("string")
+               strcpy(m_filename, filename);
+       }
+       else
+               m_filename = NULL;
+}
+
+AUD_FileFactory::AUD_FileFactory(unsigned char* buffer, int size)
+{
+       m_filename = NULL;
+       m_buffer = AUD_Reference<AUD_Buffer>(new AUD_Buffer(size));
+       memcpy(m_buffer.get()->getBuffer(), buffer, size);
+}
+
+AUD_FileFactory::~AUD_FileFactory()
+{
+       if(m_filename)
+       {
+               delete[] m_filename; AUD_DELETE("string")
+       }
+}
+
+AUD_IReader* AUD_FileFactory::createReader()
+{
+       AUD_IReader* reader = 0;
+
+#ifdef WITH_SNDFILE
+       try
+       {
+               if(m_filename)
+                       reader = new AUD_SndFileReader(m_filename);
+               else
+                       reader = new AUD_SndFileReader(m_buffer);
+               AUD_NEW("reader")
+               return reader;
+       }
+       catch(AUD_Exception e) {}
+#endif
+
+#ifdef WITH_FFMPEG
+       try
+       {
+               if(m_filename)
+                       reader = new AUD_FFMPEGReader(m_filename);
+               else
+                       reader = new AUD_FFMPEGReader(m_buffer);
+               AUD_NEW("reader")
+               return reader;
+       }
+       catch(AUD_Exception e) {}
+#endif
+
+       return reader;
+}
diff --git a/intern/audaspace/intern/AUD_FileFactory.h b/intern/audaspace/intern/AUD_FileFactory.h
new file mode 100644 (file)
index 0000000..8badb44
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * $Id: AUD_FFMPEGFactory.h 22328 2009-08-09 23:23:19Z gsrb3d $
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#ifndef AUD_FILEFACTORY
+#define AUD_FILEFACTORY
+
+#include "AUD_IFactory.h"
+#include "AUD_Reference.h"
+class AUD_Buffer;
+
+/**
+ * This factory tries to read a sound file via all available file readers.
+ */
+class AUD_FileFactory : public AUD_IFactory
+{
+private:
+       /**
+        * The filename of the sound source file.
+        */
+       char* m_filename;
+
+       /**
+        * The buffer to read from.
+        */
+       AUD_Reference<AUD_Buffer> m_buffer;
+
+public:
+       /**
+        * Creates a new factory.
+        * \param filename The sound file path.
+        */
+       AUD_FileFactory(const char* filename);
+
+       /**
+        * Creates a new factory.
+        * \param buffer The buffer to read from.
+        * \param size The size of the buffer.
+        */
+       AUD_FileFactory(unsigned char* buffer, int size);
+
+       /**
+        * Destroys the factory.
+        */
+       ~AUD_FileFactory();
+
+       virtual AUD_IReader* createReader();
+};
+
+#endif //AUD_FILEFACTORY
diff --git a/intern/audaspace/sndfile/AUD_SndFileFactory.cpp b/intern/audaspace/sndfile/AUD_SndFileFactory.cpp
new file mode 100644 (file)
index 0000000..d3c5ea8
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * $Id: AUD_FFMPEGFactory.cpp 22328 2009-08-09 23:23:19Z gsrb3d $
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#include "AUD_SndFileFactory.h"
+#include "AUD_SndFileReader.h"
+#include "AUD_Buffer.h"
+
+#include <cstring>
+
+AUD_SndFileFactory::AUD_SndFileFactory(const char* filename)
+{
+       if(filename != NULL)
+       {
+               m_filename = new char[strlen(filename)+1]; AUD_NEW("string")
+               strcpy(m_filename, filename);
+       }
+       else
+               m_filename = NULL;
+}
+
+AUD_SndFileFactory::AUD_SndFileFactory(unsigned char* buffer, int size)
+{
+       m_filename = NULL;
+       m_buffer = AUD_Reference<AUD_Buffer>(new AUD_Buffer(size));
+       memcpy(m_buffer.get()->getBuffer(), buffer, size);
+}
+
+AUD_SndFileFactory::~AUD_SndFileFactory()
+{
+       if(m_filename)
+       {
+               delete[] m_filename; AUD_DELETE("string")
+       }
+}
+
+AUD_IReader* AUD_SndFileFactory::createReader()
+{
+       AUD_IReader* reader;
+       if(m_filename)
+               reader = new AUD_SndFileReader(m_filename);
+       else
+               reader = new AUD_SndFileReader(m_buffer);
+       AUD_NEW("reader")
+       return reader;
+}
diff --git a/intern/audaspace/sndfile/AUD_SndFileFactory.h b/intern/audaspace/sndfile/AUD_SndFileFactory.h
new file mode 100644 (file)
index 0000000..6e265a6
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * $Id: AUD_FFMPEGFactory.h 22328 2009-08-09 23:23:19Z gsrb3d $
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#ifndef AUD_SNDFILEFACTORY
+#define AUD_SNDFILEFACTORY
+
+#include "AUD_IFactory.h"
+#include "AUD_Reference.h"
+class AUD_Buffer;
+
+/**
+ * This factory reads a sound file via libsndfile.
+ */
+class AUD_SndFileFactory : public AUD_IFactory
+{
+private:
+       /**
+        * The filename of the sound source file.
+        */
+       char* m_filename;
+
+       /**
+        * The buffer to read from.
+        */
+       AUD_Reference<AUD_Buffer> m_buffer;
+
+public:
+       /**
+        * Creates a new factory.
+        * \param filename The sound file path.
+        */
+       AUD_SndFileFactory(const char* filename);
+
+       /**
+        * Creates a new factory.
+        * \param buffer The buffer to read from.
+        * \param size The size of the buffer.
+        */
+       AUD_SndFileFactory(unsigned char* buffer, int size);
+
+       /**
+        * Destroys the factory.
+        */
+       ~AUD_SndFileFactory();
+
+       virtual AUD_IReader* createReader();
+};
+
+#endif //AUD_SNDFILEFACTORY
diff --git a/intern/audaspace/sndfile/AUD_SndFileReader.cpp b/intern/audaspace/sndfile/AUD_SndFileReader.cpp
new file mode 100644 (file)
index 0000000..8daef57
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * $Id: AUD_FFMPEGReader.cpp 22328 2009-08-09 23:23:19Z gsrb3d $
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#include "AUD_SndFileReader.h"
+#include "AUD_Buffer.h"
+
+#include <cstring>
+
+// This function transforms a  SampleFormat to our own sample format
+static inline AUD_SampleFormat SNDFILE_TO_AUD(int fmt)
+{
+       switch(fmt & SF_FORMAT_SUBMASK)
+       {
+       // only read s16, s32 and double as they are
+       case SF_FORMAT_PCM_16:
+               return AUD_FORMAT_S16;
+       case SF_FORMAT_PCM_32:
+               return AUD_FORMAT_S32;
+       case SF_FORMAT_DOUBLE:
+               return AUD_FORMAT_FLOAT64;
+       // read all other formats as floats
+       default:
+               return AUD_FORMAT_FLOAT32;
+       }
+}
+
+sf_count_t AUD_SndFileReader::vio_get_filelen(void *user_data)
+{
+       AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
+       return reader->m_membuffer.get()->getSize();
+}
+
+sf_count_t AUD_SndFileReader::vio_seek(sf_count_t offset, int whence, void *user_data)
+{
+       AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
+
+       switch(whence)
+       {
+       case SEEK_SET:
+               reader->m_memoffset = offset;
+               break;
+       case SEEK_CUR:
+               reader->m_memoffset = reader->m_memoffset + offset;
+               break;
+       case SEEK_END:
+               reader->m_memoffset = reader->m_membuffer.get()->getSize() + offset;
+               break;
+       }
+
+       return reader->m_memoffset;
+}
+
+sf_count_t AUD_SndFileReader::vio_read(void *ptr, sf_count_t count, void *user_data)
+{
+       AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
+
+       if(reader->m_memoffset + count > reader->m_membuffer.get()->getSize())
+               count = reader->m_membuffer.get()->getSize() - reader->m_memoffset;
+
+       memcpy(ptr, reader->m_membuffer.get()->getBuffer() + reader->m_memoffset, count);
+       reader->m_memoffset += count;
+
+       return count;
+}
+
+sf_count_t AUD_SndFileReader::vio_tell(void *user_data)
+{
+       AUD_SndFileReader* reader = (AUD_SndFileReader*)user_data;
+
+       return reader->m_memoffset;
+}
+
+AUD_SndFileReader::AUD_SndFileReader(const char* filename)
+{
+       SF_INFO sfinfo;
+
+       sfinfo.format = 0;
+       m_sndfile = sf_open(filename, SFM_READ, &sfinfo);
+
+       if(!m_sndfile)
+               AUD_THROW(AUD_ERROR_FILE);
+
+       m_specs.channels = (AUD_Channels) sfinfo.channels;
+       m_specs.format = SNDFILE_TO_AUD(sfinfo.format);
+       m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
+       m_length = sfinfo.frames;
+       m_seekable = sfinfo.seekable;
+       m_position = 0;
+
+       switch(m_specs.format)
+       {
+       case AUD_FORMAT_S16:
+               m_read = (sf_read_f) sf_readf_short;
+               break;
+       case AUD_FORMAT_S32:
+               m_read = (sf_read_f) sf_readf_int;
+               break;
+       case AUD_FORMAT_FLOAT64:
+               m_read = (sf_read_f) sf_readf_double;
+               break;
+       default:
+               m_read = (sf_read_f) sf_readf_float;
+       }
+
+       m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
+}
+
+AUD_SndFileReader::AUD_SndFileReader(AUD_Reference<AUD_Buffer> buffer)
+{
+       m_membuffer = buffer;
+       m_memoffset = 0;
+
+       m_vio.get_filelen = vio_get_filelen;
+       m_vio.read = vio_read;
+       m_vio.seek = vio_seek;
+       m_vio.tell = vio_tell;
+       m_vio.write = NULL;
+
+       SF_INFO sfinfo;
+
+       sfinfo.format = 0;
+       m_sndfile = sf_open_virtual(&m_vio, SFM_READ, &sfinfo, this);
+
+       if(!m_sndfile)
+               AUD_THROW(AUD_ERROR_FILE);
+
+       m_specs.channels = (AUD_Channels) sfinfo.channels;
+       m_specs.format = SNDFILE_TO_AUD(sfinfo.format);
+       m_specs.rate = (AUD_SampleRate) sfinfo.samplerate;
+       m_length = sfinfo.frames;
+       m_seekable = sfinfo.seekable;
+       m_position = 0;
+
+       switch(m_specs.format)
+       {
+       case AUD_FORMAT_S16:
+               m_read = (sf_read_f) sf_readf_short;
+               break;
+       case AUD_FORMAT_S32:
+               m_read = (sf_read_f) sf_readf_int;
+               break;
+       case AUD_FORMAT_FLOAT64:
+               m_read = (sf_read_f) sf_readf_double;
+               break;
+       default:
+               m_read = (sf_read_f) sf_readf_float;
+       }
+
+       m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
+}
+
+AUD_SndFileReader::~AUD_SndFileReader()
+{
+       sf_close(m_sndfile);
+
+       delete m_buffer; AUD_DELETE("buffer")
+}
+
+bool AUD_SndFileReader::isSeekable()
+{
+       return m_seekable;
+}
+
+void AUD_SndFileReader::seek(int position)
+{
+       if(m_seekable)
+       {
+               position = sf_seek(m_sndfile, position, SEEK_SET);
+               m_position = position;
+       }
+}
+
+int AUD_SndFileReader::getLength()
+{
+       return m_length;
+}
+
+int AUD_SndFileReader::getPosition()
+{
+       return m_position;
+}
+
+AUD_Specs AUD_SndFileReader::getSpecs()
+{
+       return m_specs;
+}
+
+AUD_ReaderType AUD_SndFileReader::getType()
+{
+       return AUD_TYPE_STREAM;
+}
+
+bool AUD_SndFileReader::notify(AUD_Message &message)
+{
+       return false;
+}
+
+void AUD_SndFileReader::read(int & length, sample_t* & buffer)
+{
+       int sample_size = AUD_SAMPLE_SIZE(m_specs);
+
+       // resize output buffer if necessary
+       if(m_buffer->getSize() < length*sample_size)
+               m_buffer->resize(length*sample_size);
+
+       buffer = m_buffer->getBuffer();
+
+       length = m_read(m_sndfile, buffer, length);
+
+       m_position += length;
+}
diff --git a/intern/audaspace/sndfile/AUD_SndFileReader.h b/intern/audaspace/sndfile/AUD_SndFileReader.h
new file mode 100644 (file)
index 0000000..f55c36b
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * $Id: AUD_FFMPEGReader.h 22328 2009-08-09 23:23:19Z gsrb3d $
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#ifndef AUD_SNDFILEREADER
+#define AUD_SNDFILEREADER
+
+#include "AUD_IReader.h"
+#include "AUD_Reference.h"
+class AUD_Buffer;
+
+#include <sndfile.h>
+
+typedef sf_count_t (*sf_read_f)(SNDFILE *sndfile, void *ptr, sf_count_t frames);
+
+/**
+ * This class reads a sound file via libsndfile.
+ */
+class AUD_SndFileReader : public AUD_IReader
+{
+private:
+       /**
+        * The current position in samples.
+        */
+       int m_position;
+
+       /**
+        * The sample count in the file.
+        */
+       int m_length;
+
+       /**
+        * Whether the file is seekable.
+        */
+       bool m_seekable;
+
+       /**
+        * The specification of the audio data.
+        */
+       AUD_Specs m_specs;
+
+       /**
+        * The playback buffer.
+        */
+       AUD_Buffer* m_buffer;
+
+       /**
+        * The sndfile.
+        */
+       SNDFILE* m_sndfile;
+
+       /**
+        * The reading function.
+        */
+       sf_read_f m_read;
+
+       /**
+        * The virtual IO structure for memory file reading.
+        */
+       SF_VIRTUAL_IO m_vio;
+
+       /**
+        * The pointer to the memory file.
+        */
+       AUD_Reference<AUD_Buffer> m_membuffer;
+
+       /**
+        * The current reading pointer of the memory file.
+        */
+       int m_memoffset;
+
+       // Functions for libsndfile virtual IO functionality
+       static sf_count_t vio_get_filelen(void *user_data);
+       static sf_count_t vio_seek(sf_count_t offset, int whence, void *user_data);
+       static sf_count_t vio_read(void *ptr, sf_count_t count, void *user_data);
+       static sf_count_t vio_tell(void *user_data);
+
+public:
+       /**
+        * Creates a new reader.
+        * \param filename The path to the file to be read.
+        * \exception AUD_Exception Thrown if the file specified does not exist or
+        *            cannot be read with libsndfile.
+        */
+       AUD_SndFileReader(const char* filename);
+
+       /**
+        * Creates a new reader.
+        * \param buffer The buffer to read from.
+        * \exception AUD_Exception Thrown if the buffer specified cannot be read
+        *                          with libsndfile.
+        */
+       AUD_SndFileReader(AUD_Reference<AUD_Buffer> buffer);
+
+       /**
+        * Destroys the reader and closes the file.
+        */
+       virtual ~AUD_SndFileReader();
+
+       virtual bool isSeekable();
+       virtual void seek(int position);
+       virtual int getLength();
+       virtual int getPosition();
+       virtual AUD_Specs getSpecs();
+       virtual AUD_ReaderType getType();
+       virtual bool notify(AUD_Message &message);
+       virtual void read(int & length, sample_t* & buffer);
+};
+
+#endif //AUD_SNDFILEREADER