3D Audio GSoC:

Mixdown functionality.

* Mixdown possible via libsndfile and ffmpeg!
* Fixed some ffmpeg deprecation warnings
* Mixdown UI only shows working Container, Codec and Format combinations!
* Minor bugs and warnings fixed
This commit is contained in:
Joerg Mueller
2011-08-06 17:57:20 +00:00
parent e73cf35f4a
commit c334bf69a7
20 changed files with 1241 additions and 43 deletions

View File

@@ -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()

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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);

View File

@@ -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];
}

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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

View File

@@ -40,6 +40,10 @@ AUD_NULLDevice::AUD_NULLDevice()
{
}
AUD_NULLDevice::~AUD_NULLDevice()
{
}
AUD_DeviceSpecs AUD_NULLDevice::getSpecs() const
{
AUD_DeviceSpecs specs;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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"

View File

@@ -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}")

View File

@@ -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);