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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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