2.5 Audio:
- Python script to crossfade two sound strips in the sequencer - Fix for the libsamplerate code producing awful audio when resampling sequencer strips - Changed default resampler to a linear one (as temporary workaround for a bug that seems to be in the samplerate code) - Fix for the OpenAL device to return a more accurate playback position
This commit is contained in:
@@ -890,11 +890,14 @@ float AUD_OpenALDevice::getPosition(AUD_Handle* handle)
|
|||||||
if(isValid(handle))
|
if(isValid(handle))
|
||||||
{
|
{
|
||||||
AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
|
AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
|
||||||
if(h->isBuffered)
|
alGetSourcef(h->source, AL_SEC_OFFSET, &position);
|
||||||
alGetSourcef(h->source, AL_SEC_OFFSET, &position);
|
if(!h->isBuffered)
|
||||||
else
|
{
|
||||||
position = h->reader->getPosition() /
|
AUD_Specs specs = h->reader->getSpecs();
|
||||||
(float)h->reader->getSpecs().rate;
|
position += (h->reader->getPosition() - m_buffersize *
|
||||||
|
AUD_OPENAL_CYCLE_BUFFERS / specs.channels) /
|
||||||
|
(float)specs.rate;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock();
|
unlock();
|
||||||
|
@@ -44,6 +44,7 @@ AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_IReader* reader,
|
|||||||
m_tspecs = specs;
|
m_tspecs = specs;
|
||||||
m_tspecs.channels = m_sspecs.channels;
|
m_tspecs.channels = m_sspecs.channels;
|
||||||
m_factor = (double)m_tspecs.rate / (double)m_sspecs.rate;
|
m_factor = (double)m_tspecs.rate / (double)m_sspecs.rate;
|
||||||
|
m_position = 0;
|
||||||
|
|
||||||
int error;
|
int error;
|
||||||
m_src = src_callback_new(src_callback,
|
m_src = src_callback_new(src_callback,
|
||||||
@@ -71,7 +72,7 @@ AUD_SRCResampleReader::~AUD_SRCResampleReader()
|
|||||||
|
|
||||||
long AUD_SRCResampleReader::doCallback(float** data)
|
long AUD_SRCResampleReader::doCallback(float** data)
|
||||||
{
|
{
|
||||||
int length = m_buffer->getSize() / 4 / m_tspecs.channels;
|
int length = m_buffer->getSize() / AUD_SAMPLE_SIZE(m_tspecs);
|
||||||
sample_t* buffer;
|
sample_t* buffer;
|
||||||
|
|
||||||
m_reader->read(length, buffer);
|
m_reader->read(length, buffer);
|
||||||
@@ -84,6 +85,7 @@ void AUD_SRCResampleReader::seek(int position)
|
|||||||
{
|
{
|
||||||
m_reader->seek(position / m_factor);
|
m_reader->seek(position / m_factor);
|
||||||
src_reset(m_src);
|
src_reset(m_src);
|
||||||
|
m_position = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AUD_SRCResampleReader::getLength()
|
int AUD_SRCResampleReader::getLength()
|
||||||
@@ -93,7 +95,7 @@ int AUD_SRCResampleReader::getLength()
|
|||||||
|
|
||||||
int AUD_SRCResampleReader::getPosition()
|
int AUD_SRCResampleReader::getPosition()
|
||||||
{
|
{
|
||||||
return m_reader->getPosition() * m_factor;
|
return m_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
AUD_Specs AUD_SRCResampleReader::getSpecs()
|
AUD_Specs AUD_SRCResampleReader::getSpecs()
|
||||||
@@ -111,4 +113,6 @@ void AUD_SRCResampleReader::read(int & length, sample_t* & buffer)
|
|||||||
buffer = m_buffer->getBuffer();
|
buffer = m_buffer->getBuffer();
|
||||||
|
|
||||||
length = src_callback_read(m_src, m_factor, length, buffer);
|
length = src_callback_read(m_src, m_factor, length, buffer);
|
||||||
|
|
||||||
|
m_position += length;
|
||||||
}
|
}
|
||||||
|
@@ -62,6 +62,11 @@ private:
|
|||||||
*/
|
*/
|
||||||
SRC_STATE* m_src;
|
SRC_STATE* m_src;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current playback position;
|
||||||
|
*/
|
||||||
|
int m_position;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Creates a resampling reader.
|
* Creates a resampling reader.
|
||||||
|
@@ -762,3 +762,16 @@ int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length)
|
|||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AUD_DEBUG_MEMORY
|
||||||
|
int AUD_References(int count, const char* text)
|
||||||
|
{
|
||||||
|
static int m_count = 0;
|
||||||
|
m_count += count;
|
||||||
|
if(count > 0)
|
||||||
|
printf("+%s\n", text);
|
||||||
|
if(count < 0)
|
||||||
|
printf("-%s\n", text);
|
||||||
|
return m_count;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "AUD_Mixer.h"
|
#include "AUD_Mixer.h"
|
||||||
#include "AUD_SRCResampleFactory.h"
|
#include "AUD_SRCResampleFactory.h"
|
||||||
|
#include "AUD_LinearResampleFactory.h"
|
||||||
#include "AUD_ChannelMapperFactory.h"
|
#include "AUD_ChannelMapperFactory.h"
|
||||||
#include "AUD_IReader.h"
|
#include "AUD_IReader.h"
|
||||||
#include "AUD_Buffer.h"
|
#include "AUD_Buffer.h"
|
||||||
@@ -86,7 +87,7 @@ void AUD_Mixer::setSpecs(AUD_DeviceSpecs specs)
|
|||||||
delete m_mapper; AUD_DELETE("factory")
|
delete m_mapper; AUD_DELETE("factory")
|
||||||
}
|
}
|
||||||
|
|
||||||
m_resampler = new AUD_SRCResampleFactory(specs); AUD_NEW("factory")
|
m_resampler = new AUD_MIXER_RESAMPLER(specs); AUD_NEW("factory")
|
||||||
m_mapper = new AUD_ChannelMapperFactory(specs); AUD_NEW("factory")
|
m_mapper = new AUD_ChannelMapperFactory(specs); AUD_NEW("factory")
|
||||||
|
|
||||||
int bigendian = 1;
|
int bigendian = 1;
|
||||||
|
@@ -26,9 +26,11 @@
|
|||||||
#ifndef AUD_MIXER
|
#ifndef AUD_MIXER
|
||||||
#define AUD_MIXER
|
#define AUD_MIXER
|
||||||
|
|
||||||
|
#define AUD_MIXER_RESAMPLER AUD_LinearResampleFactory
|
||||||
|
|
||||||
#include "AUD_ConverterFunctions.h"
|
#include "AUD_ConverterFunctions.h"
|
||||||
class AUD_ConverterFactory;
|
class AUD_ConverterFactory;
|
||||||
class AUD_SRCResampleFactory;
|
class AUD_MIXER_RESAMPLER;
|
||||||
class AUD_ChannelMapperFactory;
|
class AUD_ChannelMapperFactory;
|
||||||
class AUD_Buffer;
|
class AUD_Buffer;
|
||||||
class AUD_IReader;
|
class AUD_IReader;
|
||||||
@@ -54,7 +56,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* The resampling factory that resamples all readers for superposition.
|
* The resampling factory that resamples all readers for superposition.
|
||||||
*/
|
*/
|
||||||
AUD_SRCResampleFactory* m_resampler;
|
AUD_MIXER_RESAMPLER* m_resampler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The channel mapper factory that maps all readers for superposition.
|
* The channel mapper factory that maps all readers for superposition.
|
||||||
|
@@ -100,13 +100,17 @@ void AUD_SequencerReader::add(AUD_SequencerEntry* entry)
|
|||||||
{
|
{
|
||||||
AUD_SequencerStrip* strip = new AUD_SequencerStrip; AUD_NEW("seqstrip")
|
AUD_SequencerStrip* strip = new AUD_SequencerStrip; AUD_NEW("seqstrip")
|
||||||
strip->entry = entry;
|
strip->entry = entry;
|
||||||
strip->old_sound = NULL;
|
|
||||||
|
|
||||||
if(strip->old_sound)
|
if(*strip->entry->sound)
|
||||||
|
{
|
||||||
|
strip->old_sound = *strip->entry->sound;
|
||||||
strip->reader = m_mixer.prepare(strip->old_sound->createReader());
|
strip->reader = m_mixer.prepare(strip->old_sound->createReader());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
strip->reader = NULL;
|
strip->reader = NULL;
|
||||||
|
strip->old_sound = NULL;
|
||||||
|
}
|
||||||
m_strips.push_front(strip);
|
m_strips.push_front(strip);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,7 +128,7 @@ void AUD_SequencerReader::remove(AUD_SequencerEntry* entry)
|
|||||||
delete strip->reader; AUD_DELETE("reader")
|
delete strip->reader; AUD_DELETE("reader")
|
||||||
}
|
}
|
||||||
m_strips.remove(strip);
|
m_strips.remove(strip);
|
||||||
delete strip;
|
delete strip; AUD_DELETE("seqstrip")
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -97,7 +97,7 @@
|
|||||||
//#define AUD_DEBUG_MEMORY
|
//#define AUD_DEBUG_MEMORY
|
||||||
|
|
||||||
#ifdef AUD_DEBUG_MEMORY
|
#ifdef AUD_DEBUG_MEMORY
|
||||||
int AUD_References(int count = 0, const char* text = "");
|
extern int AUD_References(int count, const char* text);
|
||||||
#define AUD_NEW(text) AUD_References(1, text);
|
#define AUD_NEW(text) AUD_References(1, text);
|
||||||
#define AUD_DELETE(text) AUD_References(-1, text);
|
#define AUD_DELETE(text) AUD_References(-1, text);
|
||||||
#else
|
#else
|
||||||
|
76
release/scripts/op/sequencer.py
Normal file
76
release/scripts/op/sequencer.py
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||||
|
#
|
||||||
|
# This program 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.
|
||||||
|
#
|
||||||
|
# This program 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 this program; if not, write to the Free Software Foundation,
|
||||||
|
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
#
|
||||||
|
# ##### END GPL LICENSE BLOCK #####
|
||||||
|
|
||||||
|
# <pep8 compliant>
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
|
||||||
|
class SequencerCrossfadeSounds(bpy.types.Operator):
|
||||||
|
'''Do crossfading volume animation of two selected sound strips.'''
|
||||||
|
|
||||||
|
bl_idname = "sequencer.crossfade_sounds"
|
||||||
|
bl_label = "Crossfade sounds"
|
||||||
|
bl_register = True
|
||||||
|
bl_undo = True
|
||||||
|
|
||||||
|
def poll(self, context):
|
||||||
|
if context.scene and context.scene.sequence_editor and context.scene.sequence_editor.active_strip:
|
||||||
|
return context.scene.sequence_editor.active_strip.type == 'SOUND'
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
seq1 = None
|
||||||
|
seq2 = None
|
||||||
|
for s in context.scene.sequence_editor.sequences:
|
||||||
|
if s.selected and s.type == 'SOUND':
|
||||||
|
if seq1 == None:
|
||||||
|
seq1 = s
|
||||||
|
elif seq2 == None:
|
||||||
|
seq2 = s
|
||||||
|
else:
|
||||||
|
seq2 = None
|
||||||
|
break
|
||||||
|
if seq2 == None:
|
||||||
|
self.report({'ERROR'}, "Select 2 sound strips.")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
if seq1.start_frame_final > seq2.start_frame_final:
|
||||||
|
s = seq1
|
||||||
|
seq1 = seq2
|
||||||
|
seq2 = s
|
||||||
|
if seq1.end_frame_final > seq2.start_frame_final:
|
||||||
|
tempcfra = context.scene.current_frame
|
||||||
|
context.scene.current_frame = seq2.start_frame_final
|
||||||
|
seq1.keyframe_insert('volume')
|
||||||
|
context.scene.current_frame = seq1.end_frame_final
|
||||||
|
seq1.volume = 0
|
||||||
|
seq1.keyframe_insert('volume')
|
||||||
|
seq2.keyframe_insert('volume')
|
||||||
|
context.scene.current_frame = seq2.start_frame_final
|
||||||
|
seq2.volume = 0
|
||||||
|
seq2.keyframe_insert('volume')
|
||||||
|
context.scene.current_frame = tempcfra
|
||||||
|
return {'FINISHED'}
|
||||||
|
else:
|
||||||
|
self.report({'ERROR'}, "The selected strips don't overlap.")
|
||||||
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
bpy.types.register(SequencerCrossfadeSounds)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
bpy.ops.sequencer.crossfade_sounds()
|
Reference in New Issue
Block a user