Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/audaspace/CMakeLists.txt7
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp31
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGReader.h4
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp303
-rw-r--r--intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h114
-rw-r--r--intern/audaspace/intern/AUD_C-API.cpp21
-rw-r--r--intern/audaspace/intern/AUD_C-API.h4
-rw-r--r--intern/audaspace/intern/AUD_ConverterFunctions.cpp6
-rw-r--r--intern/audaspace/intern/AUD_FileWriter.cpp97
-rw-r--r--intern/audaspace/intern/AUD_FileWriter.h58
-rw-r--r--intern/audaspace/intern/AUD_IReader.h15
-rw-r--r--intern/audaspace/intern/AUD_IWriter.h69
-rw-r--r--intern/audaspace/intern/AUD_NULLDevice.cpp4
-rw-r--r--intern/audaspace/intern/AUD_NULLDevice.h2
-rw-r--r--intern/audaspace/intern/AUD_Space.h24
-rw-r--r--intern/audaspace/sndfile/AUD_SndFileWriter.cpp141
-rw-r--r--intern/audaspace/sndfile/AUD_SndFileWriter.h87
-rw-r--r--release/scripts/startup/bl_ui/properties_scene.py2
-rw-r--r--source/blender/editors/sound/CMakeLists.txt8
-rw-r--r--source/blender/editors/sound/sound_ops.c287
20 files changed, 1241 insertions, 43 deletions
diff --git a/intern/audaspace/CMakeLists.txt b/intern/audaspace/CMakeLists.txt
index b08c5f62b29..8b7cb1d9e69 100644
--- a/intern/audaspace/CMakeLists.txt
+++ b/intern/audaspace/CMakeLists.txt
@@ -88,12 +88,15 @@ set(SRC
intern/AUD_ConverterReader.h
intern/AUD_FileFactory.cpp
intern/AUD_FileFactory.h
+ intern/AUD_FileWriter.cpp
+ intern/AUD_FileWriter.h
intern/AUD_I3DDevice.h
intern/AUD_I3DHandle.h
intern/AUD_IDevice.h
intern/AUD_IFactory.h
intern/AUD_IHandle.h
intern/AUD_IReader.h
+ intern/AUD_IWriter.h
intern/AUD_JOSResampleFactory.cpp
intern/AUD_JOSResampleFactory.h
intern/AUD_JOSResampleReader.cpp
@@ -184,9 +187,11 @@ if(WITH_CODEC_FFMPEG)
list(APPEND SRC
ffmpeg/AUD_FFMPEGFactory.cpp
ffmpeg/AUD_FFMPEGReader.cpp
+ ffmpeg/AUD_FFMPEGWriter.cpp
ffmpeg/AUD_FFMPEGFactory.h
ffmpeg/AUD_FFMPEGReader.h
+ ffmpeg/AUD_FFMPEGWriter.h
)
endif()
@@ -246,9 +251,11 @@ if(WITH_CODEC_SNDFILE)
list(APPEND SRC
sndfile/AUD_SndFileFactory.cpp
sndfile/AUD_SndFileReader.cpp
+ sndfile/AUD_SndFileWriter.cpp
sndfile/AUD_SndFileFactory.h
sndfile/AUD_SndFileReader.h
+ sndfile/AUD_SndFileWriter.h
)
endif()
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
index b7690d55383..a7534dbed32 100644
--- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.cpp
@@ -176,11 +176,11 @@ static const char* fileopen_error = "AUD_FFMPEGReader: File couldn't be "
AUD_FFMPEGReader::AUD_FFMPEGReader(std::string filename) :
m_pkgbuf(AVCODEC_MAX_AUDIO_FRAME_SIZE<<1),
- m_byteiocontext(NULL),
+ m_aviocontext(NULL),
m_membuf(NULL)
{
// open file
- if(av_open_input_file(&m_formatCtx, filename.c_str(), NULL, 0, NULL)!=0)
+ if(avformat_open_input(&m_formatCtx, filename.c_str(), NULL, NULL)!=0)
AUD_THROW(AUD_ERROR_FILE, fileopen_error);
try
@@ -204,25 +204,20 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer) :
{
m_membuf = reinterpret_cast<data_t*>(av_malloc(FF_MIN_BUFFER_SIZE + FF_INPUT_BUFFER_PADDING_SIZE));
- m_byteiocontext = av_alloc_put_byte(m_membuf, FF_MIN_BUFFER_SIZE, 0, this,
- read_packet, NULL, seek_packet);
+ m_aviocontext = avio_alloc_context(m_membuf, FF_MIN_BUFFER_SIZE, 0, this,
+ read_packet, NULL, seek_packet);
- if(!m_byteiocontext)
+ if(!m_aviocontext)
{
- av_free(m_byteiocontext);
+ av_free(m_aviocontext);
AUD_THROW(AUD_ERROR_FILE, fileopen_error);
}
- AVProbeData probe_data;
- probe_data.filename = "";
- probe_data.buf = reinterpret_cast<data_t*>(buffer.get()->getBuffer());
- probe_data.buf_size = buffer.get()->getSize();
- AVInputFormat* fmt = av_probe_input_format(&probe_data, 1);
-
- // open stream
- if(av_open_input_stream(&m_formatCtx, m_byteiocontext, "", fmt, NULL)!=0)
+ m_formatCtx = avformat_alloc_context();
+ m_formatCtx->pb = m_aviocontext;
+ if(avformat_open_input(&m_formatCtx, "", NULL, NULL)!=0)
{
- av_free(m_byteiocontext);
+ av_free(m_aviocontext);
AUD_THROW(AUD_ERROR_FILE, streamopen_error);
}
@@ -233,7 +228,7 @@ AUD_FFMPEGReader::AUD_FFMPEGReader(AUD_Reference<AUD_Buffer> buffer) :
catch(AUD_Exception&)
{
av_close_input_stream(m_formatCtx);
- av_free(m_byteiocontext);
+ av_free(m_aviocontext);
throw;
}
}
@@ -242,10 +237,10 @@ AUD_FFMPEGReader::~AUD_FFMPEGReader()
{
avcodec_close(m_codecCtx);
- if(m_byteiocontext)
+ if(m_aviocontext)
{
av_close_input_stream(m_formatCtx);
- av_free(m_byteiocontext);
+ av_free(m_aviocontext);
}
else
av_close_input_file(m_formatCtx);
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
index 06d6fe1e5f6..222a3d8581a 100644
--- a/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGReader.h
@@ -86,9 +86,9 @@ private:
AVCodecContext* m_codecCtx;
/**
- * The ByteIOContext to read the data from.
+ * The AVIOContext to read the data from.
*/
- ByteIOContext* m_byteiocontext;
+ AVIOContext* m_aviocontext;
/**
* The stream ID in the file.
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
new file mode 100644
index 00000000000..f2b7acc5ea2
--- /dev/null
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
@@ -0,0 +1,303 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
+ * \ingroup audffmpeg
+ */
+
+
+// needed for INT64_C
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+
+#include "AUD_FFMPEGWriter.h"
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+}
+
+static const char* context_error = "AUD_FFMPEGWriter: Couldn't allocate context.";
+static const char* codec_error = "AUD_FFMPEGWriter: Invalid codec or codec not found.";
+static const char* stream_error = "AUD_FFMPEGWriter: Couldn't allocate stream.";
+static const char* format_error = "AUD_FFMPEGWriter: Unsupported sample format.";
+static const char* file_error = "AUD_FFMPEGWriter: File couldn't be written.";
+static const char* write_error = "AUD_FFMPEGWriter: Error writing packet.";
+
+AUD_FFMPEGWriter::AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate) :
+ m_position(0),
+ m_specs(specs),
+ m_input_samples(0)
+{
+ static const char* formats[] = { NULL, "ac3", "flac", "matroska", "mp2", "mp3", "ogg", "wav" };
+
+ if(avformat_alloc_output_context2(&m_formatCtx, NULL, formats[format], filename.c_str()))
+ AUD_THROW(AUD_ERROR_FFMPEG, context_error);
+
+ m_outputFmt = m_formatCtx->oformat;
+
+ switch(codec)
+ {
+ case AUD_CODEC_AAC:
+ m_outputFmt->audio_codec = CODEC_ID_AAC;
+ break;
+ case AUD_CODEC_AC3:
+ m_outputFmt->audio_codec = CODEC_ID_AC3;
+ break;
+ case AUD_CODEC_FLAC:
+ m_outputFmt->audio_codec = CODEC_ID_FLAC;
+ break;
+ case AUD_CODEC_MP2:
+ m_outputFmt->audio_codec = CODEC_ID_MP2;
+ break;
+ case AUD_CODEC_MP3:
+ m_outputFmt->audio_codec = CODEC_ID_MP3;
+ break;
+ case AUD_CODEC_PCM:
+ switch(specs.format)
+ {
+ case AUD_FORMAT_U8:
+ m_outputFmt->audio_codec = CODEC_ID_PCM_U8;
+ break;
+ case AUD_FORMAT_S16:
+ m_outputFmt->audio_codec = CODEC_ID_PCM_S16LE;
+ break;
+ case AUD_FORMAT_S24:
+ m_outputFmt->audio_codec = CODEC_ID_PCM_S24LE;
+ break;
+ case AUD_FORMAT_S32:
+ m_outputFmt->audio_codec = CODEC_ID_PCM_S32LE;
+ break;
+ case AUD_FORMAT_FLOAT32:
+ m_outputFmt->audio_codec = CODEC_ID_PCM_F32LE;
+ break;
+ case AUD_FORMAT_FLOAT64:
+ m_outputFmt->audio_codec = CODEC_ID_PCM_F64LE;
+ break;
+ default:
+ m_outputFmt->audio_codec = CODEC_ID_NONE;
+ break;
+ }
+ break;
+ case AUD_CODEC_VORBIS:
+ m_outputFmt->audio_codec = CODEC_ID_VORBIS;
+ break;
+ default:
+ m_outputFmt->audio_codec = CODEC_ID_NONE;
+ break;
+ }
+
+ try
+ {
+ if(m_outputFmt->audio_codec == CODEC_ID_NONE)
+ AUD_THROW(AUD_ERROR_SPECS, codec_error);
+
+ m_stream = av_new_stream(m_formatCtx, 0);
+ if(!m_stream)
+ AUD_THROW(AUD_ERROR_FFMPEG, stream_error);
+
+ m_codecCtx = m_stream->codec;
+ m_codecCtx->codec_id = m_outputFmt->audio_codec;
+ m_codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;
+ m_codecCtx->bit_rate = bitrate;
+ m_codecCtx->sample_rate = int(m_specs.rate);
+ m_codecCtx->channels = m_specs.channels;
+ m_codecCtx->time_base = (AVRational){1, m_codecCtx->sample_rate};
+
+ switch(m_specs.format)
+ {
+ case AUD_FORMAT_U8:
+ m_convert = AUD_convert_float_u8;
+ m_codecCtx->sample_fmt = SAMPLE_FMT_U8;
+ break;
+ case AUD_FORMAT_S16:
+ m_convert = AUD_convert_float_s16;
+ m_codecCtx->sample_fmt = SAMPLE_FMT_S16;
+ break;
+ case AUD_FORMAT_S32:
+ m_convert = AUD_convert_float_s32;
+ m_codecCtx->sample_fmt = SAMPLE_FMT_S32;
+ break;
+ case AUD_FORMAT_FLOAT32:
+ m_convert = AUD_convert_copy<float>;
+ m_codecCtx->sample_fmt = SAMPLE_FMT_FLT;
+ break;
+ case AUD_FORMAT_FLOAT64:
+ m_convert = AUD_convert_float_double;
+ m_codecCtx->sample_fmt = SAMPLE_FMT_DBL;
+ break;
+ default:
+ AUD_THROW(AUD_ERROR_FFMPEG, format_error);
+ }
+
+ try
+ {
+ if(m_formatCtx->oformat->flags & AVFMT_GLOBALHEADER)
+ m_codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
+
+ AVCodec* codec = avcodec_find_encoder(m_codecCtx->codec_id);
+ if(!codec)
+ AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
+
+ if(avcodec_open(m_codecCtx, codec))
+ AUD_THROW(AUD_ERROR_FFMPEG, codec_error);
+
+ m_output_buffer.resize(FF_MIN_BUFFER_SIZE);
+ int samplesize = AUD_MAX(AUD_SAMPLE_SIZE(m_specs), AUD_DEVICE_SAMPLE_SIZE(m_specs));
+
+ if(m_codecCtx->frame_size <= 1)
+ m_input_size = 0;
+ else
+ {
+ m_input_buffer.resize(m_codecCtx->frame_size * samplesize);
+ m_input_size = m_codecCtx->frame_size;
+ }
+
+ try
+ {
+ if(avio_open(&m_formatCtx->pb, filename.c_str(), AVIO_WRONLY))
+ AUD_THROW(AUD_ERROR_FILE, file_error);
+
+ avformat_write_header(m_formatCtx, NULL);
+ }
+ catch(AUD_Exception&)
+ {
+ avcodec_close(m_codecCtx);
+ av_freep(&m_formatCtx->streams[0]->codec);
+ throw;
+ }
+ }
+ catch(AUD_Exception&)
+ {
+ av_freep(&m_formatCtx->streams[0]);
+ throw;
+ }
+ }
+ catch(AUD_Exception&)
+ {
+ av_free(m_formatCtx);
+ throw;
+ }
+}
+
+AUD_FFMPEGWriter::~AUD_FFMPEGWriter()
+{
+ // writte missing data
+ if(m_input_samples)
+ {
+ sample_t* buf = m_input_buffer.getBuffer();
+ memset(buf + m_specs.channels * m_input_samples, 0,
+ (m_input_size - m_input_samples) * AUD_DEVICE_SAMPLE_SIZE(m_specs));
+
+ encode(buf);
+ }
+
+ av_write_trailer(m_formatCtx);
+
+ avcodec_close(m_codecCtx);
+
+ av_freep(&m_formatCtx->streams[0]->codec);
+ av_freep(&m_formatCtx->streams[0]);
+
+ avio_close(m_formatCtx->pb);
+ av_free(m_formatCtx);
+}
+
+int AUD_FFMPEGWriter::getPosition() const
+{
+ return m_position;
+}
+
+AUD_DeviceSpecs AUD_FFMPEGWriter::getSpecs() const
+{
+ return m_specs;
+}
+
+void AUD_FFMPEGWriter::encode(sample_t* data)
+{
+ sample_t* outbuf = m_output_buffer.getBuffer();
+
+ // convert first
+ if(m_input_size)
+ m_convert(reinterpret_cast<data_t*>(data), reinterpret_cast<data_t*>(data), m_input_size * m_specs.channels);
+
+ AVPacket packet;
+ av_init_packet(&packet);
+ packet.size = avcodec_encode_audio(m_codecCtx, reinterpret_cast<uint8_t*>(outbuf), m_output_buffer.getSize(), reinterpret_cast<short*>(data));
+ if(m_codecCtx->coded_frame && m_codecCtx->coded_frame->pts != AV_NOPTS_VALUE)
+ packet.pts = av_rescale_q(m_codecCtx->coded_frame->pts, m_codecCtx->time_base, m_stream->time_base);
+ packet.flags |= AV_PKT_FLAG_KEY;
+ packet.stream_index = m_stream->index;
+ packet.data = reinterpret_cast<uint8_t*>(outbuf);
+
+ if(av_interleaved_write_frame(m_formatCtx, &packet))
+ AUD_THROW(AUD_ERROR_FFMPEG, write_error);
+}
+
+void AUD_FFMPEGWriter::write(unsigned int length, sample_t* buffer)
+{
+ unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs);
+
+ if(m_input_size)
+ {
+ sample_t* inbuf = m_input_buffer.getBuffer();
+
+ while(length)
+ {
+ unsigned int len = AUD_MIN(m_input_size - m_input_samples, length);
+
+ memcpy(inbuf + m_input_samples * m_specs.channels, buffer, len * samplesize);
+
+ buffer += len * m_specs.channels;
+ m_input_samples += len;
+ m_position += len;
+ length -= len;
+
+ if(m_input_samples == m_input_size)
+ {
+ encode(inbuf);
+
+ m_input_samples = 0;
+ }
+ }
+ }
+ else // PCM data, can write directly!
+ {
+ int samplesize = AUD_SAMPLE_SIZE(m_specs);
+ if(m_output_buffer.getSize() != length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8)
+ m_output_buffer.resize(length * m_specs.channels * m_codecCtx->bits_per_coded_sample / 8);
+ m_input_buffer.assureSize(length * AUD_MAX(AUD_DEVICE_SAMPLE_SIZE(m_specs), samplesize));
+
+ sample_t* buf = m_input_buffer.getBuffer();
+ m_convert(reinterpret_cast<data_t*>(buf), reinterpret_cast<data_t*>(buffer), length * m_specs.channels);
+
+ encode(buf);
+
+ m_position += length;
+ }
+}
diff --git a/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h
new file mode 100644
index 00000000000..618ec9402ce
--- /dev/null
+++ b/intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h
@@ -0,0 +1,114 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/ffmpeg/AUD_FFMPEGWriter.h
+ * \ingroup audffmpeg
+ */
+
+
+#ifndef AUD_FFMPEGWRITER
+#define AUD_FFMPEGWRITER
+
+#include "AUD_ConverterFunctions.h"
+#include "AUD_Buffer.h"
+#include "AUD_IWriter.h"
+
+#include <string>
+
+struct AVCodecContext;
+extern "C" {
+#include <libavformat/avformat.h>
+}
+
+/**
+ * This class writes a sound file via ffmpeg.
+ */
+class AUD_FFMPEGWriter : public AUD_IWriter
+{
+private:
+ /**
+ * The current position in samples.
+ */
+ int m_position;
+
+ /**
+ * The specification of the audio data.
+ */
+ AUD_DeviceSpecs m_specs;
+
+ /**
+ * The AVFormatContext structure for using ffmpeg.
+ */
+ AVFormatContext* m_formatCtx;
+
+ /**
+ * The AVCodecContext structure for using ffmpeg.
+ */
+ AVCodecContext* m_codecCtx;
+
+ AVOutputFormat* m_outputFmt;
+
+ AVStream* m_stream;
+
+ AUD_Buffer m_input_buffer;
+
+ AUD_Buffer m_output_buffer;
+
+ unsigned int m_input_samples;
+
+ unsigned int m_input_size;
+
+ /**
+ * Converter function.
+ */
+ AUD_convert_f m_convert;
+
+ // hide copy constructor and operator=
+ AUD_FFMPEGWriter(const AUD_FFMPEGWriter&);
+ AUD_FFMPEGWriter& operator=(const AUD_FFMPEGWriter&);
+
+ void encode(sample_t* data);
+
+public:
+ /**
+ * Creates a new writer.
+ * \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 ffmpeg.
+ */
+ AUD_FFMPEGWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate);
+
+ /**
+ * Destroys the writer and closes the file.
+ */
+ virtual ~AUD_FFMPEGWriter();
+
+ virtual int getPosition() const;
+ virtual AUD_DeviceSpecs getSpecs() const;
+ virtual void write(unsigned int length, sample_t* buffer);
+};
+
+#endif //AUD_FFMPEGWRITER
diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp
index 23245b56b20..467ee736b7f 100644
--- a/intern/audaspace/intern/AUD_C-API.cpp
+++ b/intern/audaspace/intern/AUD_C-API.cpp
@@ -48,6 +48,7 @@
#include "AUD_I3DDevice.h"
#include "AUD_I3DHandle.h"
#include "AUD_FileFactory.h"
+#include "AUD_FileWriter.h"
#include "AUD_StreamBufferFactory.h"
#include "AUD_DelayFactory.h"
#include "AUD_LimiterFactory.h"
@@ -1153,3 +1154,23 @@ void* AUD_getSet(void* set)
return NULL;
}
+
+const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate)
+{
+ try
+ {
+ AUD_SequencerFactory* f = dynamic_cast<AUD_SequencerFactory*>(sound->get());
+
+ f->setSpecs(specs.specs);
+ AUD_Reference<AUD_IReader> reader = f->createReader();
+ reader->seek(start);
+ AUD_Reference<AUD_IWriter> writer = AUD_FileWriter::createWriter(filename, specs, format, codec, bitrate);
+ AUD_FileWriter::writeReader(reader, writer, length, buffersize);
+
+ return NULL;
+ }
+ catch(AUD_Exception& e)
+ {
+ return e.str;
+ }
+}
diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h
index a6ef34280c2..abcbd215074 100644
--- a/intern/audaspace/intern/AUD_C-API.h
+++ b/intern/audaspace/intern/AUD_C-API.h
@@ -508,7 +508,7 @@ extern AUD_Sound* AUD_copy(AUD_Sound* sound);
extern void AUD_freeHandle(AUD_Handle* channel);
-extern void* AUD_createSet();
+extern void* AUD_createSet(void);
extern void AUD_destroySet(void* set);
@@ -518,6 +518,8 @@ extern void AUD_addSet(void* set, void* entry);
extern void* AUD_getSet(void* set);
+extern const char* AUD_mixdown(AUD_Sound* sound, unsigned int start, unsigned int length, unsigned int buffersize, const char* filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate);
+
#ifdef WITH_PYTHON
extern PyObject* AUD_getPythonFactory(AUD_Sound* sound);
diff --git a/intern/audaspace/intern/AUD_ConverterFunctions.cpp b/intern/audaspace/intern/AUD_ConverterFunctions.cpp
index c45fde72b1b..f7be2ca805f 100644
--- a/intern/audaspace/intern/AUD_ConverterFunctions.cpp
+++ b/intern/audaspace/intern/AUD_ConverterFunctions.cpp
@@ -35,10 +35,10 @@
#define AUD_U8_0 0x80
#define AUD_S16_MAX 0x7FFF
#define AUD_S16_MIN 0x8000
-#define AUD_S16_FLT 32768.0f
+#define AUD_S16_FLT 32767.0f
#define AUD_S32_MAX 0x7FFFFFFF
#define AUD_S32_MIN 0x80000000
-#define AUD_S32_FLT 2147483648.0f
+#define AUD_S32_FLT 2147483647.0f
#define AUD_FLT_MAX 1.0f
#define AUD_FLT_MIN -1.0f
@@ -379,7 +379,7 @@ void AUD_convert_float_double(data_t* target, data_t* source, int length)
{
float* s = (float*) source;
double* t = (double*) target;
- for(int i = length - 1; i >= 0; i++)
+ for(int i = length - 1; i >= 0; i--)
t[i] = s[i];
}
diff --git a/intern/audaspace/intern/AUD_FileWriter.cpp b/intern/audaspace/intern/AUD_FileWriter.cpp
new file mode 100644
index 00000000000..a5ef592ea17
--- /dev/null
+++ b/intern/audaspace/intern/AUD_FileWriter.cpp
@@ -0,0 +1,97 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_FileWriter.cpp
+ * \ingroup audaspaceintern
+ */
+
+#ifdef WITH_FFMPEG
+// needed for INT64_C
+#ifndef __STDC_CONSTANT_MACROS
+#define __STDC_CONSTANT_MACROS
+#endif
+#include "AUD_FFMPEGWriter.h"
+#endif
+
+#ifdef WITH_SNDFILE
+#include "AUD_SndFileWriter.h"
+#endif
+
+#include "AUD_FileWriter.h"
+#include "AUD_Buffer.h"
+
+static const char* write_error = "AUD_FileWriter: File couldn't be written.";
+
+AUD_Reference<AUD_IWriter> AUD_FileWriter::createWriter(std::string filename,AUD_DeviceSpecs specs,
+ AUD_Container format, AUD_Codec codec, unsigned int bitrate)
+{
+#ifdef WITH_SNDFILE
+ try
+ {
+ return new AUD_SndFileWriter(filename, specs, format, codec, bitrate);
+ }
+ catch(AUD_Exception&) {}
+#endif
+
+#ifdef WITH_FFMPEG
+ try
+ {
+ return new AUD_FFMPEGWriter(filename, specs, format, codec, bitrate);
+ }
+ catch(AUD_Exception&) {}
+#endif
+
+ AUD_THROW(AUD_ERROR_SPECS, write_error);
+}
+
+void AUD_FileWriter::writeReader(AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_IWriter> writer, unsigned int length, unsigned int buffersize)
+{
+ AUD_Buffer buffer(buffersize * AUD_SAMPLE_SIZE(writer->getSpecs()));
+ sample_t* buf = buffer.getBuffer();
+
+ int len;
+ bool eos = false;
+ int channels = writer->getSpecs().channels;
+
+ for(unsigned int pos = 0; ((pos < length) || (length <= 0)) && !eos; pos += len)
+ {
+ len = buffersize;
+ if((len > length - pos) && (length > 0))
+ len = length - pos;
+ reader->read(len, eos, buf);
+
+ for(int i = 0; i < len * channels; i++)
+ {
+ // clamping!
+ if(buf[i] > 1)
+ buf[i] = 1;
+ else if(buf[i] < -1)
+ buf[i] = -1;
+ }
+
+ writer->write(len, buf);
+ }
+}
diff --git a/intern/audaspace/intern/AUD_FileWriter.h b/intern/audaspace/intern/AUD_FileWriter.h
new file mode 100644
index 00000000000..60aec1b5927
--- /dev/null
+++ b/intern/audaspace/intern/AUD_FileWriter.h
@@ -0,0 +1,58 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_FileWriter.h
+ * \ingroup audaspaceintern
+ */
+
+
+#ifndef AUD_FILEWRITER
+#define AUD_FILEWRITER
+
+#include <string>
+
+#include "AUD_Reference.h"
+
+#include "AUD_IWriter.h"
+#include "AUD_IReader.h"
+
+/**
+ * This factory tries to read a sound file via all available file readers.
+ */
+class AUD_FileWriter
+{
+private:
+ // hide default constructor, copy constructor and operator=
+ AUD_FileWriter();
+ AUD_FileWriter(const AUD_FileWriter&);
+ AUD_FileWriter& operator=(const AUD_FileWriter&);
+
+public:
+ static AUD_Reference<AUD_IWriter> createWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate);
+ static void writeReader(AUD_Reference<AUD_IReader> reader, AUD_Reference<AUD_IWriter> writer, unsigned int length, unsigned int buffersize);
+};
+
+#endif //AUD_FILEWRITER
diff --git a/intern/audaspace/intern/AUD_IReader.h b/intern/audaspace/intern/AUD_IReader.h
index b1a282c9d49..5fc2cd62fb2 100644
--- a/intern/audaspace/intern/AUD_IReader.h
+++ b/intern/audaspace/intern/AUD_IReader.h
@@ -49,27 +49,22 @@ public:
/**
* Tells whether the source provides seeking functionality or not.
* \warning This doesn't mean that the seeking always has to succeed.
- * \return Always returns true for readers of the buffer type.
- * \see getType
+ * \return Always returns true for readers of buffering types.
*/
virtual bool isSeekable() const=0;
/**
* Seeks to a specific position in the source.
- * This function must work for buffer type readers.
* \param position The position to seek for measured in samples. To get
* from a given time to the samples you simply have to multiply the
* time value in seconds with the sample rate of the reader.
* \warning This may work or not, depending on the actual reader.
- * \see getType
*/
virtual void seek(int position)=0;
/**
* Returns an approximated length of the source in samples.
- * For readers of the type buffer this has to return a correct value!
* \return The length as sample count. May be negative if unknown.
- * \see getType
*/
virtual int getLength() const=0;
@@ -77,10 +72,8 @@ public:
* Returns the position of the source as a sample count value.
* \return The current position in the source. A negative value indicates
* that the position is unknown.
- * \warning The value returned doesn't always have to be correct for readers
- * of the stream type, especially after seeking, it must though for
- * the buffer ones.
- * \see getType
+ * \warning The value returned doesn't always have to be correct for readers,
+ * especially after seeking.
*/
virtual int getPosition() const=0;
@@ -98,7 +91,7 @@ public:
* there were only fewer samples available.
* A smaller value also indicates the end of the reader.
* \param[out] eos End of stream, whether the end is reached or not.
- * \param[int] buffer The pointer to the buffer to read into.
+ * \param[in] buffer The pointer to the buffer to read into.
*/
virtual void read(int& length, bool& eos, sample_t* buffer)=0;
};
diff --git a/intern/audaspace/intern/AUD_IWriter.h b/intern/audaspace/intern/AUD_IWriter.h
new file mode 100644
index 00000000000..944bce961c3
--- /dev/null
+++ b/intern/audaspace/intern/AUD_IWriter.h
@@ -0,0 +1,69 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/intern/AUD_IWriter.h
+ * \ingroup audaspaceintern
+ */
+
+
+#ifndef AUD_IWRITER
+#define AUD_IWRITER
+
+#include "AUD_Space.h"
+
+/**
+ * This class represents a sound sink where audio data can be written to.
+ */
+class AUD_IWriter
+{
+public:
+ /**
+ * Destroys the writer.
+ */
+ virtual ~AUD_IWriter(){}
+
+ /**
+ * Returns how many samples have been written so far.
+ * \return The writing position as sample count. May be negative if unknown.
+ */
+ virtual int getPosition() const=0;
+
+ /**
+ * Returns the specification of the audio data being written into the sink.
+ * \return The AUD_DeviceSpecs structure.
+ * \note Regardless of the format the input still has to be float!
+ */
+ virtual AUD_DeviceSpecs getSpecs() const=0;
+
+ /**
+ * Request to write the next length samples out into the sink.
+ * \param length The count of samples to write.
+ * \param buffer The pointer to the buffer containing the data.
+ */
+ virtual void write(unsigned int length, sample_t* buffer)=0;
+};
+
+#endif //AUD_IWRITER
diff --git a/intern/audaspace/intern/AUD_NULLDevice.cpp b/intern/audaspace/intern/AUD_NULLDevice.cpp
index c3a8c754cb2..78a02d32cdd 100644
--- a/intern/audaspace/intern/AUD_NULLDevice.cpp
+++ b/intern/audaspace/intern/AUD_NULLDevice.cpp
@@ -40,6 +40,10 @@ AUD_NULLDevice::AUD_NULLDevice()
{
}
+AUD_NULLDevice::~AUD_NULLDevice()
+{
+}
+
AUD_DeviceSpecs AUD_NULLDevice::getSpecs() const
{
AUD_DeviceSpecs specs;
diff --git a/intern/audaspace/intern/AUD_NULLDevice.h b/intern/audaspace/intern/AUD_NULLDevice.h
index 69ca5b74f3b..04458575f1c 100644
--- a/intern/audaspace/intern/AUD_NULLDevice.h
+++ b/intern/audaspace/intern/AUD_NULLDevice.h
@@ -46,6 +46,8 @@ public:
*/
AUD_NULLDevice();
+ virtual ~AUD_NULLDevice();
+
virtual AUD_DeviceSpecs getSpecs() const;
virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IReader> reader, bool keep = false);
virtual AUD_Reference<AUD_IHandle> play(AUD_Reference<AUD_IFactory> factory, bool keep = false);
diff --git a/intern/audaspace/intern/AUD_Space.h b/intern/audaspace/intern/AUD_Space.h
index 117c37b56ba..4d0a06e37b2 100644
--- a/intern/audaspace/intern/AUD_Space.h
+++ b/intern/audaspace/intern/AUD_Space.h
@@ -169,6 +169,30 @@ typedef enum
AUD_AP_ORIENTATION
} AUD_AnimateablePropertyType;
+typedef enum
+{
+ AUD_CONTAINER_INVALID = 0,
+ AUD_CONTAINER_AC3,
+ AUD_CONTAINER_FLAC,
+ AUD_CONTAINER_MATROSKA,
+ AUD_CONTAINER_MP2,
+ AUD_CONTAINER_MP3,
+ AUD_CONTAINER_OGG,
+ AUD_CONTAINER_WAV
+} AUD_Container;
+
+typedef enum
+{
+ AUD_CODEC_INVALID = 0,
+ AUD_CODEC_AAC,
+ AUD_CODEC_AC3,
+ AUD_CODEC_FLAC,
+ AUD_CODEC_MP2,
+ AUD_CODEC_MP3,
+ AUD_CODEC_PCM,
+ AUD_CODEC_VORBIS
+} AUD_Codec;
+
/// Sample type.(float samples)
typedef float sample_t;
diff --git a/intern/audaspace/sndfile/AUD_SndFileWriter.cpp b/intern/audaspace/sndfile/AUD_SndFileWriter.cpp
new file mode 100644
index 00000000000..ba59cd3d9d7
--- /dev/null
+++ b/intern/audaspace/sndfile/AUD_SndFileWriter.cpp
@@ -0,0 +1,141 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/sndfile/AUD_SndFileWriter.cpp
+ * \ingroup audsndfile
+ */
+
+
+#include "AUD_SndFileWriter.h"
+
+#include <cstring>
+
+static const char* fileopen_error = "AUD_SndFileWriter: File couldn't be written.";
+static const char* format_error = "AUD_SndFileWriter: Unsupported format.";
+
+AUD_SndFileWriter::AUD_SndFileWriter(std::string filename, AUD_DeviceSpecs specs,
+ AUD_Container format, AUD_Codec codec, unsigned int bitrate) :
+ m_specs(specs)
+{
+ SF_INFO sfinfo;
+
+ sfinfo.channels = specs.channels;
+ sfinfo.samplerate = int(specs.rate);
+
+ switch(format)
+ {
+ case AUD_CONTAINER_FLAC:
+ sfinfo.format = SF_FORMAT_FLAC;
+ switch(specs.format)
+ {
+ case AUD_FORMAT_S16:
+ sfinfo.format |= SF_FORMAT_PCM_16;
+ break;
+ case AUD_FORMAT_S24:
+ sfinfo.format |= SF_FORMAT_PCM_24;
+ break;
+ case AUD_FORMAT_S32:
+ sfinfo.format |= SF_FORMAT_PCM_32;
+ break;
+ case AUD_FORMAT_FLOAT32:
+ sfinfo.format |= SF_FORMAT_FLOAT;
+ break;
+ case AUD_FORMAT_FLOAT64:
+ sfinfo.format |= SF_FORMAT_DOUBLE;
+ break;
+ default:
+ sfinfo.format = 0;
+ break;
+ }
+ break;
+ case AUD_CONTAINER_OGG:
+ if(codec == AUD_CODEC_VORBIS)
+ sfinfo.format = SF_FORMAT_OGG | SF_FORMAT_VORBIS;
+ else
+ sfinfo.format = 0;
+ break;
+ case AUD_CONTAINER_WAV:
+ sfinfo.format = SF_FORMAT_WAV;
+ switch(specs.format)
+ {
+ case AUD_FORMAT_U8:
+ sfinfo.format |= SF_FORMAT_PCM_U8;
+ break;
+ case AUD_FORMAT_S16:
+ sfinfo.format |= SF_FORMAT_PCM_16;
+ break;
+ case AUD_FORMAT_S24:
+ sfinfo.format |= SF_FORMAT_PCM_24;
+ break;
+ case AUD_FORMAT_S32:
+ sfinfo.format |= SF_FORMAT_PCM_32;
+ break;
+ case AUD_FORMAT_FLOAT32:
+ sfinfo.format |= SF_FORMAT_FLOAT;
+ break;
+ case AUD_FORMAT_FLOAT64:
+ sfinfo.format |= SF_FORMAT_DOUBLE;
+ break;
+ default:
+ sfinfo.format = 0;
+ break;
+ }
+ break;
+ default:
+ sfinfo.format = 0;
+ break;
+ }
+
+ if(sfinfo.format == 0)
+ AUD_THROW(AUD_ERROR_SPECS, format_error);
+
+ m_sndfile = sf_open(filename.c_str(), SFM_WRITE, &sfinfo);
+
+ if(!m_sndfile)
+ AUD_THROW(AUD_ERROR_FILE, fileopen_error);
+}
+
+AUD_SndFileWriter::~AUD_SndFileWriter()
+{
+ sf_close(m_sndfile);
+}
+
+int AUD_SndFileWriter::getPosition() const
+{
+ return m_position;
+}
+
+AUD_DeviceSpecs AUD_SndFileWriter::getSpecs() const
+{
+ return m_specs;
+}
+
+void AUD_SndFileWriter::write(unsigned int length, sample_t* buffer)
+{
+ length = sf_writef_float(m_sndfile, buffer, length);
+
+ m_position += length;
+}
diff --git a/intern/audaspace/sndfile/AUD_SndFileWriter.h b/intern/audaspace/sndfile/AUD_SndFileWriter.h
new file mode 100644
index 00000000000..63f9e9e1371
--- /dev/null
+++ b/intern/audaspace/sndfile/AUD_SndFileWriter.h
@@ -0,0 +1,87 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * Copyright 2009-2011 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 General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Audaspace; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file audaspace/sndfile/AUD_SndFileWriter.h
+ * \ingroup audsndfile
+ */
+
+
+#ifndef AUD_SNDFILEWRITER
+#define AUD_SNDFILEWRITER
+
+#include "AUD_IWriter.h"
+//#include "AUD_Buffer.h"
+
+#include <string>
+#include <sndfile.h>
+
+typedef sf_count_t (*sf_read_f)(SNDFILE *sndfile, void *ptr, sf_count_t frames);
+
+/**
+ * This class writes a sound file via libsndfile.
+ */
+class AUD_SndFileWriter : public AUD_IWriter
+{
+private:
+ /**
+ * The current position in samples.
+ */
+ int m_position;
+
+ /**
+ * The specification of the audio data.
+ */
+ AUD_DeviceSpecs m_specs;
+
+ /**
+ * The sndfile.
+ */
+ SNDFILE* m_sndfile;
+
+ // hide copy constructor and operator=
+ AUD_SndFileWriter(const AUD_SndFileWriter&);
+ AUD_SndFileWriter& operator=(const AUD_SndFileWriter&);
+
+public:
+ /**
+ * Creates a new writer.
+ * \param filename The path to the file to be read.
+ * \exception AUD_Exception Thrown if the file specified cannot be written
+ * with libsndfile.
+ */
+ AUD_SndFileWriter(std::string filename, AUD_DeviceSpecs specs, AUD_Container format, AUD_Codec codec, unsigned int bitrate);
+
+ /**
+ * Destroys the writer and closes the file.
+ */
+ virtual ~AUD_SndFileWriter();
+
+ virtual int getPosition() const;
+ virtual AUD_DeviceSpecs getSpecs() const;
+ virtual void write(unsigned int length, sample_t* buffer);
+};
+
+#endif //AUD_SNDFILEWRITER
diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py
index a9310fcc532..c3784b9f692 100644
--- a/release/scripts/startup/bl_ui/properties_scene.py
+++ b/release/scripts/startup/bl_ui/properties_scene.py
@@ -70,6 +70,8 @@ class SCENE_PT_audio(SceneButtonsPanel, bpy.types.Panel):
col.prop(rd, "ffmpeg_audio_channels", text="")
col.prop(rd, "ffmpeg_audio_mixrate", text="Rate")
+ layout.operator("sound.mixdown")
+
class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel):
bl_label = "Units"
diff --git a/source/blender/editors/sound/CMakeLists.txt b/source/blender/editors/sound/CMakeLists.txt
index f66288812ad..11da4165ec8 100644
--- a/source/blender/editors/sound/CMakeLists.txt
+++ b/source/blender/editors/sound/CMakeLists.txt
@@ -47,4 +47,12 @@ if(WITH_AUDASPACE)
add_definitions(-DWITH_AUDASPACE)
endif()
+if(WITH_CODEC_FFMPEG)
+ add_definitions(-DWITH_FFMPEG)
+endif()
+
+if(WITH_CODEC_SNDFILE)
+ add_definitions(-DWITH_SNDFILE)
+endif()
+
blender_add_lib(bf_editor_sound "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 8744ec5dfd6..c6a3663d512 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -82,7 +82,7 @@
static void open_init(bContext *C, wmOperator *op)
{
PropertyPointerRNA *pprop;
-
+
op->customdata= pprop= MEM_callocN(sizeof(PropertyPointerRNA), "OpenPropertyPointerRNA");
uiIDContextProperty(C, &pprop->ptr, &pprop->prop);
}
@@ -101,7 +101,7 @@ static int open_exec(bContext *C, wmOperator *op)
if(!op->customdata)
open_init(C, op);
-
+
if (sound==NULL || sound->playback_handle == NULL) {
if(op->customdata) MEM_freeN(op->customdata);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
@@ -120,15 +120,15 @@ static int open_exec(bContext *C, wmOperator *op)
if (RNA_boolean_get(op->ptr, "cache")) {
sound_cache(sound, 0);
}
-
+
/* hook into UI */
pprop= op->customdata;
-
+
if(pprop->prop) {
/* when creating new ID blocks, use is already 1, but RNA
* pointer se also increases user, so this compensates it */
sound->id.us--;
-
+
RNA_id_pointer_create(&sound->id, &idptr);
RNA_property_pointer_set(&pprop->ptr, pprop->prop, idptr);
RNA_property_update(C, &pprop->ptr, pprop->prop);
@@ -153,12 +153,12 @@ static int open_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
if(!RNA_property_is_set(op->ptr, "relative_path"))
RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
-
+
if(RNA_property_is_set(op->ptr, "filepath"))
return open_exec(C, op);
-
+
open_init(C, op);
-
+
return WM_operator_filesel(C, op, event);
}
@@ -181,6 +181,276 @@ void SOUND_OT_open(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "cache", FALSE, "Cache", "Cache the sound in memory.");
}
+/******************** mixdown operator ********************/
+
+static int mixdown_exec(bContext *C, wmOperator *op)
+{
+ char path[FILE_MAX];
+ char filename[FILE_MAX];
+ Scene *scene;
+ Main *bmain;
+
+ int bitrate, accuracy;
+ AUD_DeviceSpecs specs;
+ AUD_Container container;
+ AUD_Codec codec;
+ const char* result;
+
+ RNA_string_get(op->ptr, "filepath", path);
+ bitrate = RNA_int_get(op->ptr, "bitrate") * 1000;
+ accuracy = RNA_int_get(op->ptr, "accuracy");
+ specs.format = RNA_enum_get(op->ptr, "format");
+ container = RNA_enum_get(op->ptr, "container");
+ codec = RNA_enum_get(op->ptr, "codec");
+ scene = CTX_data_scene(C);
+ bmain = CTX_data_main(C);
+ specs.channels = scene->r.ffcodecdata.audio_channels;
+ specs.rate = scene->r.ffcodecdata.audio_mixrate;
+
+ BLI_strncpy(filename, path, sizeof(filename));
+ BLI_path_abs(filename, bmain->name);
+
+ result = AUD_mixdown(scene->sound_scene, SFRA * specs.rate / FPS, (EFRA - SFRA) * specs.rate / FPS,
+ accuracy, filename, specs, container, codec, bitrate);
+
+ if(result)
+ {
+ BKE_report(op->reports, RPT_ERROR, result);
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static int mixdown_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+ if(!RNA_property_is_set(op->ptr, "relative_path"))
+ RNA_boolean_set(op->ptr, "relative_path", U.flag & USER_RELPATHS);
+
+ if(RNA_property_is_set(op->ptr, "filepath"))
+ return mixdown_exec(C, op);
+
+ return WM_operator_filesel(C, op, event);
+}
+
+static int mixdown_draw_check_prop(PropertyRNA *prop)
+{
+ const char *prop_id= RNA_property_identifier(prop);
+ return !( strcmp(prop_id, "filepath") == 0 ||
+ strcmp(prop_id, "directory") == 0 ||
+ strcmp(prop_id, "filename") == 0
+ );
+}
+
+static void mixdown_draw(bContext *C, wmOperator *op)
+{
+ static EnumPropertyItem pcm_format_items[] = {
+ {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"},
+ {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
+#ifdef WITH_SNDFILE
+ {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"},
+#endif
+ {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"},
+ {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"},
+ {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem mp3_format_items[] = {
+ {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
+ {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem ac3_format_items[] = {
+ {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
+ {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"},
+ {0, NULL, 0, NULL, NULL}};
+
+#ifdef WITH_SNDFILE
+ static EnumPropertyItem flac_format_items[] = {
+ {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
+ {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"},
+ {0, NULL, 0, NULL, NULL}};
+#endif
+
+ static EnumPropertyItem all_codec_items[] = {
+ {AUD_CODEC_AAC, "AAC", 0, "AAC", "Advanced Audio Coding"},
+ {AUD_CODEC_AC3, "AC3", 0, "AC3", "Dolby Digital ATRAC 3"},
+ {AUD_CODEC_FLAC, "FLAC", 0, "FLAC", "Free Lossless Audio Codec"},
+ {AUD_CODEC_MP2, "MP2", 0, "MP2", "MPEG-1 Audio Layer II"},
+ {AUD_CODEC_MP3, "MP3", 0, "MP3", "MPEG-2 Audio Layer III"},
+ {AUD_CODEC_PCM, "PCM", 0, "PCM", "Pulse Code Modulation (RAW)"},
+ {AUD_CODEC_VORBIS, "VORBIS", 0, "Vorbis", "Xiph.Org Vorbis Codec"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem ogg_codec_items[] = {
+ {AUD_CODEC_FLAC, "FLAC", 0, "FLAC", "Free Lossless Audio Codec"},
+ {AUD_CODEC_VORBIS, "VORBIS", 0, "Vorbis", "Xiph.Org Vorbis Codec"},
+ {0, NULL, 0, NULL, NULL}};
+
+ uiLayout *layout = op->layout;
+ wmWindowManager *wm= CTX_wm_manager(C);
+ PointerRNA ptr;
+ PropertyRNA *prop_format;
+ PropertyRNA *prop_codec;
+ PropertyRNA *prop_bitrate;
+
+ AUD_Container container = RNA_enum_get(op->ptr, "container");
+ AUD_Codec codec = RNA_enum_get(op->ptr, "codec");
+
+ prop_format = RNA_struct_find_property(op->ptr, "format");
+ prop_codec = RNA_struct_find_property(op->ptr, "codec");
+ prop_bitrate = RNA_struct_find_property(op->ptr, "bitrate");
+
+ RNA_def_property_clear_flag(prop_bitrate, PROP_HIDDEN);
+ RNA_def_property_flag(prop_codec, PROP_HIDDEN);
+ RNA_def_property_flag(prop_format, PROP_HIDDEN);
+
+ switch(container)
+ {
+ case AUD_CONTAINER_AC3:
+ RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_format, ac3_format_items);
+ RNA_def_property_enum_items(prop_codec, all_codec_items);
+ RNA_enum_set(op->ptr, "codec", AUD_CODEC_AC3);
+ break;
+ case AUD_CONTAINER_FLAC:
+ RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_codec, all_codec_items);
+ RNA_enum_set(op->ptr, "codec", AUD_CODEC_FLAC);
+#ifdef WITH_SNDFILE
+ RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_format, flac_format_items);
+#else
+ RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
+#endif
+ break;
+ case AUD_CONTAINER_MATROSKA:
+ RNA_def_property_clear_flag(prop_codec, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_codec, all_codec_items);
+
+ switch(codec)
+ {
+ case AUD_CODEC_AAC:
+ RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
+ break;
+ case AUD_CODEC_AC3:
+ RNA_def_property_enum_items(prop_format, ac3_format_items);
+ RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
+ break;
+ case AUD_CODEC_FLAC:
+ RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
+ RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
+ break;
+ case AUD_CODEC_MP2:
+ RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
+ break;
+ case AUD_CODEC_MP3:
+ RNA_def_property_enum_items(prop_format, mp3_format_items);
+ RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
+ break;
+ case AUD_CODEC_PCM:
+ RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_format, pcm_format_items);
+ RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
+ break;
+ case AUD_CODEC_VORBIS:
+ RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
+ break;
+ }
+
+ break;
+ case AUD_CONTAINER_MP2:
+ RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
+ RNA_enum_set(op->ptr, "codec", AUD_CODEC_MP2);
+ RNA_def_property_enum_items(prop_codec, all_codec_items);
+ break;
+ case AUD_CONTAINER_MP3:
+ RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_format, mp3_format_items);
+ RNA_def_property_enum_items(prop_codec, all_codec_items);
+ RNA_enum_set(op->ptr, "codec", AUD_CODEC_MP3);
+ break;
+ case AUD_CONTAINER_OGG:
+ RNA_def_property_clear_flag(prop_codec, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_codec, ogg_codec_items);
+ RNA_enum_set(op->ptr, "format", AUD_FORMAT_S16);
+ break;
+ case AUD_CONTAINER_WAV:
+ RNA_def_property_flag(prop_bitrate, PROP_HIDDEN);
+ RNA_def_property_clear_flag(prop_format, PROP_HIDDEN);
+ RNA_def_property_enum_items(prop_format, pcm_format_items);
+ RNA_def_property_enum_items(prop_codec, all_codec_items);
+ RNA_enum_set(op->ptr, "codec", AUD_CODEC_PCM);
+ break;
+ }
+
+ RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
+
+ /* main draw call */
+ uiDefAutoButsRNA(layout, &ptr, mixdown_draw_check_prop, '\0');
+}
+
+void SOUND_OT_mixdown(wmOperatorType *ot)
+{
+ static EnumPropertyItem format_items[] = {
+ {AUD_FORMAT_U8, "U8", 0, "U8", "8 bit unsigned"},
+ {AUD_FORMAT_S16, "S16", 0, "S16", "16 bit signed"},
+ {AUD_FORMAT_S24, "S24", 0, "S24", "24 bit signed"},
+ {AUD_FORMAT_S32, "S32", 0, "S32", "32 bit signed"},
+ {AUD_FORMAT_FLOAT32, "F32", 0, "F32", "32 bit floating point"},
+ {AUD_FORMAT_FLOAT64, "F64", 0, "F64", "64 bit floating point"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem container_items[] = {
+#ifdef WITH_FFMPEG
+ {AUD_CONTAINER_AC3, "AC3", 0, "ac3", "Dolby Digital ATRAC 3"},
+#endif
+ {AUD_CONTAINER_FLAC, "FLAC", 0, "flac", "Free Lossless Audio Codec"},
+#ifdef WITH_FFMPEG
+ {AUD_CONTAINER_MATROSKA, "MATROSKA", 0, "mkv", "Matroska"},
+ {AUD_CONTAINER_MP2, "MP2", 0, "mp2", "MPEG-1 Audio Layer II"},
+ {AUD_CONTAINER_MP3, "MP3", 0, "mp3", "MPEG-2 Audio Layer III"},
+#endif
+ {AUD_CONTAINER_OGG, "OGG", 0, "ogg", "Xiph.Org Ogg Container"},
+ {AUD_CONTAINER_WAV, "WAV", 0, "wav", "Waveform Audio File Format"},
+ {0, NULL, 0, NULL, NULL}};
+
+ static EnumPropertyItem codec_items[] = {
+#ifdef WITH_FFMPEG
+ {AUD_CODEC_AAC, "AAC", 0, "AAC", "Advanced Audio Coding"},
+ {AUD_CODEC_AC3, "AC3", 0, "AC3", "Dolby Digital ATRAC 3"},
+#endif
+ {AUD_CODEC_FLAC, "FLAC", 0, "FLAC", "Free Lossless Audio Codec"},
+#ifdef WITH_FFMPEG
+ {AUD_CODEC_MP2, "MP2", 0, "MP2", "MPEG-1 Audio Layer II"},
+ {AUD_CODEC_MP3, "MP3", 0, "MP3", "MPEG-2 Audio Layer III"},
+#endif
+ {AUD_CODEC_PCM, "PCM", 0, "PCM", "Pulse Code Modulation (RAW)"},
+ {AUD_CODEC_VORBIS, "VORBIS", 0, "Vorbis", "Xiph.Org Vorbis Codec"},
+ {0, NULL, 0, NULL, NULL}};
+
+ /* identifiers */
+ ot->name= "Mixdown";
+ ot->description= "Mixes the scene's audio to a sound file";
+ ot->idname= "SOUND_OT_mixdown";
+
+ /* api callbacks */
+ ot->exec= mixdown_exec;
+ ot->invoke= mixdown_invoke;
+ ot->ui= mixdown_draw;
+
+ /* flags */
+ ot->flag= OPTYPE_REGISTER;
+
+ /* properties */
+ WM_operator_properties_filesel(ot, FOLDERFILE|SOUNDFILE, FILE_SPECIAL, FILE_SAVE, WM_FILESEL_FILEPATH);
+ RNA_def_int(ot->srna, "accuracy", 1024, 1, 16777216, "Accuracy", "Sample accuracy. Important for animation data. The lower the value, the more accurate.", 1, 16777216);
+ RNA_def_enum(ot->srna, "container", container_items, AUD_CONTAINER_FLAC, "Container", "File format");
+ RNA_def_enum(ot->srna, "codec", codec_items, AUD_CODEC_FLAC, "Codec", "Audio Codec");
+ RNA_def_enum(ot->srna, "format", format_items, AUD_FORMAT_S16, "Format", "Sample format");
+ RNA_def_int(ot->srna, "bitrate", 192, 32, 512, "Bitrate", "Bitrate in kbit/s", 32, 512);
+}
+
/* ******************************************************* */
static int sound_poll(bContext *C)
@@ -393,6 +663,7 @@ void SOUND_OT_bake_animation(wmOperatorType *ot)
void ED_operatortypes_sound(void)
{
WM_operatortype_append(SOUND_OT_open);
+ WM_operatortype_append(SOUND_OT_mixdown);
WM_operatortype_append(SOUND_OT_pack);
WM_operatortype_append(SOUND_OT_unpack);
WM_operatortype_append(SOUND_OT_update_animation_flags);