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))
|
||||
{
|
||||
AUD_OpenALHandle* h = (AUD_OpenALHandle*)handle;
|
||||
if(h->isBuffered)
|
||||
alGetSourcef(h->source, AL_SEC_OFFSET, &position);
|
||||
else
|
||||
position = h->reader->getPosition() /
|
||||
(float)h->reader->getSpecs().rate;
|
||||
if(!h->isBuffered)
|
||||
{
|
||||
AUD_Specs specs = h->reader->getSpecs();
|
||||
position += (h->reader->getPosition() - m_buffersize *
|
||||
AUD_OPENAL_CYCLE_BUFFERS / specs.channels) /
|
||||
(float)specs.rate;
|
||||
}
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
@@ -44,6 +44,7 @@ AUD_SRCResampleReader::AUD_SRCResampleReader(AUD_IReader* reader,
|
||||
m_tspecs = specs;
|
||||
m_tspecs.channels = m_sspecs.channels;
|
||||
m_factor = (double)m_tspecs.rate / (double)m_sspecs.rate;
|
||||
m_position = 0;
|
||||
|
||||
int error;
|
||||
m_src = src_callback_new(src_callback,
|
||||
@@ -71,7 +72,7 @@ AUD_SRCResampleReader::~AUD_SRCResampleReader()
|
||||
|
||||
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;
|
||||
|
||||
m_reader->read(length, buffer);
|
||||
@@ -84,6 +85,7 @@ void AUD_SRCResampleReader::seek(int position)
|
||||
{
|
||||
m_reader->seek(position / m_factor);
|
||||
src_reset(m_src);
|
||||
m_position = position;
|
||||
}
|
||||
|
||||
int AUD_SRCResampleReader::getLength()
|
||||
@@ -93,7 +95,7 @@ int AUD_SRCResampleReader::getLength()
|
||||
|
||||
int AUD_SRCResampleReader::getPosition()
|
||||
{
|
||||
return m_reader->getPosition() * m_factor;
|
||||
return m_position;
|
||||
}
|
||||
|
||||
AUD_Specs AUD_SRCResampleReader::getSpecs()
|
||||
@@ -111,4 +113,6 @@ void AUD_SRCResampleReader::read(int & length, sample_t* & buffer)
|
||||
buffer = m_buffer->getBuffer();
|
||||
|
||||
length = src_callback_read(m_src, m_factor, length, buffer);
|
||||
|
||||
m_position += length;
|
||||
}
|
||||
|
@@ -62,6 +62,11 @@ private:
|
||||
*/
|
||||
SRC_STATE* m_src;
|
||||
|
||||
/**
|
||||
* The current playback position;
|
||||
*/
|
||||
int m_position;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a resampling reader.
|
||||
|
@@ -762,3 +762,16 @@ int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int 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_SRCResampleFactory.h"
|
||||
#include "AUD_LinearResampleFactory.h"
|
||||
#include "AUD_ChannelMapperFactory.h"
|
||||
#include "AUD_IReader.h"
|
||||
#include "AUD_Buffer.h"
|
||||
@@ -86,7 +87,7 @@ void AUD_Mixer::setSpecs(AUD_DeviceSpecs specs)
|
||||
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")
|
||||
|
||||
int bigendian = 1;
|
||||
|
@@ -26,9 +26,11 @@
|
||||
#ifndef AUD_MIXER
|
||||
#define AUD_MIXER
|
||||
|
||||
#define AUD_MIXER_RESAMPLER AUD_LinearResampleFactory
|
||||
|
||||
#include "AUD_ConverterFunctions.h"
|
||||
class AUD_ConverterFactory;
|
||||
class AUD_SRCResampleFactory;
|
||||
class AUD_MIXER_RESAMPLER;
|
||||
class AUD_ChannelMapperFactory;
|
||||
class AUD_Buffer;
|
||||
class AUD_IReader;
|
||||
@@ -54,7 +56,7 @@ private:
|
||||
/**
|
||||
* 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.
|
||||
|
@@ -100,13 +100,17 @@ void AUD_SequencerReader::add(AUD_SequencerEntry* entry)
|
||||
{
|
||||
AUD_SequencerStrip* strip = new AUD_SequencerStrip; AUD_NEW("seqstrip")
|
||||
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());
|
||||
}
|
||||
else
|
||||
{
|
||||
strip->reader = NULL;
|
||||
|
||||
strip->old_sound = NULL;
|
||||
}
|
||||
m_strips.push_front(strip);
|
||||
}
|
||||
|
||||
@@ -124,7 +128,7 @@ void AUD_SequencerReader::remove(AUD_SequencerEntry* entry)
|
||||
delete strip->reader; AUD_DELETE("reader")
|
||||
}
|
||||
m_strips.remove(strip);
|
||||
delete strip;
|
||||
delete strip; AUD_DELETE("seqstrip")
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@@ -97,7 +97,7 @@
|
||||
//#define 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_DELETE(text) AUD_References(-1, text);
|
||||
#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