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:
@@ -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()
|
||||
|
||||
|
@@ -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);
|
||||
|
@@ -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.
|
||||
|
303
intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
Normal file
303
intern/audaspace/ffmpeg/AUD_FFMPEGWriter.cpp
Normal 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;
|
||||
}
|
||||
}
|
114
intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h
Normal file
114
intern/audaspace/ffmpeg/AUD_FFMPEGWriter.h
Normal 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
|
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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];
|
||||
}
|
||||
|
||||
|
97
intern/audaspace/intern/AUD_FileWriter.cpp
Normal file
97
intern/audaspace/intern/AUD_FileWriter.cpp
Normal 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);
|
||||
}
|
||||
}
|
58
intern/audaspace/intern/AUD_FileWriter.h
Normal file
58
intern/audaspace/intern/AUD_FileWriter.h
Normal 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
|
@@ -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;
|
||||
};
|
||||
|
69
intern/audaspace/intern/AUD_IWriter.h
Normal file
69
intern/audaspace/intern/AUD_IWriter.h
Normal 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
|
@@ -40,6 +40,10 @@ AUD_NULLDevice::AUD_NULLDevice()
|
||||
{
|
||||
}
|
||||
|
||||
AUD_NULLDevice::~AUD_NULLDevice()
|
||||
{
|
||||
}
|
||||
|
||||
AUD_DeviceSpecs AUD_NULLDevice::getSpecs() const
|
||||
{
|
||||
AUD_DeviceSpecs specs;
|
||||
|
@@ -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);
|
||||
|
@@ -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;
|
||||
|
||||
|
141
intern/audaspace/sndfile/AUD_SndFileWriter.cpp
Normal file
141
intern/audaspace/sndfile/AUD_SndFileWriter.cpp
Normal 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;
|
||||
}
|
87
intern/audaspace/sndfile/AUD_SndFileWriter.h
Normal file
87
intern/audaspace/sndfile/AUD_SndFileWriter.h
Normal 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
|
@@ -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"
|
||||
|
@@ -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}")
|
||||
|
@@ -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);
|
||||
|
Reference in New Issue
Block a user