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:
Joerg Mueller
2010-02-08 14:43:44 +00:00
parent 03bdfb6f31
commit 6c8e3e303d
9 changed files with 123 additions and 15 deletions

View File

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

View File

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

View File

@@ -62,6 +62,11 @@ private:
*/
SRC_STATE* m_src;
/**
* The current playback position;
*/
int m_position;
public:
/**
* Creates a resampling reader.

View File

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

View File

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

View File

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

View File

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

View File

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

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