Added jack audio support, building with cmake only currently, feel free to add scons...
authorJoerg Mueller <nexyon@gmail.com>
Sun, 16 Aug 2009 14:53:11 +0000 (14:53 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Sun, 16 Aug 2009 14:53:11 +0000 (14:53 +0000)
12 files changed:
CMake/macros.cmake
CMakeLists.txt
intern/audaspace/CMakeLists.txt
intern/audaspace/SDL/AUD_SDLDevice.cpp
intern/audaspace/SDL/AUD_SDLDevice.h
intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
intern/audaspace/intern/AUD_C-API.cpp
intern/audaspace/intern/AUD_C-API.h
intern/audaspace/intern/AUD_Space.h
intern/audaspace/jack/AUD_JackDevice.cpp [new file with mode: 0644]
intern/audaspace/jack/AUD_JackDevice.h [new file with mode: 0644]
source/blender/makesrna/intern/rna_userdef.c

index dfff2722b83fcc4f6a77e679700d54f42ca43fd3..e6c4664b68d38050da39f85fbed9385b1abc00b2 100644 (file)
@@ -54,6 +54,9 @@ MACRO(SETUP_LIBDIRS)
   IF(WITH_OPENAL)
     LINK_DIRECTORIES(${OPENAL_LIBPATH})
   ENDIF(WITH_OPENAL)
+  IF(WITH_JACK)
+    LINK_DIRECTORIES(${JACK_LIBPATH})
+  ENDIF(WITH_JACK)
   IF(WITH_FFTW3)
     LINK_DIRECTORIES(${FFTW3_LIBPATH})
   ENDIF(WITH_FFTW3)    
@@ -108,6 +111,9 @@ MACRO(SETUP_LIBLINKS
   IF(WITH_OPENAL)
     TARGET_LINK_LIBRARIES(${target} ${OPENAL_LIBRARY})
   ENDIF(WITH_OPENAL)
+  IF(WITH_JACK)
+    TARGET_LINK_LIBRARIES(${target} ${JACK_LIB})
+  ENDIF(WITH_JACK)
   IF(WITH_SDL)
     TARGET_LINK_LIBRARIES(${target} ${SDL_LIBRARY})
   ENDIF(WITH_SDL)
index 974067383d44f698fd92c65ec1b41869191c4434..029a65eb7390c07dd25d1eec00c3f16e60bf38be 100644 (file)
@@ -69,6 +69,7 @@ OPTION(WITH_OPENAL            "Enable OpenAL Support (http://www.openal.org)"         ON)
 OPTION(WITH_OPENMP             "Enable OpenMP (has to be supported by the compiler)"   OFF)
 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_INSTALL "Install accompanying scripts and language files needed to run blender" ON)
 
 IF(NOT WITH_GAMEENGINE AND WITH_PLAYER)
@@ -100,6 +101,13 @@ IF(UNIX AND NOT APPLE)
     ENDIF(OPENAL_FOUND)
   ENDIF(WITH_OPENAL)
 
+  IF(WITH_JACK)
+       SET(JACK /usr)
+       SET(JACK_INC ${JACK}/include/jack)
+       SET(JACK_LIB jack)
+       SET(JACK_LIBPATH ${JACK}/lib)
+  ENDIF(WITH_JACK)
+
   FIND_LIBRARY(INTL_LIBRARY
     NAMES intl
     PATHS
@@ -230,6 +238,13 @@ IF(WIN32)
     SET(OPENAL_LIBPATH ${OPENAL}/lib)
   ENDIF(CMAKE_CL_64)
 
+  IF(WITH_JACK)
+       SET(JACK ${LIBDIR}/jack)
+       SET(JACK_INC ${JACK}/include/jack)
+       SET(JACK_LIB jack)
+       SET(JACK_LIBPATH ${JACK}/lib)
+  ENDIF(WITH_JACK)
+
   IF(CMAKE_CL_64)
     SET(PNG_LIBRARIES libpng)
   ELSE(CMAKE_CL_64)
@@ -363,6 +378,12 @@ IF(APPLE)
     ENDIF(OPENAL_FOUND)
   ENDIF(WITH_OPENAL)
 
+  IF(WITH_JACK)
+       SET(JACK /usr)
+       SET(JACK_INC ${JACK}/include/jack)
+       SET(JACK_LIB jack)
+       SET(JACK_LIBPATH ${JACK}/lib)
+  ENDIF(WITH_JACK)
 
   SET(PYTHON_VERSION 3.1)
 
index 4939e1d38d9dd5e1318c65e40ce6e114a1f76631..940a4b2bedc33cb278deb8d8bafc90b47ad8dad2 100644 (file)
@@ -47,6 +47,12 @@ IF(WITH_OPENAL)
   ENDIF(FRAMEWORK)
 ENDIF(WITH_OPENAL)
 
-SET(SRC ${SRC} ${FFMPEGSRC} ${SDLSRC} ${OPENALSRC})
+IF(WITH_JACK)
+  SET(INC ${INC} jack ${JACK_INC})
+  FILE(GLOB JACKSRC jack/*.cpp)
+  ADD_DEFINITIONS(-DWITH_JACK)
+ENDIF(WITH_JACK)
+
+SET(SRC ${SRC} ${FFMPEGSRC} ${SDLSRC} ${OPENALSRC} ${JACKSRC})
 
 BLENDERLIB(bf_audaspace "${SRC}" "${INC}")
index 9ea5f1a74ee74b3ee89ff6280968228d92b8f78d..dd443e7f5c72559095b8b67515ddb27dff619e15 100644 (file)
 #include "AUD_SDLDevice.h"
 #include "AUD_IReader.h"
 
-#include <SDL.h>
-
-// this is the callback function for SDL, it only calls the class
-void mixAudio(void *data, Uint8* buffer, int length)
+void AUD_SDLDevice::SDL_mix(void *data, Uint8* buffer, int length)
 {
        AUD_SDLDevice* device = (AUD_SDLDevice*)data;
-       device->SDLmix((sample_t *)buffer, length);
+
+       device->mix((sample_t*)buffer, length/AUD_SAMPLE_SIZE(device->m_specs));
 }
 
 AUD_SDLDevice::AUD_SDLDevice(AUD_Specs specs, int buffersize)
@@ -56,7 +54,7 @@ AUD_SDLDevice::AUD_SDLDevice(AUD_Specs specs, int buffersize)
                format.format = AUDIO_S16SYS;
        format.channels = m_specs.channels;
        format.samples = buffersize;
-       format.callback = &mixAudio;
+       format.callback = AUD_SDLDevice::SDL_mix;
        format.userdata = this;
 
        if(SDL_OpenAudio(&format, &obtained) != 0)
@@ -86,11 +84,6 @@ AUD_SDLDevice::~AUD_SDLDevice()
        destroy();
 }
 
-void AUD_SDLDevice::SDLmix(sample_t* buffer, int length)
-{
-       mix(buffer, length/AUD_SAMPLE_SIZE(m_specs));
-}
-
 void AUD_SDLDevice::playing(bool playing)
 {
        SDL_PauseAudio(playing ? 0 : 1);
index 3eb93d287622d906acbb821dab1aa9957002e4cb..e2c6f7631b71caf6946699b93e1a6c0362efd819 100644 (file)
 
 #include "AUD_SoftwareDevice.h"
 
+#include <SDL.h>
+
 /**
  * This device plays back through SDL, the simple direct media layer.
  */
 class AUD_SDLDevice : public AUD_SoftwareDevice
 {
+private:
+       /**
+        * Mixes the next bytes into the buffer.
+        * \param data The SDL device.
+        * \param buffer The target buffer.
+        * \param length The length in bytes to be filled.
+        */
+       static void SDL_mix(void *data, Uint8* buffer, int length);
+
 protected:
        virtual void playing(bool playing);
 
@@ -50,14 +61,6 @@ public:
         * Closes the SDL audio device.
         */
        virtual ~AUD_SDLDevice();
-
-       /**
-        * Mixes the next bytes into the buffer.
-        * \param buffer The target buffer.
-        * \param length The length in bytes to be filled.
-        * \warning This function shall not be called from outside!
-        */
-       void SDLmix(sample_t* buffer, int length);
 };
 
 #endif //AUD_SDLDEVICE
index 28356e3b97d51b4de6be03c31e45f10f20787193..b79375c2dc56fed92846b456f6aeb689d7b5b0ba 100644 (file)
@@ -34,7 +34,7 @@ extern "C" {
 #include <libavformat/avformat.h>
 }
 
-// This function transforms a FFMPEG SampleFormat to or own sample format
+// This function transforms a FFMPEG SampleFormat to our own sample format
 static inline AUD_SampleFormat FFMPEG_TO_AUD(SampleFormat fmt)
 {
        switch(fmt)
index 92a499e84b82b9dc3ecf9be73f6a53be5e377289..d2c8e94c94912e5de77bfcdddac1c01a0884e9c1 100644 (file)
  * ***** END LGPL LICENSE BLOCK *****
  */
 
-/*#define WITH_SDL
-#define WITH_FFMPEG
-#define WITH_OPENAL*/
-
 #include "AUD_NULLDevice.h"
 #include "AUD_I3DDevice.h"
 #include "AUD_StreamBufferFactory.h"
 #include "AUD_OpenALDevice.h"
 #endif
 
+#ifdef WITH_JACK
+#include "AUD_JackDevice.h"
+#endif
+
 #ifdef WITH_FFMPEG
 #include "AUD_FFMPEGFactory.h"
 extern "C" {
@@ -97,6 +97,11 @@ int AUD_init(AUD_DeviceType device, AUD_Specs specs, int buffersize)
                case AUD_OPENAL_DEVICE:
                        dev = new AUD_OpenALDevice(specs, buffersize);
                        break;
+#endif
+#ifdef WITH_JACK
+               case AUD_JACK_DEVICE:
+                       dev = new AUD_JackDevice(specs);
+                       break;
 #endif
                default:
                        return false;
@@ -125,6 +130,9 @@ int* AUD_enumDevices()
 #endif
 #ifdef WITH_OPENAL
        AUD_available_devices[i++] = AUD_OPENAL_DEVICE;
+#endif
+#ifdef WITH_JACK
+       AUD_available_devices[i++] = AUD_JACK_DEVICE;
 #endif
        AUD_available_devices[i++] = AUD_NULL_DEVICE;
        return AUD_available_devices;
index b08f05db1ca579896e328040b9fd7f53cd245ba8..6ec5ec87ad5fb2bd88a65a21836b612921f5076f 100644 (file)
@@ -36,7 +36,8 @@ typedef enum
 {
        AUD_NULL_DEVICE = 0,
        AUD_SDL_DEVICE,
-       AUD_OPENAL_DEVICE
+       AUD_OPENAL_DEVICE,
+       AUD_JACK_DEVICE
 } AUD_DeviceType;
 
 typedef struct
index 9c6cc70c314b21f6e802cd35d095995df5b7dd41..123d9c272a085f2876e04ecb105883d9bbde2fce 100644 (file)
@@ -180,7 +180,8 @@ typedef enum
        AUD_ERROR_FILE,
        AUD_ERROR_FFMPEG,
        AUD_ERROR_SDL,
-       AUD_ERROR_OPENAL
+       AUD_ERROR_OPENAL,
+       AUD_ERROR_JACK
 } AUD_Error;
 
 /// Message codes.
diff --git a/intern/audaspace/jack/AUD_JackDevice.cpp b/intern/audaspace/jack/AUD_JackDevice.cpp
new file mode 100644 (file)
index 0000000..02095ca
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * $Id: AUD_SDLDevice.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_FloatMixer.h"
+#include "AUD_JackDevice.h"
+#include "AUD_IReader.h"
+#include "AUD_Buffer.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// AUD_XXX this is not realtime suitable!
+int AUD_JackDevice::jack_mix(jack_nframes_t length, void *data)
+{
+       AUD_JackDevice* device = (AUD_JackDevice*)data;
+       int samplesize = AUD_SAMPLE_SIZE(device->m_specs);
+       if(device->m_buffer->getSize() < samplesize * length)
+               device->m_buffer->resize(samplesize * length);
+       device->mix(device->m_buffer->getBuffer(), length);
+
+       float* in = (float*) device->m_buffer->getBuffer();
+       float* out;
+       int count = device->m_specs.channels;
+
+       for(int i = 0; i < count; i++)
+       {
+               out = (float*)jack_port_get_buffer(device->m_ports[i], length);
+               for(int j = 0; j < length; j++)
+                       out[j] = in[j * count + i];
+       }
+
+       return 0;
+}
+
+void AUD_JackDevice::jack_shutdown(void *data)
+{
+       AUD_JackDevice* device = (AUD_JackDevice*)data;
+       device->m_valid = false;
+}
+
+AUD_JackDevice::AUD_JackDevice(AUD_Specs specs)
+{
+       if(specs.channels == AUD_CHANNELS_INVALID)
+               specs.channels = AUD_CHANNELS_STEREO;
+
+       // jack uses floats
+       m_specs = specs;
+       m_specs.format = AUD_FORMAT_FLOAT32;
+
+       jack_options_t options = JackNullOption;
+       jack_status_t status;
+
+       // open client
+       m_client = jack_client_open("Blender", options, &status);
+       if(m_client == NULL)
+               AUD_THROW(AUD_ERROR_JACK);
+
+       m_buffer = new AUD_Buffer(); AUD_NEW("buffer");
+
+       // set callbacks
+       jack_set_process_callback(m_client, AUD_JackDevice::jack_mix, this);
+       jack_on_shutdown(m_client, AUD_JackDevice::jack_shutdown, this);
+
+       // register our output channels which are called ports in jack
+       m_ports = new jack_port_t*[m_specs.channels]; AUD_NEW("jack_port")
+
+       try
+       {
+               char portname[64];
+               for(int i = 0; i < m_specs.channels; i++)
+               {
+                       sprintf(portname, "out %d", i+1);
+                       m_ports[i] = jack_port_register(m_client, portname,
+                                                                                       JACK_DEFAULT_AUDIO_TYPE,
+                                                                                       JackPortIsOutput, 0);
+                       if(m_ports[i] == NULL)
+                               AUD_THROW(AUD_ERROR_JACK);
+               }
+
+               m_specs.rate = (AUD_SampleRate)jack_get_sample_rate(m_client);
+
+               // activate the client
+               if(jack_activate(m_client))
+                       AUD_THROW(AUD_ERROR_JACK);
+       }
+       catch(AUD_Exception e)
+       {
+               jack_client_close(m_client);
+               delete[] m_ports; AUD_DELETE("jack_port")
+               delete m_buffer; AUD_DELETE("buffer");
+               throw;
+       }
+
+       const char** ports = jack_get_ports(m_client, NULL, NULL,
+                                                                               JackPortIsPhysical | JackPortIsInput);
+       if(ports != NULL)
+       {
+               for(int i = 0; i < m_specs.channels && ports[i]; i++)
+                       jack_connect(m_client, jack_port_name(m_ports[i]), ports[i]);
+
+               free(ports);
+       }
+
+       m_mixer = new AUD_FloatMixer(); AUD_NEW("mixer")
+       m_mixer->setSpecs(m_specs);
+
+       m_valid = true;
+
+       create();
+}
+
+AUD_JackDevice::~AUD_JackDevice()
+{
+       lock();
+       if(m_valid)
+               jack_client_close(m_client);
+       delete[] m_ports; AUD_DELETE("jack_port")
+       delete m_buffer; AUD_DELETE("buffer");
+       unlock();
+
+       destroy();
+}
+
+void AUD_JackDevice::playing(bool playing)
+{
+       // Do nothing.
+}
diff --git a/intern/audaspace/jack/AUD_JackDevice.h b/intern/audaspace/jack/AUD_JackDevice.h
new file mode 100644 (file)
index 0000000..7b34099
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * $Id: AUD_SDLDevice.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_JACKDEVICE
+#define AUD_JACKDEVICE
+
+#include "AUD_SoftwareDevice.h"
+class AUD_Buffer;
+
+#include <jack.h>
+
+/**
+ * This device plays back through Jack.
+ */
+class AUD_JackDevice : public AUD_SoftwareDevice
+{
+private:
+       /**
+        * The output ports of jack.
+        */
+       jack_port_t** m_ports;
+
+       /**
+        * The jack client.
+        */
+       jack_client_t* m_client;
+
+       /**
+        * The output buffer.
+        */
+       AUD_Buffer* m_buffer;
+
+       /**
+        * Whether the device is valid.
+        */
+       bool m_valid;
+
+       /**
+        * Invalidates the jack device.
+        * \param data The jack device that gets invalidet by jack.
+        */
+       static void jack_shutdown(void *data);
+
+       /**
+        * Mixes the next bytes into the buffer.
+        * \param length The length in samples to be filled.
+        * \param data A pointer to the jack device.
+        * \return 0 what shows success.
+        */
+       static int jack_mix(jack_nframes_t length, void *data);
+
+protected:
+       virtual void playing(bool playing);
+
+public:
+       /**
+        * Creates a Jack client for audio output.
+        * \param specs The wanted audio specification, where only the channel count is important.
+        * \exception AUD_Exception Thrown if the audio device cannot be opened.
+        */
+       AUD_JackDevice(AUD_Specs specs);
+
+       /**
+        * Closes the Jack client.
+        */
+       virtual ~AUD_JackDevice();
+};
+
+#endif //AUD_JACKDEVICE
index 19b2b5376f7f55961ba5e4da6445fb42dc40c021..2179b10e47e1076312d8fd2189c08a69405b2a0f 100644 (file)
@@ -1992,6 +1992,7 @@ static void rna_def_userdef_system(BlenderRNA *brna)
                {0, "AUDIO_DEVICE_NULL", 0, "No Audio", "Null device - there will be no audio output."},
                {1, "AUDIO_DEVICE_SDL", 0, "SDL", "SDL device - simple direct media layer, recommended for sequencer usage."},
                {2, "AUDIO_DEVICE_OPENAL", 0, "OpenAL", "OpenAL device - supports 3D audio, recommended for game engine usage."},
+               {3, "AUDIO_DEVICE_JACK", 0, "Jack", "Jack device - open source pro audio, recommended for pro audio users."},
                {0, NULL, 0, NULL, NULL}};
 
        static EnumPropertyItem audio_rate_items[] = {