diff options
-rw-r--r-- | CMake/macros.cmake | 6 | ||||
-rw-r--r-- | CMakeLists.txt | 21 | ||||
-rw-r--r-- | intern/audaspace/CMakeLists.txt | 8 | ||||
-rw-r--r-- | intern/audaspace/SDL/AUD_SDLDevice.cpp | 15 | ||||
-rw-r--r-- | intern/audaspace/SDL/AUD_SDLDevice.h | 19 | ||||
-rw-r--r-- | intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp | 2 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_C-API.cpp | 16 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_C-API.h | 3 | ||||
-rw-r--r-- | intern/audaspace/intern/AUD_Space.h | 3 | ||||
-rw-r--r-- | intern/audaspace/jack/AUD_JackDevice.cpp | 149 | ||||
-rw-r--r-- | intern/audaspace/jack/AUD_JackDevice.h | 91 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_userdef.c | 1 |
12 files changed, 307 insertions, 27 deletions
diff --git a/CMake/macros.cmake b/CMake/macros.cmake index dfff2722b83..e6c4664b68d 100644 --- a/CMake/macros.cmake +++ b/CMake/macros.cmake @@ -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) diff --git a/CMakeLists.txt b/CMakeLists.txt index 974067383d4..029a65eb739 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/intern/audaspace/CMakeLists.txt b/intern/audaspace/CMakeLists.txt index 4939e1d38d9..940a4b2bedc 100644 --- a/intern/audaspace/CMakeLists.txt +++ b/intern/audaspace/CMakeLists.txt @@ -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}") diff --git a/intern/audaspace/SDL/AUD_SDLDevice.cpp b/intern/audaspace/SDL/AUD_SDLDevice.cpp index 9ea5f1a74ee..dd443e7f5c7 100644 --- a/intern/audaspace/SDL/AUD_SDLDevice.cpp +++ b/intern/audaspace/SDL/AUD_SDLDevice.cpp @@ -27,13 +27,11 @@ #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); diff --git a/intern/audaspace/SDL/AUD_SDLDevice.h b/intern/audaspace/SDL/AUD_SDLDevice.h index 3eb93d28762..e2c6f7631b7 100644 --- a/intern/audaspace/SDL/AUD_SDLDevice.h +++ b/intern/audaspace/SDL/AUD_SDLDevice.h @@ -28,11 +28,22 @@ #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 diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp index 28356e3b97d..b79375c2dc5 100644 --- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp +++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp @@ -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) diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index 92a499e84b8..d2c8e94c949 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -23,10 +23,6 @@ * ***** 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" @@ -47,6 +43,10 @@ #include "AUD_OpenALDevice.h" #endif +#ifdef WITH_JACK +#include "AUD_JackDevice.h" +#endif + #ifdef WITH_FFMPEG #include "AUD_FFMPEGFactory.h" extern "C" { @@ -98,6 +98,11 @@ int AUD_init(AUD_DeviceType device, AUD_Specs specs, int buffersize) 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; } @@ -126,6 +131,9 @@ int* AUD_enumDevices() #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; } diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index b08f05db1ca..6ec5ec87ad5 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -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 diff --git a/intern/audaspace/intern/AUD_Space.h b/intern/audaspace/intern/AUD_Space.h index 9c6cc70c314..123d9c272a0 100644 --- a/intern/audaspace/intern/AUD_Space.h +++ b/intern/audaspace/intern/AUD_Space.h @@ -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 index 00000000000..02095caab74 --- /dev/null +++ b/intern/audaspace/jack/AUD_JackDevice.cpp @@ -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 index 00000000000..7b340992d52 --- /dev/null +++ b/intern/audaspace/jack/AUD_JackDevice.h @@ -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 diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 19b2b5376f7..2179b10e47e 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -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[] = { |