2.5 Audio:
authorJoerg Mueller <nexyon@gmail.com>
Mon, 8 Feb 2010 14:43:44 +0000 (14:43 +0000)
committerJoerg Mueller <nexyon@gmail.com>
Mon, 8 Feb 2010 14:43:44 +0000 (14:43 +0000)
- 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

intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
intern/audaspace/SRC/AUD_SRCResampleReader.cpp
intern/audaspace/SRC/AUD_SRCResampleReader.h
intern/audaspace/intern/AUD_C-API.cpp
intern/audaspace/intern/AUD_Mixer.cpp
intern/audaspace/intern/AUD_Mixer.h
intern/audaspace/intern/AUD_SequencerReader.cpp
intern/audaspace/intern/AUD_Space.h
release/scripts/op/sequencer.py [new file with mode: 0644]

index 9e153b9b34f124dc0ccc10443f797f5db7258fa5..7ee8652f226839c880c46815a75faa97d2ee4bac 100644 (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;
+               alGetSourcef(h->source, AL_SEC_OFFSET, &position);
+               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();
index 940f4245316c80dfabc2308522d477afc6bc6afe..e89857635dec99c573cb090a499c1c8b651a487e 100644 (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;
 }
index 4fe30b48c6e7aa41eb7d81893ffda01af3797379..e09d1b66f13c72cc6315b4be1a142e744e7397eb 100644 (file)
@@ -62,6 +62,11 @@ private:
         */
        SRC_STATE* m_src;
 
+       /**
+        * The current playback position;
+        */
+       int m_position;
+
 public:
        /**
         * Creates a resampling reader.
index b363c4576b38efb67aff69542c43e31fa1cbe4a9..2e3ae4ef6424bd69aaec32be57fc3545fbad6eb2 100644 (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
index b2704602a89b5d49f4ee4161672b0765b9c6eaf7..e77d40fdbcab5cac64eed807ad1e4cd011480072 100644 (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;
index 5dcdef45eba17cc6315a99fe1bee151e25f79fbc..a24422a8a21c81c3351441616e5ed3ed74b4477f 100644 (file)
 #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.
index 84c1476289351adf6f6c9a94811f12b7c1ace23f..8869d8d54ca3453b31f906155c31484843c0e610 100644 (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;
                }
        }
index 9e192ac2cac57092d741d2dfe9f3c6da25b98ae9..9e857ce73b045c41e0cb8b3bd9c65678b421aef9 100644 (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
diff --git a/release/scripts/op/sequencer.py b/release/scripts/op/sequencer.py
new file mode 100644 (file)
index 0000000..e78084b
--- /dev/null
@@ -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()