Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoerg Mueller <nexyon@gmail.com>2010-02-08 02:41:17 +0300
committerJoerg Mueller <nexyon@gmail.com>2010-02-08 02:41:17 +0300
commit9827a3e9eac70f68db6dc16d03016c51b7ece3f0 (patch)
tree8825b454008d3b97a64018884c179ea94874af44
parent2f72b91a54faa7cfbdfd97eff608c8911df1d221 (diff)
2.5 Audio:
- recode of the whole sequencer audio handling - encode audio flag removed, instead you choose None as audio codec, added None for video codec too - ffmpeg formats/codecs: enabled: theora, ogg, vorbis; added: matroska, flac (not working, who can fix?), mp3, wav - sequencer wave drawing - volume animation (now also working when mixing down to a file!) - made sequencer strip position and length values unanimatable
-rw-r--r--intern/audaspace/FX/AUD_LoopReader.cpp9
-rw-r--r--intern/audaspace/FX/AUD_LoopReader.h5
-rw-r--r--intern/audaspace/OpenAL/AUD_OpenALDevice.cpp13
-rw-r--r--intern/audaspace/intern/AUD_C-API.cpp109
-rw-r--r--intern/audaspace/intern/AUD_C-API.h29
-rw-r--r--intern/audaspace/intern/AUD_Mixer.cpp12
-rw-r--r--intern/audaspace/intern/AUD_Mixer.h9
-rw-r--r--intern/audaspace/intern/AUD_SequencerFactory.cpp109
-rw-r--r--intern/audaspace/intern/AUD_SequencerFactory.h77
-rw-r--r--intern/audaspace/intern/AUD_SequencerReader.cpp245
-rw-r--r--intern/audaspace/intern/AUD_SequencerReader.h102
-rw-r--r--intern/audaspace/intern/AUD_SoftwareDevice.cpp9
-rw-r--r--intern/audaspace/intern/AUD_Space.h6
-rw-r--r--release/scripts/ui/properties_render.py8
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h8
-rw-r--r--source/blender/blenkernel/BKE_sound.h27
-rw-r--r--source/blender/blenkernel/BKE_writeffmpeg.h2
-rw-r--r--source/blender/blenkernel/intern/scene.c7
-rw-r--r--source/blender/blenkernel/intern/sequencer.c90
-rw-r--r--source/blender/blenkernel/intern/sound.c293
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c170
-rw-r--r--source/blender/blenloader/intern/readfile.c18
-rw-r--r--source/blender/editors/animation/anim_ops.c2
-rw-r--r--source/blender/editors/screen/screen_ops.c14
-rw-r--r--source/blender/editors/sound/sound_ops.c4
-rw-r--r--source/blender/editors/space_graph/graph_ops.c2
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c38
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c74
-rw-r--r--source/blender/editors/transform/transform_conversions.c14
-rw-r--r--source/blender/makesdna/DNA_scene_types.h5
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h4
-rw-r--r--source/blender/makesdna/DNA_sound_types.h25
-rw-r--r--source/blender/makesrna/intern/rna_scene.c33
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c24
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_SoundActuator.cpp2
37 files changed, 1101 insertions, 507 deletions
diff --git a/intern/audaspace/FX/AUD_LoopReader.cpp b/intern/audaspace/FX/AUD_LoopReader.cpp
index 7d70fc20221..3bcd8c2f9d3 100644
--- a/intern/audaspace/FX/AUD_LoopReader.cpp
+++ b/intern/audaspace/FX/AUD_LoopReader.cpp
@@ -31,6 +31,7 @@
AUD_LoopReader::AUD_LoopReader(AUD_IReader* reader, int loop) :
AUD_EffectReader(reader), m_loop(loop)
{
+ m_samples = -1;
m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
}
@@ -51,6 +52,7 @@ bool AUD_LoopReader::notify(AUD_Message &message)
if(message.type == AUD_MSG_LOOP)
{
m_loop = message.loopcount;
+ m_samples = message.time * m_reader->getSpecs().rate;
m_reader->notify(message);
@@ -64,6 +66,13 @@ void AUD_LoopReader::read(int & length, sample_t* & buffer)
AUD_Specs specs = m_reader->getSpecs();
int samplesize = AUD_SAMPLE_SIZE(specs);
+ if(m_samples >= 0)
+ {
+ if(length > m_samples)
+ length = m_samples;
+ m_samples -= length;
+ }
+
int len = length;
m_reader->read(len, buffer);
diff --git a/intern/audaspace/FX/AUD_LoopReader.h b/intern/audaspace/FX/AUD_LoopReader.h
index 621ee3493ab..e61a49cb0db 100644
--- a/intern/audaspace/FX/AUD_LoopReader.h
+++ b/intern/audaspace/FX/AUD_LoopReader.h
@@ -46,6 +46,11 @@ private:
*/
int m_loop;
+ /**
+ * The left samples.
+ */
+ int m_samples;
+
public:
/**
* Creates a new loop reader.
diff --git a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
index 0b3e86eda56..9e153b9b34f 100644
--- a/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
+++ b/intern/audaspace/OpenAL/AUD_OpenALDevice.cpp
@@ -180,7 +180,7 @@ void AUD_OpenALDevice::updateStreams()
AUD_DEVICE_SAMPLE_SIZE(specs),
specs.rate);
- if(alGetError() != AL_NO_ERROR)
+ if((err = alGetError()) != AL_NO_ERROR)
{
sound->data_end = true;
break;
@@ -839,13 +839,14 @@ bool AUD_OpenALDevice::seek(AUD_Handle* handle, float position)
if(info != AL_PLAYING)
{
- if(info != AL_STOPPED)
+ if(info == AL_PAUSED)
alSourceStop(alhandle->source);
- alSourceUnqueueBuffers(alhandle->source,
- AUD_OPENAL_CYCLE_BUFFERS,
- alhandle->buffers);
- if(alGetError() == AL_NO_ERROR)
+ alSourcei(alhandle->source, AL_BUFFER, 0);
+ alhandle->current = 0;
+
+ ALenum err;
+ if((err = alGetError()) == AL_NO_ERROR)
{
sample_t* buf;
int length;
diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp
index b7d0183cb5e..b363c4576b3 100644
--- a/intern/audaspace/intern/AUD_C-API.cpp
+++ b/intern/audaspace/intern/AUD_C-API.cpp
@@ -25,6 +25,7 @@
#include <cstdlib>
#include <cstring>
+#include <cmath>
#include "AUD_NULLDevice.h"
#include "AUD_I3DDevice.h"
@@ -47,6 +48,7 @@
#include "AUD_ReadDevice.h"
#include "AUD_SourceCaps.h"
#include "AUD_IReader.h"
+#include "AUD_SequencerFactory.h"
#ifdef WITH_SDL
#include "AUD_SDLDevice.h"
@@ -231,7 +233,7 @@ AUD_Sound* AUD_delaySound(AUD_Sound* sound, float delay)
}
}
-extern AUD_Sound* AUD_limitSound(AUD_Sound* sound, float start, float end)
+AUD_Sound* AUD_limitSound(AUD_Sound* sound, float start, float end)
{
assert(sound);
@@ -273,13 +275,14 @@ AUD_Sound* AUD_loopSound(AUD_Sound* sound)
}
}
-int AUD_stopLoop(AUD_Handle* handle)
+int AUD_setLoop(AUD_Handle* handle, int loops, float time)
{
if(handle)
{
AUD_Message message;
message.type = AUD_MSG_LOOP;
- message.loopcount = 0;
+ message.loopcount = loops;
+ message.time = time;
try
{
@@ -537,14 +540,16 @@ AUD_Device* AUD_openReadDevice(AUD_DeviceSpecs specs)
}
}
-AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound)
+AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek)
{
assert(device);
assert(sound);
try
{
- return device->play(sound);
+ AUD_Handle* handle = device->play(sound);
+ device->seek(handle, seek);
+ return handle;
}
catch(AUD_Exception)
{
@@ -663,3 +668,97 @@ float* AUD_readSoundBuffer(const char* filename, float low, float high,
*length = position;
return result;
}
+
+AUD_Sound* AUD_createSequencer(void* data, AUD_volumeFunction volume)
+{
+ if(AUD_device)
+ {
+ return new AUD_SequencerFactory(AUD_device->getSpecs().specs, data, volume);
+ }
+ else
+ {
+ AUD_Specs specs;
+ specs.channels = AUD_CHANNELS_STEREO;
+ specs.rate = AUD_RATE_44100;
+ return new AUD_SequencerFactory(specs, data, volume);
+ }
+}
+
+void AUD_destroySequencer(AUD_Sound* sequencer)
+{
+ delete ((AUD_SequencerFactory*)sequencer);
+}
+
+AUD_SequencerEntry* AUD_addSequencer(AUD_Sound** sequencer, AUD_Sound* sound,
+ float begin, float end, float skip, void* data)
+{
+ return ((AUD_SequencerFactory*)sequencer)->add((AUD_IFactory**) sound, begin, end, skip, data);
+}
+
+void AUD_removeSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry)
+{
+ ((AUD_SequencerFactory*)sequencer)->remove(entry);
+}
+
+void AUD_moveSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry,
+ float begin, float end, float skip)
+{
+ ((AUD_SequencerFactory*)sequencer)->move(entry, begin, end, skip);
+}
+
+void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, char mute)
+{
+ ((AUD_SequencerFactory*)sequencer)->mute(entry, mute);
+}
+
+int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length)
+{
+ AUD_IReader* reader = sound->createReader();
+ AUD_DeviceSpecs specs;
+ sample_t* buf;
+
+ specs.specs = reader->getSpecs();
+ specs.channels = AUD_CHANNELS_MONO;
+ specs.format = AUD_FORMAT_FLOAT32;
+
+ AUD_ChannelMapperFactory mapper(reader, specs);
+
+ if(!reader || reader->getType() != AUD_TYPE_BUFFER)
+ return -1;
+
+ reader = mapper.createReader();
+
+ if(!reader)
+ return -1;
+
+ int len = reader->getLength();
+ float samplejump = (float)len / (float)length;
+ float min, max;
+
+ for(int i = 0; i < length; i++)
+ {
+ len = floor(samplejump * (i+1)) - floor(samplejump * i);
+ reader->read(len, buf);
+
+ if(len < 1)
+ {
+ length = i;
+ break;
+ }
+
+ max = min = *buf;
+ for(int j = 1; j < len; j++)
+ {
+ if(buf[j] < min)
+ min = buf[j];
+ if(buf[j] > max)
+ max = buf[j];
+ buffer[i * 2] = min;
+ buffer[i * 2 + 1] = max;
+ }
+ }
+
+ delete reader; AUD_DELETE("reader")
+
+ return length;
+}
diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h
index c3439f89ade..ce1791886de 100644
--- a/intern/audaspace/intern/AUD_C-API.h
+++ b/intern/audaspace/intern/AUD_C-API.h
@@ -50,6 +50,8 @@ typedef struct
typedef void AUD_Sound;
typedef void AUD_Handle;
typedef void AUD_Device;
+ typedef void AUD_SequencerEntry;
+ typedef float (*AUD_volumeFunction)(void*, void*, float);
#endif
/**
@@ -143,11 +145,13 @@ extern AUD_Sound* AUD_pingpongSound(AUD_Sound* sound);
extern AUD_Sound* AUD_loopSound(AUD_Sound* sound);
/**
- * Stops a looping sound when the current playback finishes.
+ * Sets a remaining loop count of a looping sound that currently plays.
* \param handle The playback handle.
+ * \param loops The count of remaining loops, -1 for infinity.
+ * \param time The time after which playback should stop, -1 for infinity.
* \return Whether the handle is valid.
*/
-extern int AUD_stopLoop(AUD_Handle* handle);
+extern int AUD_setLoop(AUD_Handle* handle, int loops, float time);
/**
* Rectifies a sound.
@@ -211,6 +215,7 @@ extern int AUD_seek(AUD_Handle* handle, float seekTo);
/**
* Retrieves the playback position of a handle.
+ * \param handle The handle to the sound.
* \return The current playback position in seconds or 0.0 if the handle is
* invalid.
*/
@@ -318,9 +323,10 @@ extern int AUD_setDeviceVolume(AUD_Device* device, float volume);
* Plays back a sound file through a read device.
* \param device The read device.
* \param sound The handle of the sound file.
+ * \param seek The position where the sound should be seeked to.
* \return A handle to the played back sound.
*/
-extern AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound);
+extern AUD_Handle* AUD_playDevice(AUD_Device* device, AUD_Sound* sound, float seek);
/**
* Sets the volume of a played back sound of a read device.
@@ -360,6 +366,23 @@ extern float* AUD_readSoundBuffer(const char* filename, float low, float high,
float sthreshold, int samplerate,
int* length);
+extern AUD_Sound* AUD_createSequencer(void* data, AUD_volumeFunction volume);
+
+extern void AUD_destroySequencer(AUD_Sound* sequencer);
+
+extern AUD_SequencerEntry* AUD_addSequencer(AUD_Sound** sequencer, AUD_Sound* sound,
+ float begin, float end, float skip, void* data);
+
+extern void AUD_removeSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry);
+
+extern void AUD_moveSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry,
+ float begin, float end, float skip);
+
+extern void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry,
+ char mute);
+
+extern int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length);
+
#ifdef __cplusplus
}
#endif
diff --git a/intern/audaspace/intern/AUD_Mixer.cpp b/intern/audaspace/intern/AUD_Mixer.cpp
index bddc719b179..299388b558b 100644
--- a/intern/audaspace/intern/AUD_Mixer.cpp
+++ b/intern/audaspace/intern/AUD_Mixer.cpp
@@ -68,6 +68,11 @@ AUD_IReader* AUD_Mixer::prepare(AUD_IReader* reader)
return reader;
}
+AUD_DeviceSpecs AUD_Mixer::getSpecs()
+{
+ return m_specs;
+}
+
void AUD_Mixer::setSpecs(AUD_DeviceSpecs specs)
{
m_specs = specs;
@@ -115,10 +120,11 @@ void AUD_Mixer::setSpecs(AUD_DeviceSpecs specs)
}
}
-void AUD_Mixer::add(sample_t* buffer, int length, float volume)
+void AUD_Mixer::add(sample_t* buffer, int start, int length, float volume)
{
AUD_MixerBuffer buf;
buf.buffer = buffer;
+ buf.start = start;
buf.length = length;
buf.volume = volume;
m_buffers.push_back(buf);
@@ -145,11 +151,11 @@ void AUD_Mixer::superpose(data_t* buffer, int length, float volume)
buf = m_buffers.front();
m_buffers.pop_front();
- end = buf.length*channels;
+ end = buf.length * channels;
in = buf.buffer;
for(int i = 0; i < end; i++)
- out[i] += in[i]*buf.volume * volume;
+ out[i + buf.start * channels] += in[i] * buf.volume * volume;
}
m_convert(buffer, (data_t*) out, length * channels);
diff --git a/intern/audaspace/intern/AUD_Mixer.h b/intern/audaspace/intern/AUD_Mixer.h
index 5097b9ec2a6..5dcdef45eba 100644
--- a/intern/audaspace/intern/AUD_Mixer.h
+++ b/intern/audaspace/intern/AUD_Mixer.h
@@ -37,6 +37,7 @@ class AUD_IReader;
struct AUD_MixerBuffer
{
sample_t* buffer;
+ int start;
int length;
float volume;
};
@@ -99,6 +100,12 @@ public:
AUD_IReader* prepare(AUD_IReader* reader);
/**
+ * Returns the target specification for superposing.
+ * \return The target specification.
+ */
+ AUD_DeviceSpecs getSpecs();
+
+ /**
* Sets the target specification for superposing.
* \param specs The target specification.
*/
@@ -111,7 +118,7 @@ public:
* \param length The length of the buffer in samples.
* \param volume The mixing volume. Must be a value between 0.0 and 1.0.
*/
- void add(sample_t* buffer, int length, float volume);
+ void add(sample_t* buffer, int start, int length, float volume);
/**
* Superposes all added buffers into an output buffer.
diff --git a/intern/audaspace/intern/AUD_SequencerFactory.cpp b/intern/audaspace/intern/AUD_SequencerFactory.cpp
new file mode 100644
index 00000000000..bb5cf27fb5f
--- /dev/null
+++ b/intern/audaspace/intern/AUD_SequencerFactory.cpp
@@ -0,0 +1,109 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#include "AUD_SequencerFactory.h"
+#include "AUD_SequencerReader.h"
+
+typedef std::list<AUD_SequencerReader*>::iterator AUD_ReaderIterator;
+
+AUD_SequencerFactory::AUD_SequencerFactory(AUD_Specs specs, void* data, AUD_volumeFunction volume)
+{
+ m_specs = specs;
+ m_data = data;
+ m_volume = volume;
+}
+
+AUD_SequencerFactory::~AUD_SequencerFactory()
+{
+ AUD_SequencerReader* reader;
+ AUD_SequencerEntry* entry;
+
+ while(!m_readers.empty())
+ {
+ reader = m_readers.front();
+ m_readers.pop_front();
+ reader->destroy();
+ }
+
+ while(!m_entries.empty())
+ {
+ entry = m_entries.front();
+ m_entries.pop_front();
+ delete entry; AUD_DELETE("seqentry")
+ }
+}
+
+AUD_SequencerEntry* AUD_SequencerFactory::add(AUD_IFactory** sound, float begin, float end, float skip, void* data)
+{
+ AUD_SequencerEntry* entry = new AUD_SequencerEntry; AUD_NEW("seqentry")
+ entry->sound = sound;
+ entry->begin = begin;
+ entry->skip = skip;
+ entry->end = end;
+ entry->muted = false;
+ entry->data = data;
+
+ m_entries.push_front(entry);
+
+ for(AUD_ReaderIterator i = m_readers.begin(); i != m_readers.end(); i++)
+ (*i)->add(entry);
+
+ return entry;
+}
+
+void AUD_SequencerFactory::remove(AUD_SequencerEntry* entry)
+{
+ for(AUD_ReaderIterator i = m_readers.begin(); i != m_readers.end(); i++)
+ (*i)->remove(entry);
+
+ m_entries.remove(entry);
+
+ delete entry; AUD_DELETE("seqentry")
+}
+
+void AUD_SequencerFactory::move(AUD_SequencerEntry* entry, float begin, float end, float skip)
+{
+ entry->begin = begin;
+ entry->skip = skip;
+ entry->end = end;
+}
+
+void AUD_SequencerFactory::mute(AUD_SequencerEntry* entry, bool mute)
+{
+ entry->muted = mute;
+}
+
+AUD_IReader* AUD_SequencerFactory::createReader()
+{
+ AUD_SequencerReader* reader = new AUD_SequencerReader(this, m_entries, m_specs, m_data, m_volume); AUD_NEW("reader")
+ m_readers.push_front(reader);
+
+ return reader;
+}
+
+void AUD_SequencerFactory::removeReader(AUD_SequencerReader* reader)
+{
+ m_readers.remove(reader);
+}
diff --git a/intern/audaspace/intern/AUD_SequencerFactory.h b/intern/audaspace/intern/AUD_SequencerFactory.h
new file mode 100644
index 00000000000..b564c888fc6
--- /dev/null
+++ b/intern/audaspace/intern/AUD_SequencerFactory.h
@@ -0,0 +1,77 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#ifndef AUD_SEQUENCERFACTORY
+#define AUD_SEQUENCERFACTORY
+
+#include "AUD_IFactory.h"
+
+#include <list>
+
+typedef float (*AUD_volumeFunction)(void*, void*, float);
+
+struct AUD_SequencerEntry
+{
+ AUD_IFactory** sound;
+ float begin;
+ float end;
+ float skip;
+ bool muted;
+ void* data;
+};
+
+class AUD_SequencerReader;
+
+/**
+ * This factory creates a resampling reader that does simple linear resampling.
+ */
+class AUD_SequencerFactory : public AUD_IFactory
+{
+private:
+ /**
+ * The target specification.
+ */
+ AUD_Specs m_specs;
+
+ std::list<AUD_SequencerEntry*> m_entries;
+ std::list<AUD_SequencerReader*> m_readers;
+ void* m_data;
+ AUD_volumeFunction m_volume;
+
+public:
+ AUD_SequencerFactory(AUD_Specs specs, void* data, AUD_volumeFunction volume);
+ ~AUD_SequencerFactory();
+
+ AUD_SequencerEntry* add(AUD_IFactory** sound, float begin, float end, float skip, void* data);
+ void remove(AUD_SequencerEntry* entry);
+ void move(AUD_SequencerEntry* entry, float begin, float end, float skip);
+ void mute(AUD_SequencerEntry* entry, bool mute);
+
+ virtual AUD_IReader* createReader();
+
+ void removeReader(AUD_SequencerReader* reader);
+};
+
+#endif //AUD_SEQUENCERFACTORY
diff --git a/intern/audaspace/intern/AUD_SequencerReader.cpp b/intern/audaspace/intern/AUD_SequencerReader.cpp
new file mode 100644
index 00000000000..84c14762893
--- /dev/null
+++ b/intern/audaspace/intern/AUD_SequencerReader.cpp
@@ -0,0 +1,245 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#include "AUD_SequencerReader.h"
+#include "AUD_Buffer.h"
+
+#include <math.h>
+
+typedef std::list<AUD_SequencerStrip*>::iterator AUD_StripIterator;
+typedef std::list<AUD_SequencerEntry*>::iterator AUD_EntryIterator;
+
+AUD_SequencerReader::AUD_SequencerReader(AUD_SequencerFactory* factory, std::list<AUD_SequencerEntry*> &entries, AUD_Specs specs, void* data, AUD_volumeFunction volume)
+{
+ AUD_DeviceSpecs dspecs;
+ dspecs.specs = specs;
+ dspecs.format = AUD_FORMAT_FLOAT32;
+
+ m_mixer.setSpecs(dspecs);
+ m_factory = factory;
+ m_data = data;
+ m_volume = volume;
+
+ AUD_SequencerStrip* strip;
+
+ for(AUD_EntryIterator i = entries.begin(); i != entries.end(); i++)
+ {
+ strip = new AUD_SequencerStrip; AUD_NEW("seqstrip")
+ strip->entry = *i;
+ strip->old_sound = NULL;
+
+ if(strip->old_sound)
+ strip->reader = m_mixer.prepare(strip->old_sound->createReader());
+ else
+ strip->reader = NULL;
+
+ m_strips.push_front(strip);
+ }
+
+ m_position = 0;
+ m_buffer = new AUD_Buffer(); AUD_NEW("buffer")
+}
+
+AUD_SequencerReader::~AUD_SequencerReader()
+{
+ if(m_factory != NULL)
+ m_factory->removeReader(this);
+
+ AUD_SequencerStrip* strip;
+
+ while(!m_strips.empty())
+ {
+ strip = m_strips.front();
+ m_strips.pop_front();
+ if(strip->reader)
+ {
+ delete strip->reader; AUD_DELETE("reader")
+ }
+ delete strip; AUD_DELETE("seqstrip")
+ }
+
+ delete m_buffer; AUD_DELETE("buffer")
+}
+
+void AUD_SequencerReader::destroy()
+{
+ m_factory = NULL;
+ AUD_SequencerStrip* strip;
+
+ while(!m_strips.empty())
+ {
+ strip = m_strips.front();
+ m_strips.pop_front();
+ delete strip; AUD_DELETE("seqstrip")
+ }
+}
+
+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)
+ strip->reader = m_mixer.prepare(strip->old_sound->createReader());
+ else
+ strip->reader = NULL;
+
+ m_strips.push_front(strip);
+}
+
+void AUD_SequencerReader::remove(AUD_SequencerEntry* entry)
+{
+ AUD_SequencerStrip* strip;
+ for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
+ {
+ strip = *i;
+ if(strip->entry == entry)
+ {
+ i++;
+ if(strip->reader)
+ {
+ delete strip->reader; AUD_DELETE("reader")
+ }
+ m_strips.remove(strip);
+ delete strip;
+ return;
+ }
+ }
+}
+
+bool AUD_SequencerReader::isSeekable()
+{
+ return true;
+}
+
+void AUD_SequencerReader::seek(int position)
+{
+ m_position = position;
+}
+
+int AUD_SequencerReader::getLength()
+{
+ return -1;
+}
+
+int AUD_SequencerReader::getPosition()
+{
+ return m_position;
+}
+
+AUD_Specs AUD_SequencerReader::getSpecs()
+{
+ return m_mixer.getSpecs().specs;
+}
+
+AUD_ReaderType AUD_SequencerReader::getType()
+{
+ return AUD_TYPE_STREAM;
+}
+
+bool AUD_SequencerReader::notify(AUD_Message &message)
+{
+ bool result = false;
+ AUD_SequencerStrip* strip;
+
+ for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
+ {
+ strip = *i;
+ if(strip->reader)
+ result |= (*i)->reader->notify(message);
+ }
+
+ return result;
+}
+
+void AUD_SequencerReader::read(int & length, sample_t* & buffer)
+{
+ AUD_DeviceSpecs specs = m_mixer.getSpecs();
+ int samplesize = AUD_SAMPLE_SIZE(specs);
+ int rate = specs.rate;
+
+ int size = length * samplesize;
+
+ int start, end, current, skip, len;
+ AUD_SequencerStrip* strip;
+ sample_t* buf;
+
+ if(m_buffer->getSize() < size)
+ m_buffer->resize(size);
+ buffer = m_buffer->getBuffer();
+
+ for(AUD_StripIterator i = m_strips.begin(); i != m_strips.end(); i++)
+ {
+ strip = *i;
+ if(!strip->entry->muted)
+ {
+ if(strip->old_sound != *strip->entry->sound)
+ {
+ strip->old_sound = *strip->entry->sound;
+ if(strip->reader)
+ {
+ delete strip->reader; AUD_DELETE("reader")
+ }
+
+ if(strip->old_sound)
+ strip->reader = m_mixer.prepare(strip->old_sound->createReader());
+ else
+ strip->reader = NULL;
+ }
+
+ if(strip->reader)
+ {
+ end = floor(strip->entry->end * rate);
+ if(m_position < end)
+ {
+ start = floor(strip->entry->begin * rate);
+ if(m_position + length > start)
+ {
+ current = m_position - start;
+ if(current < 0)
+ {
+ skip = -current;
+ current = 0;
+ }
+ else
+ skip = 0;
+ current += strip->entry->skip * rate;
+ len = length > end - m_position ? end - m_position : length;
+ len -= skip;
+ if(strip->reader->getPosition() != current)
+ strip->reader->seek(current);
+ strip->reader->read(len, buf);
+ m_mixer.add(buf, skip, len, m_volume(m_data, strip->entry->data, (float)m_position / (float)rate));
+ }
+ }
+ }
+ }
+ }
+
+ m_mixer.superpose((data_t*)buffer, length, 1.0f);
+
+ m_position += length;
+}
diff --git a/intern/audaspace/intern/AUD_SequencerReader.h b/intern/audaspace/intern/AUD_SequencerReader.h
new file mode 100644
index 00000000000..a50e1642260
--- /dev/null
+++ b/intern/audaspace/intern/AUD_SequencerReader.h
@@ -0,0 +1,102 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN LGPL LICENSE BLOCK *****
+ *
+ * Copyright 2009 Jörg Hermann Müller
+ *
+ * This file is part of AudaSpace.
+ *
+ * AudaSpace is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * AudaSpace 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with AudaSpace. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ***** END LGPL LICENSE BLOCK *****
+ */
+
+#ifndef AUD_SEQUENCERREADER
+#define AUD_SEQUENCERREADER
+
+#include "AUD_IReader.h"
+#include "AUD_SequencerFactory.h"
+#include "AUD_Mixer.h"
+
+class AUD_Buffer;
+
+struct AUD_SequencerStrip
+{
+ AUD_IFactory* old_sound;
+ AUD_IReader* reader;
+ AUD_SequencerEntry* entry;
+};
+
+/**
+ * This resampling reader uses libsamplerate for resampling.
+ */
+class AUD_SequencerReader : public AUD_IReader
+{
+private:
+ /**
+ * The current position.
+ */
+ int m_position;
+
+ /**
+ * The sound output buffer.
+ */
+ AUD_Buffer *m_buffer;
+
+ /**
+ * The target specification.
+ */
+ AUD_Mixer m_mixer;
+
+ /**
+ * Saves the SequencerFactory the reader belongs to.
+ */
+ AUD_SequencerFactory* m_factory;
+
+ std::list<AUD_SequencerStrip*> m_strips;
+
+ void* m_data;
+ AUD_volumeFunction m_volume;
+
+public:
+ /**
+ * Creates a resampling reader.
+ * \param reader The reader to mix.
+ * \param specs The target specification.
+ * \exception AUD_Exception Thrown if the reader is NULL.
+ */
+ AUD_SequencerReader(AUD_SequencerFactory* factory, std::list<AUD_SequencerEntry*> &entries, AUD_Specs specs, void* data, AUD_volumeFunction volume);
+
+ /**
+ * Destroys the reader.
+ */
+ ~AUD_SequencerReader();
+
+ void destroy();
+
+ void add(AUD_SequencerEntry* entry);
+ void remove(AUD_SequencerEntry* entry);
+
+ virtual bool isSeekable();
+ virtual void seek(int position);
+ virtual int getLength();
+ virtual int getPosition();
+ virtual AUD_Specs getSpecs();
+ virtual AUD_ReaderType getType();
+ virtual bool notify(AUD_Message &message);
+ virtual void read(int & length, sample_t* & buffer);
+};
+
+#endif //AUD_SEQUENCERREADER
diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp
index a615bcd0245..5a3f25fba07 100644
--- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp
+++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp
@@ -100,7 +100,6 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
AUD_SoftwareHandle* sound;
int len;
sample_t* buf;
- int sample_size = AUD_DEVICE_SAMPLE_SIZE(m_specs);
std::list<AUD_SoftwareHandle*> stopSounds;
// for all sounds
@@ -116,7 +115,7 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
len = length;
sound->reader->read(len, buf);
- m_mixer->add(buf, len, sound->volume);
+ m_mixer->add(buf, 0, len, sound->volume);
// in case the end of the sound is reached
if(len < length)
@@ -128,12 +127,6 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length)
}
}
- // fill with silence
- if(m_specs.format == AUD_FORMAT_U8)
- memset(buffer, 0x80, length * sample_size);
- else
- memset(buffer, 0, length * sample_size);
-
// superpose
m_mixer->superpose(buffer, length, m_volume);
diff --git a/intern/audaspace/intern/AUD_Space.h b/intern/audaspace/intern/AUD_Space.h
index 1d60be3979b..9e192ac2cac 100644
--- a/intern/audaspace/intern/AUD_Space.h
+++ b/intern/audaspace/intern/AUD_Space.h
@@ -294,7 +294,11 @@ typedef struct
union
{
// loop reader
- int loopcount;
+ struct
+ {
+ int loopcount;
+ float time;
+ };
// volume reader
float volume;
diff --git a/release/scripts/ui/properties_render.py b/release/scripts/ui/properties_render.py
index c7f8ddd052c..0eb46955a0c 100644
--- a/release/scripts/ui/properties_render.py
+++ b/release/scripts/ui/properties_render.py
@@ -416,11 +416,11 @@ class RENDER_PT_encoding(RenderButtonsPanel):
col.prop(rd, "ffmpeg_packetsize", text="Packet Size")
# Audio:
- layout.prop(rd, "ffmpeg_multiplex_audio", text="Audio")
-
sub = layout.column()
- sub.active = rd.ffmpeg_multiplex_audio
- sub.prop(rd, "ffmpeg_audio_codec", text="Codec")
+
+ if rd.ffmpeg_format not in ('MP3'):
+ sub.prop(rd, "ffmpeg_audio_codec", text="Audio Codec")
+
sub.separator()
split = sub.split()
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 0c84d729d47..49afe201c92 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -150,8 +150,8 @@ struct ImBuf *give_ibuf_seq(struct Scene *scene, int rectx, int recty, int cfra,
struct ImBuf *give_ibuf_seq_threaded(struct Scene *scene, int rectx, int recty, int cfra, int chanshown, int render_size);
struct ImBuf *give_ibuf_seq_direct(struct Scene *scene, int rectx, int recty, int cfra, int render_size, struct Sequence *seq);
void give_ibuf_prefetch_request(int rectx, int recty, int cfra, int chanshown, int render_size);
-void calc_sequence(struct Sequence *seq);
-void calc_sequence_disp(struct Sequence *seq);
+void calc_sequence(struct Scene *scene, struct Sequence *seq);
+void calc_sequence_disp(struct Scene *scene, struct Sequence *seq);
void new_tstripdata(struct Sequence *seq);
void reload_sequence_new_file(struct Scene *scene, struct Sequence * seq);
void sort_seq(struct Scene *scene);
@@ -191,8 +191,8 @@ int shuffle_seq_time(ListBase * seqbasep, struct Scene *evil_scene);
int seqbase_isolated_sel_check(struct ListBase *seqbase);
void free_imbuf_seq(struct Scene *scene, struct ListBase * seqbasep, int check_mem_usage);
-void seq_update_sound(struct Sequence *seq);
-void seq_update_muting(struct Editing *ed);
+void seq_update_sound(struct Scene* scene, struct Sequence *seq);
+void seq_update_muting(struct Scene* scene, struct Editing *ed);
void seqbase_sound_reload(Scene *scene, ListBase *seqbase);
void clear_scene_in_allseqs(struct Scene *sce);
diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h
index 82ef525ba91..1c9a7db03c3 100644
--- a/source/blender/blenkernel/BKE_sound.h
+++ b/source/blender/blenkernel/BKE_sound.h
@@ -36,6 +36,7 @@ struct bSound;
struct bContext;
struct ListBase;
struct Main;
+struct Sequence;
void sound_init();
@@ -63,20 +64,28 @@ void sound_load(struct Main *main, struct bSound* sound);
void sound_free(struct bSound* sound);
-void sound_unlink(struct bContext *C, struct bSound* sound);
+#ifdef AUD_CAPI
+AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
+#endif
-struct SoundHandle* sound_new_handle(struct Scene *scene, struct bSound* sound, int startframe, int endframe, int frameskip);
+void sound_create_scene(struct Scene *scene);
-void sound_delete_handle(struct Scene *scene, struct SoundHandle *handle);
+void sound_destroy_scene(struct Scene *scene);
-void sound_update_playing(struct bContext *C);
+void* sound_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip);
-void sound_scrub(struct bContext *C);
+void sound_remove_scene_sound(struct Scene *scene, void* handle);
-#ifdef AUD_CAPI
-AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, int end, float volume);
-#endif
+void sound_mute_scene_sound(struct Scene *scene, void* handle, char mute);
+
+void sound_move_scene_sound(struct Scene *scene, void* handle, int startframe, int endframe, int frameskip);
+
+void sound_play_scene(struct Scene *scene);
+
+void sound_stop_scene(struct Scene *scene);
+
+void sound_seek_scene(struct bContext *C);
-void sound_stop_all(struct bContext *C);
+int sound_read_sound_buffer(struct bSound* sound, float* buffer, int length);
#endif
diff --git a/source/blender/blenkernel/BKE_writeffmpeg.h b/source/blender/blenkernel/BKE_writeffmpeg.h
index 98c385ea2e1..20c5b2fd46f 100644
--- a/source/blender/blenkernel/BKE_writeffmpeg.h
+++ b/source/blender/blenkernel/BKE_writeffmpeg.h
@@ -45,6 +45,8 @@ extern "C" {
#define FFMPEG_FLV 8
#define FFMPEG_MKV 9
#define FFMPEG_OGG 10
+#define FFMPEG_WAV 11
+#define FFMPEG_MP3 12
#define FFMPEG_PRESET_NONE 0
#define FFMPEG_PRESET_DVD 1
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index b80f22a05c2..780ded2a941 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -83,6 +83,7 @@
#include "BKE_sequencer.h"
#include "BKE_world.h"
#include "BKE_utildefines.h"
+#include "BKE_sound.h"
//XXX #include "BIF_previewrender.h"
//XXX #include "BIF_editseq.h"
@@ -233,6 +234,8 @@ Scene *copy_scene(Main *bmain, Scene *sce, int type)
}
}
+ sound_create_scene(scen);
+
return scen;
}
@@ -315,6 +318,8 @@ void free_scene(Scene *sce)
if(sce->stats)
MEM_freeN(sce->stats);
+
+ sound_destroy_scene(sce);
}
Scene *add_scene(char *name)
@@ -480,6 +485,8 @@ Scene *add_scene(char *name)
sce->gm.flag = GAME_DISPLAY_LISTS;
sce->gm.matmode = GAME_MAT_MULTITEX;
+ sound_create_scene(sce);
+
return sce;
}
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 9fde0730011..8c119eb753b 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -233,8 +233,8 @@ void seq_free_sequence(Scene *scene, Sequence *seq)
if (ed->act_seq==seq)
ed->act_seq= NULL;
- if(seq->sound_handle)
- sound_delete_handle(scene, seq->sound_handle);
+ if(seq->scene_sound)
+ sound_remove_scene_sound(scene, seq->scene_sound);
}
MEM_freeN(seq);
@@ -484,7 +484,7 @@ void build_seqar_cb(ListBase *seqbase, Sequence ***seqar, int *totseq,
}
-void calc_sequence_disp(Sequence *seq)
+void calc_sequence_disp(Scene *scene, Sequence *seq)
{
if(seq->startofs && seq->startstill) seq->startstill= 0;
if(seq->endofs && seq->endstill) seq->endstill= 0;
@@ -500,10 +500,10 @@ void calc_sequence_disp(Sequence *seq)
seq->handsize= (float)((seq->enddisp-seq->startdisp)/25);
}
- seq_update_sound(seq);
+ seq_update_sound(scene, seq);
}
-void calc_sequence(Sequence *seq)
+void calc_sequence(Scene *scene, Sequence *seq)
{
Sequence *seqm;
int min, max;
@@ -511,7 +511,7 @@ void calc_sequence(Sequence *seq)
/* check all metas recursively */
seqm= seq->seqbase.first;
while(seqm) {
- if(seqm->seqbase.first) calc_sequence(seqm);
+ if(seqm->seqbase.first) calc_sequence(scene, seqm);
seqm= seqm->next;
}
@@ -534,7 +534,7 @@ void calc_sequence(Sequence *seq)
seq->enddisp= MIN3(seq->seq1->enddisp, seq->seq2->enddisp, seq->seq3->enddisp);
seq->len= seq->enddisp - seq->startdisp;
} else {
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
}
if(seq->strip && seq->len!=seq->strip->len) {
@@ -563,7 +563,7 @@ void calc_sequence(Sequence *seq)
}
}
}
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
}
}
@@ -614,7 +614,7 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq)
}
seq->strip->len = seq->len;
} else if (seq->type == SEQ_SOUND) {
- seq->len = AUD_getInfo(seq->sound->handle).length * FPS;
+ seq->len = AUD_getInfo(seq->sound->playback_handle).length * FPS;
seq->len -= seq->anim_startofs;
seq->len -= seq->anim_endofs;
if (seq->len < 0) {
@@ -653,7 +653,7 @@ void reload_sequence_new_file(Scene *scene, Sequence * seq)
free_proxy_seq(seq);
- calc_sequence(seq);
+ calc_sequence(scene, seq);
}
void sort_seq(Scene *scene)
@@ -3189,7 +3189,7 @@ static int update_changed_seq_recurs(Scene *scene, Sequence *seq, Sequence *chan
}
if(len_change)
- calc_sequence(seq);
+ calc_sequence(scene, seq);
}
return free_imbuf;
@@ -3239,23 +3239,6 @@ static void free_imbuf_seq_with_ipo(Scene *scene, struct Ipo *ipo)
}
#endif
-static int seq_sound_reload_cb(Sequence *seq, void *arg_pt)
-{
- if (seq->type==SEQ_SOUND && seq->sound) {
- Scene *scene= (Scene *)arg_pt;
- if(seq->sound_handle)
- sound_delete_handle(scene, seq->sound_handle);
-
- seq->sound_handle = sound_new_handle(scene, seq->sound, seq->start, seq->start + seq->strip->len, 0);
- return 0;
- }
- return 1; /* recurse meta's */
-}
-void seqbase_sound_reload(Scene *scene, ListBase *seqbase)
-{
- seqbase_recursive_apply(seqbase, seq_sound_reload_cb, (void *)scene);
-}
-
/* seq funcs's for transforming internally
notice the difference between start/end and left/right.
@@ -3463,7 +3446,7 @@ static void seq_translate(Scene *evil_scene, Sequence *seq, int delta)
}
}
- calc_sequence_disp(seq);
+ calc_sequence_disp(evil_scene, seq);
}
/* return 0 if there werent enough space */
@@ -3471,13 +3454,13 @@ int shuffle_seq(ListBase * seqbasep, Sequence *test, Scene *evil_scene)
{
int orig_machine= test->machine;
test->machine++;
- calc_sequence(test);
+ calc_sequence(evil_scene, test);
while( seq_test_overlap(seqbasep, test) ) {
if(test->machine >= MAXSEQ) {
break;
}
test->machine++;
- calc_sequence(test); // XXX - I dont think this is needed since were only moving vertically, Campbell.
+ calc_sequence(evil_scene, test); // XXX - I dont think this is needed since were only moving vertically, Campbell.
}
@@ -3497,7 +3480,7 @@ int shuffle_seq(ListBase * seqbasep, Sequence *test, Scene *evil_scene)
new_frame = new_frame + (test->start-test->startdisp); /* adjust by the startdisp */
seq_translate(evil_scene, test, new_frame - test->start);
- calc_sequence(test);
+ calc_sequence(evil_scene, test);
return 0;
} else {
return 1;
@@ -3526,7 +3509,7 @@ static int shuffle_seq_time_offset_test(ListBase * seqbasep, char dir)
return offset;
}
-static int shuffle_seq_time_offset(ListBase * seqbasep, char dir)
+static int shuffle_seq_time_offset(Scene* scene, ListBase * seqbasep, char dir)
{
int ofs= 0;
int tot_ofs= 0;
@@ -3545,7 +3528,7 @@ static int shuffle_seq_time_offset(ListBase * seqbasep, char dir)
for(seq= seqbasep->first; seq; seq= seq->next) {
if(seq->tmp)
- calc_sequence_disp(seq); /* corrects dummy startdisp/enddisp values */
+ calc_sequence_disp(scene, seq); /* corrects dummy startdisp/enddisp values */
}
return tot_ofs;
@@ -3557,8 +3540,8 @@ int shuffle_seq_time(ListBase * seqbasep, Scene *evil_scene)
Sequence *seq;
- int offset_l = shuffle_seq_time_offset(seqbasep, 'L');
- int offset_r = shuffle_seq_time_offset(seqbasep, 'R');
+ int offset_l = shuffle_seq_time_offset(evil_scene, seqbasep, 'L');
+ int offset_r = shuffle_seq_time_offset(evil_scene, seqbasep, 'R');
int offset = (-offset_l < offset_r) ? offset_l:offset_r;
if(offset) {
@@ -3573,19 +3556,16 @@ int shuffle_seq_time(ListBase * seqbasep, Scene *evil_scene)
return offset? 0:1;
}
-void seq_update_sound(Sequence *seq)
+void seq_update_sound(Scene* scene, Sequence *seq)
{
- if(seq->type == SEQ_SOUND && seq->sound_handle)
+ if(seq->scene_sound)
{
- seq->sound_handle->startframe = seq->startdisp;
- seq->sound_handle->endframe = seq->enddisp;
- seq->sound_handle->frameskip = seq->startofs + seq->anim_startofs;
- seq->sound_handle->changed = -1;
+ sound_move_scene_sound(scene, seq->scene_sound, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs);
/* mute is set in seq_update_muting_recursive */
}
}
-static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, int mute)
+static void seq_update_muting_recursive(Scene *scene, ListBase *seqbasep, Sequence *metaseq, int mute)
{
Sequence *seq;
int seqmute;
@@ -3601,27 +3581,26 @@ static void seq_update_muting_recursive(ListBase *seqbasep, Sequence *metaseq, i
if(seq == metaseq)
seqmute= 0;
- seq_update_muting_recursive(&seq->seqbase, metaseq, seqmute);
+ seq_update_muting_recursive(scene, &seq->seqbase, metaseq, seqmute);
}
else if(seq->type == SEQ_SOUND) {
- if(seq->sound_handle && seqmute != seq->sound_handle->mute) {
- seq->sound_handle->mute = seqmute;
- seq->sound_handle->changed = -1;
+ if(seq->scene_sound) {
+ sound_mute_scene_sound(scene, seq->scene_sound, seqmute);
}
}
}
}
-void seq_update_muting(Editing *ed)
+void seq_update_muting(Scene *scene, Editing *ed)
{
if(ed) {
/* mute all sounds up to current metastack list */
MetaStack *ms= ed->metastack.last;
if(ms)
- seq_update_muting_recursive(&ed->seqbase, ms->parseq, 1);
+ seq_update_muting_recursive(scene, &ed->seqbase, ms->parseq, 1);
else
- seq_update_muting_recursive(&ed->seqbase, NULL, 0);
+ seq_update_muting_recursive(scene, &ed->seqbase, NULL, 0);
}
}
@@ -3744,6 +3723,7 @@ Sequence *alloc_sequence(ListBase *lb, int cfra, int machine)
seq->machine= machine;
seq->mul= 1.0;
seq->blend_opacity = 100.0;
+ seq->volume = 1.0f;
return seq;
}
@@ -3793,13 +3773,13 @@ Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
sound = sound_new_file(CTX_data_main(C), seq_load->path);
- if (sound==NULL || sound->handle == NULL) {
+ if (sound==NULL || sound->playback_handle == NULL) {
//if(op)
// BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return NULL;
}
- info = AUD_getInfo(sound->handle);
+ info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
sound_delete(C, sound);
@@ -3824,9 +3804,9 @@ Sequence *sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
BLI_split_dirfile_basic(seq_load->path, strip->dir, se->name);
- seq->sound_handle = sound_new_handle(scene, sound, seq_load->start_frame, seq_load->start_frame + strip->len, 0);
+ seq->scene_sound = sound_add_scene_sound(scene, seq, seq_load->start_frame, seq_load->start_frame + strip->len, 0);
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
/* last active name */
strncpy(ed->act_sounddir, strip->dir, FILE_MAXDIR-1);
@@ -3868,7 +3848,7 @@ Sequence *sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoadInfo
BLI_split_dirfile_basic(seq_load->path, strip->dir, se->name);
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
if(seq_load->flag & SEQ_LOAD_MOVIE_SOUND) {
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 1be59529cc7..7b451bd5a98 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -12,6 +12,7 @@
#include "BLI_blenlib.h"
#include "DNA_scene_types.h"
+#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_screen_types.h"
@@ -26,6 +27,9 @@
#include "BKE_context.h"
#include "BKE_library.h"
#include "BKE_packedFile.h"
+#include "BKE_fcurve.h"
+
+#include "RNA_access.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
@@ -107,7 +111,7 @@ struct bSound* sound_new_file(struct Main *main, char* filename)
sound_load(main, sound);
- if(!sound->handle)
+ if(!sound->playback_handle)
{
free_libblock(&main->sound, sound);
sound = NULL;
@@ -133,7 +137,7 @@ struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source)
sound_load(CTX_data_main(C), sound);
- if(!sound->handle)
+ if(!sound->playback_handle)
{
free_libblock(&CTX_data_main(C)->sound, sound);
sound = NULL;
@@ -159,7 +163,7 @@ struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, floa
sound_load(CTX_data_main(C), sound);
- if(!sound->handle)
+ if(!sound->playback_handle)
{
free_libblock(&CTX_data_main(C)->sound, sound);
sound = NULL;
@@ -175,8 +179,6 @@ void sound_delete(struct bContext *C, struct bSound* sound)
{
sound_free(sound);
- sound_unlink(C, sound);
-
free_libblock(&CTX_data_main(C)->sound, sound);
}
}
@@ -187,7 +189,7 @@ void sound_cache(struct bSound* sound, int ignore)
AUD_unload(sound->cache);
sound->cache = AUD_bufferSound(sound->handle);
- sound->changed++;
+ sound->playback_handle = sound->cache;
}
void sound_delete_cache(struct bSound* sound)
@@ -196,6 +198,7 @@ void sound_delete_cache(struct bSound* sound)
{
AUD_unload(sound->cache);
sound->cache = NULL;
+ sound->playback_handle = sound->handle;
}
}
@@ -207,6 +210,7 @@ void sound_load(struct Main *main, struct bSound* sound)
{
AUD_unload(sound->handle);
sound->handle = NULL;
+ sound->playback_handle = NULL;
}
// XXX unused currently
@@ -253,7 +257,10 @@ void sound_load(struct Main *main, struct bSound* sound)
break;
}
#endif
- sound->changed++;
+ if(sound->cache)
+ sound->playback_handle = sound->cache;
+ else
+ sound->playback_handle = sound->handle;
}
}
@@ -269,243 +276,115 @@ void sound_free(struct bSound* sound)
{
AUD_unload(sound->handle);
sound->handle = NULL;
+ sound->playback_handle = NULL;
}
}
-void sound_unlink(struct bContext *C, struct bSound* sound)
+static float sound_get_volume(Scene* scene, Sequence* sequence, float time)
{
- Scene *scene;
- SoundHandle *handle;
-
-// XXX unused currently
-#if 0
- bSound *snd;
- for(snd = CTX_data_main(C)->sound.first; snd; snd = snd->id.next)
- {
- if(snd->child_sound == sound)
- {
- snd->child_sound = NULL;
- if(snd->handle)
- {
- AUD_unload(sound->handle);
- snd->handle = NULL;
- }
-
- sound_unlink(C, snd);
- }
- }
-#endif
-
- for(scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next)
- {
- for(handle = scene->sound_handles.first; handle; handle = handle->next)
- {
- if(handle->source == sound)
- {
- handle->source = NULL;
- if(handle->handle)
- AUD_stop(handle->handle);
- }
- }
- }
+ struct FCurve* fcu = id_data_find_fcurve(scene, sequence, &RNA_Sequence, "volume", 0);
+ if(fcu)
+ return evaluate_fcurve(fcu, time * FPS);
+ else
+ return sequence->volume;
}
-struct SoundHandle* sound_new_handle(struct Scene *scene, struct bSound* sound, int startframe, int endframe, int frameskip)
+AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
{
- ListBase* handles = &scene->sound_handles;
+ AUD_Device* mixdown = AUD_openReadDevice(specs);
+
+ AUD_setDeviceVolume(mixdown, volume);
- SoundHandle* handle = MEM_callocN(sizeof(SoundHandle), "sound_handle");
- handle->source = sound;
- handle->startframe = startframe;
- handle->endframe = endframe;
- handle->frameskip = frameskip;
- handle->state = AUD_STATUS_INVALID;
- handle->volume = 1.0f;
+ AUD_playDevice(mixdown, scene->sound_scene, start / FPS);
- BLI_addtail(handles, handle);
+ return mixdown;
+}
- return handle;
+void sound_create_scene(struct Scene *scene)
+{
+ scene->sound_scene = AUD_createSequencer(scene, (AUD_volumeFunction)&sound_get_volume);
}
-void sound_delete_handle(struct Scene *scene, struct SoundHandle *handle)
+void sound_destroy_scene(struct Scene *scene)
{
- if(handle == NULL)
- return;
+ if(scene->sound_scene_handle)
+ AUD_stop(scene->sound_scene_handle);
+ if(scene->sound_scene)
+ AUD_destroySequencer(scene->sound_scene);
+}
- if(handle->handle)
- AUD_stop(handle->handle);
+void* sound_add_scene_sound(struct Scene *scene, struct Sequence* sequence, int startframe, int endframe, int frameskip)
+{
+ return AUD_addSequencer(scene->sound_scene, &(sequence->sound->playback_handle), startframe / FPS, endframe / FPS, frameskip / FPS, sequence);
+}
- BLI_freelinkN(&scene->sound_handles, handle);
+void sound_remove_scene_sound(struct Scene *scene, void* handle)
+{
+ AUD_removeSequencer(scene->sound_scene, handle);
}
-void sound_stop_all(struct bContext *C)
+void sound_mute_scene_sound(struct Scene *scene, void* handle, char mute)
{
- SoundHandle *handle;
+ AUD_muteSequencer(scene->sound_scene, handle, mute);
+}
- for(handle = CTX_data_scene(C)->sound_handles.first; handle; handle = handle->next)
- {
- if(handle->state == AUD_STATUS_PLAYING)
- {
- AUD_pause(handle->handle);
- handle->state = AUD_STATUS_PAUSED;
- }
- }
+void sound_move_scene_sound(struct Scene *scene, void* handle, int startframe, int endframe, int frameskip)
+{
+ AUD_moveSequencer(scene->sound_scene, handle, startframe / FPS, endframe / FPS, frameskip / FPS);
}
-void sound_update_playing(struct bContext *C)
+void sound_start_play_scene(struct Scene *scene)
{
- SoundHandle *handle;
- Scene* scene = CTX_data_scene(C);
- int cfra = CFRA;
- float fps = FPS;
- int action;
+ AUD_Sound* sound;
+ sound = AUD_loopSound(scene->sound_scene);
+ scene->sound_scene_handle = AUD_play(sound, 1);
+ AUD_unload(sound);
+}
+void sound_play_scene(struct Scene *scene)
+{
AUD_lock();
- for(handle = scene->sound_handles.first; handle; handle = handle->next)
- {
- if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute || (scene->audio.flag & AUDIO_MUTE))
- {
- if(handle->state == AUD_STATUS_PLAYING)
- {
- AUD_pause(handle->handle);
- handle->state = AUD_STATUS_PAUSED;
- }
- }
- else
- {
- action = 0;
-
- if(handle->changed != handle->source->changed)
- {
- handle->changed = handle->source->changed;
- action = 3;
- if(handle->state != AUD_STATUS_INVALID)
- {
- AUD_stop(handle->handle);
- handle->state = AUD_STATUS_INVALID;
- }
- }
- else
- {
- if(handle->state != AUD_STATUS_PLAYING)
- action = 3;
- else
- {
- handle->state = AUD_getStatus(handle->handle);
- if(handle->state != AUD_STATUS_PLAYING)
- action = 3;
- else
- {
- float diff = AUD_getPosition(handle->handle) * fps - cfra + handle->startframe;
- if(diff < 0.0)
- diff = -diff;
- if(diff > FPS/2.0)
- {
- action = 2;
- }
- }
- }
- }
-
- AUD_setSoundVolume(handle->handle, handle->volume);
-
- if(action & 1)
- {
- if(handle->state == AUD_STATUS_INVALID)
- {
- if(handle->source && handle->source->handle)
- {
- AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->handle, handle->frameskip / fps, (handle->frameskip + handle->endframe - handle->startframe)/fps);
- handle->handle = AUD_play(limiter, 1);
- AUD_unload(limiter);
- if(handle->handle)
- handle->state = AUD_STATUS_PLAYING;
- if(cfra == handle->startframe)
- action &= ~2;
- }
- }
- else
- if(AUD_resume(handle->handle))
- handle->state = AUD_STATUS_PLAYING;
- else
- handle->state = AUD_STATUS_INVALID;
- }
-
- if(action & 2)
- AUD_seek(handle->handle, (cfra - handle->startframe) / fps);
- }
- }
+ if(!scene->sound_scene_handle || AUD_getStatus(scene->sound_scene_handle) == AUD_STATUS_INVALID)
+ sound_start_play_scene(scene);
+
+ AUD_seek(scene->sound_scene_handle, CFRA / FPS);
+ AUD_setLoop(scene->sound_scene_handle, -1, -1);
+ AUD_resume(scene->sound_scene_handle);
AUD_unlock();
}
-void sound_scrub(struct bContext *C)
+void sound_stop_scene(struct Scene *scene)
{
- SoundHandle *handle;
- Scene* scene = CTX_data_scene(C);
- int cfra = CFRA;
- float fps = FPS;
-
- if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer)
- {
- AUD_lock();
-
- for(handle = scene->sound_handles.first; handle; handle = handle->next)
- {
- if(cfra >= handle->startframe && cfra < handle->endframe && !handle->mute)
- {
- if(handle->source && handle->source->handle)
- {
- int frameskip = handle->frameskip + cfra - handle->startframe;
- AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->handle, frameskip / fps, (frameskip + 1)/fps);
- AUD_play(limiter, 0);
- AUD_unload(limiter);
- }
- }
- }
-
- AUD_unlock();
- }
+ AUD_pause(scene->sound_scene_handle);
}
-AUD_Device* sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, int end, float volume)
+void sound_seek_scene(struct bContext *C)
{
- AUD_Device* mixdown = AUD_openReadDevice(specs);
- SoundHandle *handle;
- float fps = FPS;
- AUD_Sound *limiter, *delayer;
- int frameskip, s, e;
+ struct Scene *scene = CTX_data_scene(C);
- end++;
+ AUD_lock();
- AUD_setDeviceVolume(mixdown, volume);
+ if(!scene->sound_scene_handle || AUD_getStatus(scene->sound_scene_handle) == AUD_STATUS_INVALID)
+ {
+ sound_start_play_scene(scene);
+ AUD_pause(scene->sound_scene_handle);
+ }
- for(handle = scene->sound_handles.first; handle; handle = handle->next)
+ if(scene->audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer)
{
- if(start < handle->endframe && end > handle->startframe && !handle->mute && handle->source && handle->source->handle)
- {
- frameskip = handle->frameskip;
- s = handle->startframe - start;
- e = handle->frameskip + AUD_MIN(handle->endframe, end) - handle->startframe;
-
- if(s < 0)
- {
- frameskip -= s;
- s = 0;
- }
-
- AUD_setSoundVolume(handle->handle, handle->volume);
-
- limiter = AUD_limitSound(handle->source->handle, frameskip / fps, e / fps);
- delayer = AUD_delaySound(limiter, s / fps);
-
- AUD_playDevice(mixdown, delayer);
-
- AUD_unload(delayer);
- AUD_unload(limiter);
- }
+ AUD_setLoop(scene->sound_scene_handle, -1, 1 / FPS);
+ AUD_seek(scene->sound_scene_handle, CFRA / FPS);
+ AUD_resume(scene->sound_scene_handle);
}
+ else
+ AUD_seek(scene->sound_scene_handle, CFRA / FPS);
- return mixdown;
+ AUD_unlock();
+}
+
+int sound_read_sound_buffer(bSound* sound, float* buffer, int length)
+{
+ AUD_readSound(sound->cache, buffer, length);
}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 9c38f84aa26..3aca9ffb4e7 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -15,7 +15,6 @@
*
*/
-
#ifdef WITH_FFMPEG
#include <string.h>
#include <stdio.h>
@@ -78,11 +77,10 @@ extern void do_init_ffmpeg();
static int ffmpeg_type = 0;
static int ffmpeg_codec = CODEC_ID_MPEG4;
-static int ffmpeg_audio_codec = CODEC_ID_MP2;
+static int ffmpeg_audio_codec = CODEC_ID_NONE;
static int ffmpeg_video_bitrate = 1150;
static int ffmpeg_audio_bitrate = 128;
static int ffmpeg_gop_size = 12;
-static int ffmpeg_multiplex_audio = 1;
static int ffmpeg_autosplit = 0;
static int ffmpeg_autosplit_count = 0;
@@ -99,6 +97,7 @@ static uint8_t* audio_input_buffer = 0;
static int audio_input_frame_size = 0;
static uint8_t* audio_output_buffer = 0;
static int audio_outbuf_size = 0;
+static double audio_time = 0.0f;
static AUD_Device* audio_mixdown_device = 0;
@@ -130,30 +129,43 @@ static int write_audio_frame(void)
{
AVCodecContext* c = NULL;
AVPacket pkt;
+ AVStream* str = audio_stream;
c = get_codec_from_stream(audio_stream);
- if(audio_mixdown_device)
- AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_frame_size);
-
av_init_packet(&pkt);
+ pkt.size = 0;
+
+ AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_frame_size);
+ audio_time += (double) audio_input_frame_size / (double) c->sample_rate;
pkt.size = avcodec_encode_audio(c, audio_output_buffer,
- audio_outbuf_size,
+ audio_outbuf_size,
(short*) audio_input_buffer);
+
+ if(pkt.size <= 0)
+ {
+ // XXX error("Error writing audio packet");
+ return -1;
+ }
+
pkt.data = audio_output_buffer;
+
+ if(c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)
+ {
#ifdef FFMPEG_CODEC_TIME_BASE
- pkt.pts = av_rescale_q(c->coded_frame->pts,
- c->time_base, audio_stream->time_base);
+ pkt.pts = av_rescale_q(c->coded_frame->pts,
+ c->time_base, audio_stream->time_base);
#else
- pkt.pts = c->coded_frame->pts;
+ pkt.pts = c->coded_frame->pts;
#endif
- fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts);
+ fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts);
+ }
pkt.stream_index = audio_stream->index;
pkt.flags |= PKT_FLAG_KEY;
if (av_interleaved_write_frame(outfile, &pkt) != 0) {
- //XXX error("Error writing audio packet");
+ // XXX error("Error writing audio packet");
return -1;
}
return 0;
@@ -233,6 +245,14 @@ static const char** get_file_extensions(int format)
static const char * rv[] = { ".ogg", ".ogv", NULL };
return rv;
}
+ case FFMPEG_MP3: {
+ static const char * rv[] = { ".mp3", NULL };
+ return rv;
+ }
+ case FFMPEG_WAV: {
+ static const char * rv[] = { ".wav", NULL };
+ return rv;
+ }
default:
return NULL;
}
@@ -563,6 +583,7 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
c->sample_rate = rd->ffcodecdata.audio_mixrate;
c->bit_rate = ffmpeg_audio_bitrate*1000;
+ c->sample_fmt = SAMPLE_FMT_S16;
c->channels = 2;
codec = avcodec_find_encoder(c->codec_id);
if (!codec) {
@@ -577,40 +598,22 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
return NULL;
}
- /* FIXME: Should be user configurable */
- if (ffmpeg_type == FFMPEG_DV) {
- /* this is a hack around the poor ffmpeg dv multiplexer. */
- /* only fixes PAL for now
- (NTSC is a lot more complicated here...)! */
- audio_outbuf_size = 7680;
- } else {
- audio_outbuf_size = 10000;
- }
+ audio_outbuf_size = FF_MIN_BUFFER_SIZE;
+
audio_output_buffer = (uint8_t*)MEM_mallocN(
audio_outbuf_size, "FFMPEG audio encoder input buffer");
- /* ugly hack for PCM codecs */
-
- if (c->frame_size <= 1) {
- audio_input_frame_size = audio_outbuf_size / c->channels;
- switch(c->codec_id) {
- case CODEC_ID_PCM_S16LE:
- case CODEC_ID_PCM_S16BE:
- case CODEC_ID_PCM_U16LE:
- case CODEC_ID_PCM_U16BE:
- audio_input_frame_size >>= 1;
- break;
- default:
- break;
- }
- } else {
+ if((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
+ audio_input_frame_size = audio_outbuf_size * 8 / c->bits_per_coded_sample / c->channels;
+ else
audio_input_frame_size = c->frame_size;
- }
audio_input_buffer = (uint8_t*)MEM_mallocN(
- audio_input_frame_size * sizeof(short) * c->channels,
+ audio_input_frame_size * c->channels * sizeof(int16_t),
"FFMPEG audio encoder output buffer");
+ audio_time = 0.0f;
+
return st;
}
/* essential functions -- start, append, end */
@@ -629,8 +632,6 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
ffmpeg_gop_size = rd->ffcodecdata.gop_size;
- ffmpeg_multiplex_audio = rd->ffcodecdata.flags
- & FFMPEG_MULTIPLEX_AUDIO;
ffmpeg_autosplit = rd->ffcodecdata.flags
& FFMPEG_AUTOSPLIT_OUTPUT;
@@ -641,12 +642,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
fprintf(stderr, "Starting output to %s(ffmpeg)...\n"
" Using type=%d, codec=%d, audio_codec=%d,\n"
" video_bitrate=%d, audio_bitrate=%d,\n"
- " gop_size=%d, multiplex=%d, autosplit=%d\n"
+ " gop_size=%d, autosplit=%d\n"
" render width=%d, render height=%d\n",
name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
- ffmpeg_gop_size, ffmpeg_multiplex_audio,
- ffmpeg_autosplit, rectx, recty);
+ ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty);
exts = get_file_extensions(ffmpeg_type);
if (!exts) {
@@ -667,7 +667,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->oformat = fmt;
of->packet_size= rd->ffcodecdata.mux_packet_size;
- if (ffmpeg_multiplex_audio) {
+ if (ffmpeg_audio_codec != CODEC_ID_NONE) {
of->mux_rate = rd->ffcodecdata.mux_rate;
} else {
of->mux_rate = 0;
@@ -676,6 +676,8 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
of->preload = (int)(0.5*AV_TIME_BASE);
of->max_delay = (int)(0.7*AV_TIME_BASE);
+ fmt->audio_codec = ffmpeg_audio_codec;
+
snprintf(of->filename, sizeof(of->filename), "%s", name);
/* set the codec to the user's selection */
switch(ffmpeg_type) {
@@ -703,6 +705,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
case FFMPEG_FLV:
fmt->video_codec = CODEC_ID_FLV1;
break;
+ case FFMPEG_MP3:
+ fmt->audio_codec = CODEC_ID_MP3;
+ case FFMPEG_WAV:
+ fmt->video_codec = CODEC_ID_NONE;
+ break;
case FFMPEG_MPEG4:
default:
fmt->video_codec = CODEC_ID_MPEG4;
@@ -723,30 +730,29 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
}
}
- fmt->audio_codec = ffmpeg_audio_codec;
-
if (ffmpeg_type == FFMPEG_DV) {
fmt->audio_codec = CODEC_ID_PCM_S16LE;
- if (ffmpeg_multiplex_audio && rd->ffcodecdata.audio_mixrate != 48000) {
+ if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000) {
BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
return 0;
}
}
- video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty);
- printf("alloc video stream %p\n", video_stream);
- if (!video_stream) {
- BKE_report(reports, RPT_ERROR, "Error initializing video stream.");
- return 0;
+ if (fmt->video_codec != CODEC_ID_NONE) {
+ video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty);
+ printf("alloc video stream %p\n", video_stream);
+ if (!video_stream) {
+ BKE_report(reports, RPT_ERROR, "Error initializing video stream.");
+ return 0;
+ }
}
-
- if (ffmpeg_multiplex_audio) {
+
+ if (ffmpeg_audio_codec != CODEC_ID_NONE) {
audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of);
if (!audio_stream) {
BKE_report(reports, RPT_ERROR, "Error initializing audio stream.");
return 0;
}
- //XXX audiostream_play(SFRA, 0, 1);
}
if (av_set_parameters(of, NULL) < 0) {
BKE_report(reports, RPT_ERROR, "Error setting output parameters.");
@@ -818,14 +824,14 @@ int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, Repo
success = start_ffmpeg_impl(rd, rectx, recty, reports);
- if(ffmpeg_multiplex_audio && audio_stream)
+ if(audio_stream)
{
AVCodecContext* c = get_codec_from_stream(audio_stream);
AUD_DeviceSpecs specs;
specs.channels = c->channels;
specs.format = AUD_FORMAT_S16;
specs.rate = rd->ffcodecdata.audio_mixrate;
- audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra, rd->ffcodecdata.audio_volume);
+ audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume);
}
return success;
@@ -833,21 +839,13 @@ int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, Repo
void end_ffmpeg(void);
-static void write_audio_frames()
+static void write_audio_frames(double to_pts)
{
int finished = 0;
- while (ffmpeg_multiplex_audio && !finished) {
- double a_pts = ((double)audio_stream->pts.val
- * audio_stream->time_base.num
- / audio_stream->time_base.den);
- double v_pts = ((double)video_stream->pts.val
- * video_stream->time_base.num
- / video_stream->time_base.den);
-
- if (a_pts < v_pts) {
- write_audio_frame();
- } else {
+ while (audio_stream && !finished) {
+ if((audio_time >= to_pts) ||
+ (write_audio_frame())) {
finished = 1;
}
}
@@ -856,25 +854,31 @@ static void write_audio_frames()
int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports)
{
AVFrame* avframe;
- int success;
+ int success = 1;
fprintf(stderr, "Writing frame %i, "
"render width=%d, render height=%d\n", frame,
rectx, recty);
- write_audio_frames();
+// why is this done before writing the video frame and again at end_ffmpeg?
+// write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
- avframe= generate_video_frame((unsigned char*) pixels, reports);
- success= (avframe && write_video_frame(rd, avframe, reports));
-
- if (ffmpeg_autosplit) {
- if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) {
- end_ffmpeg();
- ffmpeg_autosplit_count++;
- success &= start_ffmpeg_impl(rd, rectx, recty, reports);
+ if(video_stream)
+ {
+ avframe= generate_video_frame((unsigned char*) pixels, reports);
+ success= (avframe && write_video_frame(rd, avframe, reports));
+
+ if (ffmpeg_autosplit) {
+ if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) {
+ end_ffmpeg();
+ ffmpeg_autosplit_count++;
+ success &= start_ffmpeg_impl(rd, rectx, recty, reports);
+ }
}
}
+ write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
+
return success;
}
@@ -885,9 +889,9 @@ void end_ffmpeg(void)
fprintf(stderr, "Closing ffmpeg...\n");
- if (audio_stream && video_stream) {
+/* if (audio_stream) { SEE UPPER
write_audio_frames();
- }
+ }*/
if(audio_mixdown_device)
{
@@ -1259,8 +1263,8 @@ void ffmpeg_verify_image_type(RenderData *rd)
}
}
- if(audio && rd->ffcodecdata.audio_codec <= 0) {
- rd->ffcodecdata.audio_codec = CODEC_ID_MP2;
+ if(audio && rd->ffcodecdata.audio_codec < 0) {
+ rd->ffcodecdata.audio_codec = CODEC_ID_NONE;
rd->ffcodecdata.audio_bitrate = 128;
}
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index ed551e56fe9..5938f9e6e2a 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -4138,14 +4138,14 @@ static void lib_link_scene(FileData *fd, Main *main)
if(seq->ipo) seq->ipo= newlibadr_us(fd, sce->id.lib, seq->ipo);
if(seq->scene) seq->scene= newlibadr(fd, sce->id.lib, seq->scene);
if(seq->sound) {
- seq->sound_handle= NULL;
+ seq->scene_sound = NULL;
if(seq->type == SEQ_HD_SOUND)
seq->type = SEQ_SOUND;
else
seq->sound= newlibadr(fd, sce->id.lib, seq->sound);
if (seq->sound) {
seq->sound->id.us++;
- seq->sound_handle= sound_new_handle(sce, seq->sound, seq->startdisp, seq->enddisp, seq->startofs);
+ seq->scene_sound = sound_add_scene_sound(sce, seq, seq->startdisp, seq->enddisp, seq->startofs);
}
}
seq->anim= 0;
@@ -4161,7 +4161,7 @@ static void lib_link_scene(FileData *fd, Main *main)
#endif
if(sce->ed)
- seq_update_muting(sce->ed);
+ seq_update_muting(sce, sce->ed);
if(sce->nodetree) {
lib_link_ntree(fd, &sce->id, sce->nodetree);
@@ -4217,7 +4217,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->obedit= NULL;
sce->stats= 0;
- memset(&sce->sound_handles, 0, sizeof(sce->sound_handles));
+ sound_create_scene(sce);
/* set users to one by default, not in lib-link, this will increase it for compo nodes */
sce->id.us= 1;
@@ -5200,6 +5200,7 @@ static void fix_relpaths_library(const char *basepath, Main *main)
static void direct_link_sound(FileData *fd, bSound *sound)
{
sound->handle = NULL;
+ sound->playback_handle = NULL;
sound->packedfile = direct_link_packedfile(fd, sound->packedfile);
sound->newpackedfile = direct_link_packedfile(fd, sound->newpackedfile);
@@ -10565,6 +10566,7 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
/* put 2.50 compatibility code here until next subversion bump */
{
Scene *sce;
+ Sequence *seq;
/* initialize to sane default so toggling on border shows something */
for(sce = main->scene.first; sce; sce = sce->id.next) {
@@ -10575,6 +10577,14 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
sce->r.border.xmax= 1.0f;
sce->r.border.ymax= 1.0f;
}
+
+ if((sce->r.ffcodecdata.flags & FFMPEG_MULTIPLEX_AUDIO) == 0)
+ sce->r.ffcodecdata.audio_codec = 0x0; // CODEC_ID_NONE
+
+ SEQ_BEGIN(sce->ed, seq) {
+ seq->volume = 1.0f;
+ }
+ SEQ_END
}
/* sequencer changes */
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 82a2b615681..8ac2bd5753a 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -83,7 +83,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
CFRA= RNA_int_get(op->ptr, "frame");
/* do updates */
- sound_scrub(C);
+ sound_seek_scene(C);
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
}
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index f7aeee14cb7..53cd34c46f5 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1513,9 +1513,11 @@ static int frame_offset_exec(bContext *C, wmOperator *op)
int delta;
delta = RNA_int_get(op->ptr, "delta");
-
+
CTX_data_scene(C)->r.cfra += delta;
+ sound_seek_scene(C);
+
WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
return OPERATOR_FINISHED;
@@ -2473,12 +2475,13 @@ static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
}
}
+ if(sad->flag & ANIMPLAY_FLAG_JUMPED)
+ sound_seek_scene(C);
+
/* since we follow drawflags, we can't send notifier but tag regions ourselves */
ED_update_for_newframe(C, 1);
- sound_update_playing(C);
-
for(sa= screen->areabase.first; sa; sa= sa->next) {
ARegion *ar;
for(ar= sa->regionbase.first; ar; ar= ar->next) {
@@ -2521,16 +2524,19 @@ static void SCREEN_OT_animation_step(wmOperatorType *ot)
static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
{
bScreen *screen= CTX_wm_screen(C);
+ struct Scene* scene = CTX_data_scene(C);
if(screen->animtimer) {
/* stop playback now */
ED_screen_animation_timer(C, 0, 0, 0);
- sound_stop_all(C);
+ sound_stop_scene(scene);
}
else {
ScrArea *sa= CTX_wm_area(C);
int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
int sync= -1;
+ if(mode == 1) // XXX only play audio forwards!?
+ sound_play_scene(scene);
if(RNA_property_is_set(op->ptr, "sync"))
sync= (RNA_boolean_get(op->ptr, "sync"));
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index 064baafbd95..7398017a267 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -74,12 +74,12 @@ static int open_exec(bContext *C, wmOperator *op)
sound = sound_new_file(CTX_data_main(C), path);
- if (sound==NULL || sound->handle == NULL) {
+ if (sound==NULL || sound->playback_handle == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
}
- info = AUD_getInfo(sound->handle);
+ info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
sound_delete(C, sound);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index 648a162890d..f8a12c566df 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -77,7 +77,7 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
* NOTE: sync this part of the code with ANIM_OT_change_frame
*/
CFRA= RNA_int_get(op->ptr, "frame");
- sound_scrub(C);
+ sound_seek_scene(C);
/* set the cursor value */
sipo->cursorVal= RNA_float_get(op->ptr, "value");
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 359082c470a..566abaa18c3 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -215,7 +215,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
else
strcpy(seq->name+2, sce_seq->id.name+2);
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
sort_seq(scene);
if (RNA_boolean_get(op->ptr, "replace_sel")) {
@@ -303,7 +303,7 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
}
sort_seq(scene);
- seq_update_muting(ed);
+ seq_update_muting(scene, ed);
WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene);
@@ -428,7 +428,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
}
}
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
sort_seq(scene);
@@ -530,7 +530,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
seq->flag |= SEQ_USE_EFFECT_DEFAULT_FADE;
- calc_sequence(seq);
+ calc_sequence(scene, seq);
/* basic defaults */
seq->strip= strip= MEM_callocN(sizeof(Strip), "strip");
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index b3682681fd7..5339acf74d9 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -49,7 +49,8 @@
#include "BKE_sequencer.h"
#include "BKE_scene.h"
#include "BKE_utildefines.h"
-
+#include "BKE_sound.h"
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -172,6 +173,38 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, char *col)
}
}
+static void drawseqwave(Sequence *seq, float x1, float y1, float x2, float y2, float stepsize)
+{
+ /*
+ x1 is the starting x value to draw the wave,
+ x2 the end x value, same for y1 and y2
+ stepsize is width of a pixel.
+ */
+ if(seq->sound->cache)
+ {
+ int i;
+ int length = floor((x2-x1)/stepsize)+1;
+ float ymid = (y1+y2)/2;
+ float yscale = (y2-y1)/2;
+ float* samples = malloc(length * sizeof(float) * 2);
+ if(!samples)
+ return;
+ if(sound_read_sound_buffer(seq->sound, samples, length) != length)
+ {
+ free(samples);
+ return;
+ }
+ glBegin(GL_LINES);
+ for(i = 0; i < length; i++)
+ {
+ glVertex2f(x1+i*stepsize, ymid + samples[i * 2] * yscale);
+ glVertex2f(x1+i*stepsize, ymid + samples[i * 2 + 1] * yscale);
+ }
+ glEnd();
+ free(samples);
+ }
+}
+
static void drawmeta_contents(Scene *scene, Sequence *seqm, float x1, float y1, float x2, float y2)
{
/* Note, this used to use WHILE_SEQ, but it messes up the seq->depth value, (needed by transform when doing overlap checks)
@@ -557,6 +590,9 @@ static void draw_seq_strip(Scene *scene, ARegion *ar, SpaceSeq *sseq, Sequence *
x1= seq->startdisp;
x2= seq->enddisp;
+ /* draw sound wave */
+ if(seq->type == SEQ_SOUND) drawseqwave(seq, x1, y1, x2, y2, (ar->v2d.cur.xmax - ar->v2d.cur.xmin)/ar->winx);
+
get_seq_color3ubv(scene, seq, col);
if (G.moving && (seq->flag & SELECT)) {
if(seq->flag & SEQ_OVERLAP) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index fb8f3b37683..4f19cfa86af 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -479,7 +479,7 @@ static void reload_sound_strip(Scene *scene, char *name)
seqact->strip= seq->strip;
seqact->len= seq->len;
- calc_sequence(seqact);
+ calc_sequence(scene, seqact);
seq->strip= 0;
seq_free_sequence(scene, seq);
@@ -519,7 +519,7 @@ static void reload_image_strip(Scene *scene, char *name)
seqact->strip= seq->strip;
seqact->len= seq->len;
- calc_sequence(seqact);
+ calc_sequence(scene, seqact);
seq->strip= 0;
seq_free_sequence(scene, seq);
@@ -857,8 +857,8 @@ static Sequence *dupli_seq(struct Scene *scene, Sequence *seq)
} else if(seq->type == SEQ_SOUND) {
seqn->strip->stripdata =
MEM_dupallocN(seq->strip->stripdata);
- if(seq->sound_handle)
- seqn->sound_handle = sound_new_handle(scene, seqn->sound, seq->sound_handle->startframe, seq->sound_handle->endframe, seq->sound_handle->frameskip);
+ if(seq->scene_sound)
+ seqn->scene_sound = sound_add_scene_sound(scene, seqn, seq->startdisp, seq->enddisp, seq->startofs + seq->anim_startofs);
seqn->sound->id.us++;
} else if(seq->type == SEQ_IMAGE) {
@@ -983,7 +983,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence * seq, int cutframe)
}
reload_sequence_new_file(scene, seq);
- calc_sequence(seq);
+ calc_sequence(scene, seq);
if (!skip_dup) {
/* Duplicate AFTER the first change */
@@ -1022,7 +1022,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence * seq, int cutframe)
}
reload_sequence_new_file(scene, seqn);
- calc_sequence(seqn);
+ calc_sequence(scene, seqn);
}
return seqn;
}
@@ -1072,7 +1072,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence * seq, int cutframe)
}
}
- calc_sequence(seq);
+ calc_sequence(scene, seq);
if (!skip_dup) {
/* Duplicate AFTER the first change */
@@ -1107,7 +1107,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence * seq, int cutframe)
seqn->startstill = 0;
}
- calc_sequence(seqn);
+ calc_sequence(scene, seqn);
}
return seqn;
}
@@ -1161,7 +1161,7 @@ int insert_gap(Scene *scene, int gap, int cfra)
SEQP_BEGIN(ed, seq) {
if(seq->startdisp >= cfra) {
seq->start+= gap;
- calc_sequence(seq);
+ calc_sequence(scene, seq);
done= 1;
}
}
@@ -1336,7 +1336,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
}
seq_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
}
- calc_sequence(seq);
+ calc_sequence(scene, seq);
}
}
SEQ_END
@@ -1351,11 +1351,11 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
}
else if(seq->type & SEQ_EFFECT) {
if(seq->seq1 && (seq->seq1->flag & SELECT))
- calc_sequence(seq);
+ calc_sequence(scene, seq);
else if(seq->seq2 && (seq->seq2->flag & SELECT))
- calc_sequence(seq);
+ calc_sequence(scene, seq);
else if(seq->seq3 && (seq->seq3->flag & SELECT))
- calc_sequence(seq);
+ calc_sequence(scene, seq);
}
}
SEQ_END;
@@ -1425,7 +1425,7 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op)
}
}
- seq_update_muting(ed);
+ seq_update_muting(scene, ed);
WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -1476,7 +1476,7 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op)
}
}
- seq_update_muting(ed);
+ seq_update_muting(scene, ed);
WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -1623,8 +1623,6 @@ static int sequencer_refresh_all_exec(bContext *C, wmOperator *op)
free_imbuf_seq(scene, &ed->seqbase, FALSE);
- seqbase_sound_reload(scene, &ed->seqbase);
-
WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -1840,7 +1838,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *op)
/* updates lengths etc */
seq= ed->seqbasep->first;
while(seq) {
- calc_sequence(seq);
+ calc_sequence(scene, seq);
seq= seq->next;
}
@@ -1848,7 +1846,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *op)
ms= ed->metastack.last;
while(ms) {
ms->parseq->strip->len= 0; /* force new alloc */
- calc_sequence(ms->parseq);
+ calc_sequence(scene, ms->parseq);
ms= ms->prev;
}
@@ -1923,7 +1921,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
/* new stripdata */
strip_new->stripdata= se_new= MEM_callocN(sizeof(StripElem)*1, "stripelem");
strncpy(se_new->name, se->name, FILE_MAXFILE-1);
- calc_sequence(seq_new);
+ calc_sequence(scene, seq_new);
seq_new->flag &= ~SEQ_OVERLAP;
if (seq_test_overlap(ed->seqbasep, seq_new)) {
shuffle_seq(ed->seqbasep, seq_new, scene);
@@ -2011,7 +2009,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *op)
/* recalc all: the meta can have effects connected to it */
for(seq= ed->seqbasep->first; seq; seq= seq->next)
- calc_sequence(seq);
+ calc_sequence(scene, seq);
active_seq_set(scene, ms->parseq);
@@ -2022,7 +2020,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *op)
}
- seq_update_muting(ed);
+ seq_update_muting(scene, ed);
WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@@ -2081,7 +2079,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
seq= next;
}
seqm->machine= channel_max;
- calc_sequence(seqm);
+ calc_sequence(scene, seqm);
seqm->strip= MEM_callocN(sizeof(Strip), "metastrip");
seqm->strip->len= seqm->len;
@@ -2091,7 +2089,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
if( seq_test_overlap(ed->seqbasep, seqm) ) shuffle_seq(ed->seqbasep, seqm, scene);
- seq_update_muting(ed);
+ seq_update_muting(scene, ed);
seqUniqueName(scene->ed->seqbasep, seqm);
@@ -2165,7 +2163,7 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *op)
SEQ_END;
sort_seq(scene);
- seq_update_muting(ed);
+ seq_update_muting(scene, ed);
WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, scene);
@@ -2521,13 +2519,13 @@ void SEQUENCER_OT_previous_edit(wmOperatorType *ot)
/* properties */
}
-static void swap_sequence(Sequence* seqa, Sequence* seqb)
+static void swap_sequence(Scene* scene, Sequence* seqa, Sequence* seqb)
{
int gap = seqb->startdisp - seqa->enddisp;
seqb->start = seqa->start;
- calc_sequence(seqb);
+ calc_sequence(scene, seqb);
seqa->start = seqb->enddisp + gap;
- calc_sequence(seqa);
+ calc_sequence(scene, seqa);
}
static Sequence* sequence_find_parent(Scene* scene, Sequence* child)
@@ -2571,17 +2569,17 @@ static int sequencer_swap_exec(bContext *C, wmOperator *op)
switch (side) {
case SEQ_SIDE_LEFT:
- swap_sequence(seq, active_seq);
+ swap_sequence(scene, seq, active_seq);
break;
case SEQ_SIDE_RIGHT:
- swap_sequence(active_seq, seq);
+ swap_sequence(scene, active_seq, seq);
break;
}
// XXX - should be a generic function
for(iseq= scene->ed->seqbasep->first; iseq; iseq= iseq->next) {
if((iseq->type & SEQ_EFFECT) && (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
- calc_sequence(iseq);
+ calc_sequence(scene, iseq);
}
}
@@ -2682,9 +2680,9 @@ static void seq_del_sound(Scene *scene, Sequence *seq)
seq_del_sound(scene, iseq);
}
}
- else if(seq->sound_handle) {
- sound_delete_handle(scene, seq->sound_handle);
- seq->sound_handle= NULL;
+ else if(seq->scene_sound) {
+ sound_remove_scene_sound(scene, seq->scene_sound);
+ seq->scene_sound = NULL;
}
}
@@ -2733,19 +2731,19 @@ void SEQUENCER_OT_copy(wmOperatorType *ot)
/* properties */
}
-static void seq_offset(Sequence *seq, int ofs)
+static void seq_offset(Scene *scene, Sequence *seq, int ofs)
{
if(seq->type == SEQ_META) {
Sequence *iseq;
for(iseq= seq->seqbase.first; iseq; iseq= iseq->next) {
- seq_offset(iseq, ofs);
+ seq_offset(scene, iseq, ofs);
}
}
else {
seq->start += ofs;
}
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
}
static int sequencer_paste_exec(bContext *C, wmOperator *op)
@@ -2764,7 +2762,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op)
/* transform pasted strips before adding */
if(ofs) {
for(iseq= new.first; iseq; iseq= iseq->next) {
- seq_offset(iseq, ofs);
+ seq_offset(scene, iseq, ofs);
}
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 15b812dc1f2..e93e9c42e10 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -2369,10 +2369,10 @@ void flushTransSeq(TransInfo *t)
/* Calculate this strip and all nested strips
* children are ALWAYS transformed first
* so we dont need to do this in another loop. */
- calc_sequence(seq);
+ calc_sequence(t->scene, seq);
}
else {
- calc_sequence_disp(seq);
+ calc_sequence_disp(t->scene, seq);
}
}
seq_prev= seq;
@@ -2404,7 +2404,7 @@ void flushTransSeq(TransInfo *t)
while(seq) {
if (seq->type == SEQ_META && seq->flag & SELECT)
- calc_sequence(seq);
+ calc_sequence(t->scene, seq);
seq= seq->next;
}
}
@@ -4105,9 +4105,9 @@ static void freeSeqData(TransInfo *t)
for(seq= seqbasep->first; seq; seq= seq->next) {
/* We might want to build a list of effects that need to be updated during transform */
if(seq->type & SEQ_EFFECT) {
- if (seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(seq);
- else if (seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(seq);
- else if (seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(seq);
+ if (seq->seq1 && seq->seq1->flag & SELECT) calc_sequence(t->scene, seq);
+ else if (seq->seq2 && seq->seq2->flag & SELECT) calc_sequence(t->scene, seq);
+ else if (seq->seq3 && seq->seq3->flag & SELECT) calc_sequence(t->scene, seq);
}
}
@@ -4118,7 +4118,7 @@ static void freeSeqData(TransInfo *t)
for(a=0; a<t->total; a++, td++) {
seq= ((TransDataSeq *)td->extra)->seq;
if ((seq != seq_prev) && (seq->depth==0)) {
- calc_sequence_disp(seq);
+ calc_sequence_disp(t->scene, seq);
}
seq_prev= seq;
}
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 63d3e764263..204af647b3a 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -758,7 +758,8 @@ typedef struct Scene {
ListBase markers;
ListBase transform_spaces;
- ListBase sound_handles;
+ void *sound_scene;
+ void *sound_scene_handle;
/* none of the dependancy graph vars is mean to be saved */
struct DagForest *theDag;
@@ -1078,7 +1079,7 @@ typedef struct Scene {
#define AUDIO_SYNC 2
#define AUDIO_SCRUB 4
-#define FFMPEG_MULTIPLEX_AUDIO 1
+#define FFMPEG_MULTIPLEX_AUDIO 1 /* deprecated, you can choose none as audiocodec now */
#define FFMPEG_AUTOSPLIT_OUTPUT 2
/* Paint.flags */
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 0b45d62e347..c93625e9c27 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -161,7 +161,9 @@ typedef struct Sequence {
ListBase seqbase; /* list of strips for metastrips */
struct bSound *sound; /* the linked "bSound" object */
- struct SoundHandle *sound_handle;
+ void *scene_sound;
+ float volume, pad;
+
float level, pan; /* level in dB (0=full), pan -1..1 */
int scenenr; /* for scene selection */
float strobe;
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index 55b48e4aacd..c0b8657618d 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -41,21 +41,6 @@ struct Ipo;
struct PackedFile;
struct SpaceLink;
-// runtime only - no saving
-typedef struct SoundHandle {
- struct SoundHandle *next, *prev;
- struct bSound *source;
- void *handle;
- int state;
- int startframe;
- int endframe;
- int frameskip;
- int mute;
- int changed;
- float volume;
- float pad;
-} SoundHandle;
-
typedef struct Sound3D
{
float min_gain;
@@ -98,19 +83,21 @@ typedef struct bSound {
float max_gain;
float distance;
int flags;
+ int pad;
/** currently int type;
struct bSound *child_sound;*/
/**
- * Whether the sound has been changed and must be restarted if playing.
+ * The audaspace handle for cache.
*/
- int changed;
+ void *cache;
/**
- * The audaspace handle for cache.
+ * The audaspace handle that should actually be played back.
+ * Should be cache if cache != NULL; otherwise it's handle
*/
- void *cache;
+ void *playback_handle;
/** XXX unused currently // SOUND_TYPE_LIMITER
float start, end;*/
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index 11aff7922c7..452745ba364 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -107,6 +107,7 @@ EnumPropertyItem snap_element_items[] = {
#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BKE_mesh.h"
+#include "BKE_sound.h"
#include "BLI_threads.h"
#include "BLI_editVert.h"
@@ -287,10 +288,11 @@ static void rna_Scene_preview_range_end_frame_set(PointerRNA *ptr, int value)
data->r.pefra= value;
}
-static void rna_Scene_frame_update(Main *bmain, Scene *unused, PointerRNA *ptr)
+static void rna_Scene_frame_update(bContext *C, PointerRNA *ptr)
{
//Scene *scene= ptr->id.data;
//ED_update_for_newframe(C);
+ sound_seek_scene(C);
}
static int rna_Scene_active_keying_set_editable(PointerRNA *ptr)
@@ -1675,12 +1677,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
#ifdef WITH_FFMPEG
{R_H264, "H264", ICON_FILE_MOVIE, "H.264", ""},
{R_XVID, "XVID", ICON_FILE_MOVIE, "Xvid", ""},
- // XXX broken
-#if 0
-#ifdef WITH_OGG
{R_THEORA, "THEORA", ICON_FILE_MOVIE, "Ogg Theora", ""},
-#endif
-#endif
{R_FFMPEG, "FFMPEG", ICON_FILE_MOVIE, "FFMpeg", ""},
#endif
{R_FRAMESERVER, "FRAMESERVER", ICON_FILE_SCRIPT, "Frame Server", ""},
@@ -1731,16 +1728,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{FFMPEG_DV, "DV", 0, "DV", ""},
{FFMPEG_H264, "H264", 0, "H.264", ""},
{FFMPEG_XVID, "XVID", 0, "Xvid", ""},
- // XXX broken
-#if 0
-#ifdef WITH_OGG
{FFMPEG_OGG, "OGG", 0, "Ogg", ""},
-#endif
-#endif
+ {FFMPEG_MKV, "MKV", 0, "Matroska", ""},
{FFMPEG_FLV, "FLASH", 0, "Flash", ""},
+ {FFMPEG_WAV, "WAV", 0, "Wav", ""},
+ {FFMPEG_MP3, "MP3", 0, "Mp3", ""},
{0, NULL, 0, NULL, NULL}};
-
+
static EnumPropertyItem ffmpeg_codec_items[] = {
+ {CODEC_ID_NONE, "NONE", 0, "None", ""},
{CODEC_ID_MPEG1VIDEO, "MPEG1", 0, "MPEG-1", ""},
{CODEC_ID_MPEG2VIDEO, "MPEG2", 0, "MPEG-2", ""},
{CODEC_ID_MPEG4, "MPEG4", 0, "MPEG-4(divx)", ""},
@@ -1748,18 +1744,18 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
{CODEC_ID_DVVIDEO, "DV", 0, "DV", ""},
{CODEC_ID_H264, "H264", 0, "H.264", ""},
{CODEC_ID_XVID, "XVID", 0, "Xvid", ""},
-#ifdef WITH_OGG
{CODEC_ID_THEORA, "THEORA", 0, "Theora", ""},
-#endif
{CODEC_ID_FLV1, "FLASH", 0, "Flash Video", ""},
{0, NULL, 0, NULL, NULL}};
-
+
static EnumPropertyItem ffmpeg_audio_codec_items[] = {
+ {CODEC_ID_NONE, "NONE", 0, "None", ""},
{CODEC_ID_MP2, "MP2", 0, "MP2", ""},
{CODEC_ID_MP3, "MP3", 0, "MP3", ""},
{CODEC_ID_AC3, "AC3", 0, "AC3", ""},
{CODEC_ID_AAC, "AAC", 0, "AAC", ""},
{CODEC_ID_VORBIS, "VORBIS", 0, "Vorbis", ""},
+ {CODEC_ID_FLAC, "FLAC", 0, "FLAC", ""},
{CODEC_ID_PCM_S16LE, "PCM", 0, "PCM", ""},
{0, NULL, 0, NULL, NULL}};
#endif
@@ -1992,7 +1988,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
/* FFMPEG Audio*/
-
prop= RNA_def_property(srna, "ffmpeg_audio_codec", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "ffcodecdata.audio_codec");
RNA_def_property_enum_items(prop, ffmpeg_audio_codec_items);
@@ -2005,11 +2000,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bitrate", "Audio bitrate(kb/s)");
RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
- prop= RNA_def_property(srna, "ffmpeg_multiplex_audio", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "ffcodecdata.flags", FFMPEG_MULTIPLEX_AUDIO);
- RNA_def_property_ui_text(prop, "Multiplex Audio", "Interleave audio with the output video");
- RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL);
-
prop= RNA_def_property(srna, "ffmpeg_audio_mixrate", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "ffcodecdata.audio_mixrate");
RNA_def_property_range(prop, 8000, 192000);
@@ -2636,6 +2626,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "r.cfra");
RNA_def_property_range(prop, MINAFRAME, MAXFRAME);
RNA_def_property_ui_text(prop, "Current Frame", "");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SCENE|ND_FRAME, "rna_Scene_frame_update");
prop= RNA_def_property(srna, "start_frame", PROP_INT, PROP_TIME);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 7ffaa4d478b..00a156cf820 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -93,7 +93,7 @@ static void rna_Sequence_frame_change_update(Scene *scene, Sequence *seq)
{
Editing *ed= seq_give_editing(scene, FALSE);
ListBase *seqbase= seq_seqbase(&ed->seqbase, seq);
- calc_sequence_disp(seq);
+ calc_sequence_disp(scene, seq);
if(seq_test_overlap(seqbase, seq)) {
shuffle_seq(seqbase, seq, scene); // XXX - BROKEN!, uses context seqbasep
@@ -351,14 +351,14 @@ static void rna_Sequence_update(Main *bmain, Scene *scene, PointerRNA *ptr)
free_imbuf_seq(scene, &ed->seqbase, FALSE);
if(RNA_struct_is_a(ptr->type, &RNA_SoundSequence))
- seq_update_sound(ptr->data);
+ seq_update_sound(scene, ptr->data);
}
static void rna_Sequence_mute_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Editing *ed= seq_give_editing(scene, FALSE);
- seq_update_muting(ed);
+ seq_update_muting(scene, ed);
rna_Sequence_update(bmain, scene, ptr);
}
@@ -606,24 +606,28 @@ static void rna_def_sequence(BlenderRNA *brna)
prop= RNA_def_property(srna, "length", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "len");
RNA_def_property_range(prop, 1, MAXFRAME);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Length", "The length of the contents of this strip before the handles are applied");
RNA_def_property_int_funcs(prop, "rna_Sequence_length_get", "rna_Sequence_length_set",NULL);
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
prop= RNA_def_property(srna, "start_frame", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "start");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Start Frame", "");
RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_start_frame_set",NULL); // overlap tests and calc_seq_disp
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
prop= RNA_def_property(srna, "start_frame_final", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "startdisp");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "Start Frame", "Start frame displayed in the sequence editor after offsets are applied, setting this is equivilent to moving the handle, not the actual start frame.");
RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_start_frame_final_set", NULL); // overlap tests and calc_seq_disp
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
prop= RNA_def_property(srna, "end_frame_final", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "enddisp");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(prop, "End Frame", "End frame displayed in the sequence editor after offsets are applied.");
RNA_def_property_int_funcs(prop, NULL, "rna_Sequence_end_frame_final_set", NULL); // overlap tests and calc_seq_disp
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
@@ -949,6 +953,12 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sound", "Sound datablock used by this sequence.");
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
+ prop= RNA_def_property(srna, "volume", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "volume");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Volume", "Playback volume of the sound");
+ RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
+
prop= RNA_def_property(srna, "filename", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "strip->stripdata->name");
RNA_def_property_ui_text(prop, "Filename", "");
@@ -961,14 +971,6 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
rna_def_input(srna);
-
- RNA_def_struct_sdna_from(srna, "SoundHandle", "sound_handle");
-
- prop= RNA_def_property(srna, "volume", PROP_FLOAT, PROP_NONE);
- RNA_def_property_float_sdna(prop, NULL, "volume");
- RNA_def_property_range(prop, 0.0f, 1.0f);
- RNA_def_property_ui_text(prop, "Volume", "Playback volume of the sound");
- RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update");
}
static void rna_def_effect(BlenderRNA *brna)
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index a0645476063..29332effa29 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -394,7 +394,7 @@ void BL_ConvertActuators(char* maggiename,
"\" has no sound datablock." << std::endl;
}
else
- snd_sound = sound->cache ? sound->cache : sound->handle;
+ snd_sound = sound->playback_handle;
KX_SoundActuator* tmpsoundact =
new KX_SoundActuator(gameobj,
snd_sound,
diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp
index 40d2339b816..bf7d890f53b 100644
--- a/source/gameengine/Ketsji/KX_SoundActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp
@@ -187,7 +187,7 @@ bool KX_SoundActuator::Update(double curtime, bool frame)
case KX_SOUNDACT_LOOPBIDIRECTIONAL:
{
// stop the looping so that the sound stops when it finished
- AUD_stopLoop(m_handle);
+ AUD_setLoop(m_handle, 0, -1);
break;
}
default: