From bd6ca0570e089afc1d29b4f18b8bb6cc086545ea Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Thu, 28 Jul 2011 13:58:59 +0000 Subject: [PATCH] 3D Audio GSoC: Implemented basic audio animation. * AnimatableProperty: Propper cache writing and spline interpolation for reading (the solution for stair steps in audio animation) * Animatable properties so far are: volume, pitch, panning * Users note: Changing the pitch of a sound results in wrong seeking, due to the resulting playback length difference. * Users note: Panning only works for mono sources, values are in the range [-2..2], this basically controls the angle of the sound, 0 is front, -1 left, 1 right and 2 and -2 are back. Typical stereo panning only supports [-1..1]. * Disabled animation of audio related ffmpeg output parameters. * Scene Audio Panel: 3D Listener settings also for Renderer, new Volume property (animatable!), Update/Bake buttons for animation problems, moved sampling rate and channel count here --- .../intern/AUD_AnimateableProperty.cpp | 81 +++++++++++++++- .../intern/AUD_AnimateableProperty.h | 2 +- intern/audaspace/intern/AUD_C-API.cpp | 18 ++++ intern/audaspace/intern/AUD_C-API.h | 4 + .../audaspace/intern/AUD_SequencerEntry.cpp | 32 +++++- intern/audaspace/intern/AUD_SequencerEntry.h | 2 + .../audaspace/intern/AUD_SequencerFactory.cpp | 2 + .../audaspace/intern/AUD_SequencerHandle.cpp | 13 ++- intern/audaspace/intern/AUD_SequencerHandle.h | 2 +- .../audaspace/intern/AUD_SequencerReader.cpp | 14 ++- .../audaspace/intern/AUD_SoftwareDevice.cpp | 12 ++- intern/audaspace/intern/AUD_SoftwareDevice.h | 6 ++ .../scripts/startup/bl_ui/properties_game.py | 15 --- .../startup/bl_ui/properties_render.py | 3 - .../scripts/startup/bl_ui/properties_scene.py | 26 +++++ .../scripts/startup/bl_ui/space_sequencer.py | 2 + source/blender/blenkernel/BKE_fcurve.h | 2 +- source/blender/blenkernel/BKE_sound.h | 10 ++ source/blender/blenkernel/intern/fcurve.c | 12 ++- source/blender/blenkernel/intern/scene.c | 9 +- source/blender/blenkernel/intern/seqeffects.c | 2 +- source/blender/blenkernel/intern/sequencer.c | 3 +- source/blender/blenkernel/intern/sound.c | 28 +++++- source/blender/blenloader/intern/readfile.c | 22 +++-- source/blender/editors/sound/sound_ops.c | 97 +++++++++++++++++++ source/blender/makesdna/DNA_scene_types.h | 9 +- source/blender/makesdna/DNA_sequence_types.h | 7 +- source/blender/makesrna/intern/rna_scene.c | 21 ++++ .../blender/makesrna/intern/rna_sequencer.c | 45 ++++++++- 29 files changed, 439 insertions(+), 62 deletions(-) diff --git a/intern/audaspace/intern/AUD_AnimateableProperty.cpp b/intern/audaspace/intern/AUD_AnimateableProperty.cpp index bc517819f37..03d2d3a5ea1 100644 --- a/intern/audaspace/intern/AUD_AnimateableProperty.cpp +++ b/intern/audaspace/intern/AUD_AnimateableProperty.cpp @@ -32,6 +32,7 @@ #include "AUD_AnimateableProperty.h" #include +#include AUD_AnimateableProperty::AUD_AnimateableProperty(int count) : AUD_Buffer(count * sizeof(float)), m_count(count), m_isAnimated(false), m_changed(false) @@ -78,16 +79,85 @@ void AUD_AnimateableProperty::write(const float* data, int position, int count) lock(); m_isAnimated = true; - m_changed = true; + + int pos = getSize() / (sizeof(float) * m_count); + assureSize((count + position) * m_count * sizeof(float), true); - memcpy(getBuffer() + position * m_count, data, count * m_count * sizeof(float)); + + float* buf = getBuffer(); + + memcpy(buf + position * m_count, data, count * m_count * sizeof(float)); + + for(int i = pos; i < position; i++) + memcpy(buf + i * m_count, buf + (pos - 1) * m_count, m_count * sizeof(float)); unlock(); } -const float* AUD_AnimateableProperty::read(int position) const +void AUD_AnimateableProperty::read(float position, float* out) { - return getBuffer() + position * m_count; + lock(); + + if(!m_isAnimated) + { + memcpy(out, getBuffer(), m_count * sizeof(float)); + unlock(); + return; + } + + float last = (getSize() / (sizeof(float) * m_count) - 1); + float t = position - floor(position); + + if(position > last) + { + position = last; + t = 0; + } + + if(t == 0) + { + memcpy(out, getBuffer() + int(floor(position)) * m_count, m_count * sizeof(float)); + } + else + { + int pos = int(floor(position)) * m_count; + float t2 = t * t; + float t3 = t2 * t; + float m0, m1; + float* p0; + float* p1 = getBuffer() + pos; + float* p2; + float* p3; + + if(pos == 0) + p0 = p1; + else + p0 = p1 - m_count; + + if(pos > last) + { + p3 = p2 = p1; + } + else + { + p2 = p1 + m_count; + if(pos + m_count > last) + p3 = p2; + else + p3 = p2 + m_count; + } + + for(int i = 0; i < m_count; i++) + { + m0 = (p2[i] - p0[i]) / 2.0f; + m1 = (p3[i] - p1[i]) / 2.0f; + + out[i] = (2 * t3 - 3 * t2 + 1) * p0[i] + (-2 * t3 + 3 * t2) * p1[i] + + (t3 - 2 * t2 + t) * m0 + (t3 - t2) * m1; + } + } + + unlock(); } bool AUD_AnimateableProperty::isAnimated() const @@ -97,6 +167,9 @@ bool AUD_AnimateableProperty::isAnimated() const bool AUD_AnimateableProperty::hasChanged() { + if(m_isAnimated) + return true; + bool result = m_changed; m_changed = false; return result; diff --git a/intern/audaspace/intern/AUD_AnimateableProperty.h b/intern/audaspace/intern/AUD_AnimateableProperty.h index 5fb9509267b..d3b2e29c036 100644 --- a/intern/audaspace/intern/AUD_AnimateableProperty.h +++ b/intern/audaspace/intern/AUD_AnimateableProperty.h @@ -84,7 +84,7 @@ public: void write(const float* data, int position, int count); - const float* read(int position) const; + void read(float position, float* out); bool isAnimated() const; diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index 477dc61fd53..c365f8b9c5e 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -938,6 +938,24 @@ void AUD_updateSequenceSound(AUD_SEntry* entry, AUD_Sound* sound) (*entry)->setSound(AUD_Sound()); } +void AUD_setSequenceAnimData(AUD_SEntry* entry, AUD_AnimateablePropertyType type, int frame, float* data, char animated) +{ + AUD_AnimateableProperty* prop = (*entry)->getAnimProperty(type); + if(animated) + prop->write(data, frame, 1); + else + prop->write(data); +} + +void AUD_setSequencerAnimData(AUD_Sound* sequencer, AUD_AnimateablePropertyType type, int frame, float* data, char animated) +{ + AUD_AnimateableProperty* prop = ((AUD_SequencerFactory*)sequencer->get())->getAnimProperty(type); + if(animated) + prop->write(data, frame, 1); + else + prop->write(data); +} + void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer) { ((AUD_SequencerFactory*)sequencer->get())->setSpecs(AUD_device->getSpecs().specs); diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index 949bb89d9e5..8b7112bfa3f 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -471,6 +471,10 @@ extern void AUD_muteSequence(AUD_SEntry* entry, char mute); extern void AUD_updateSequenceSound(AUD_SEntry* entry, AUD_Sound* sound); +extern void AUD_setSequenceAnimData(AUD_SEntry* entry, AUD_AnimateablePropertyType type, int frame, float* data, char animated); + +extern void AUD_setSequencerAnimData(AUD_Sound* sequencer, AUD_AnimateablePropertyType type, int frame, float* data, char animated); + extern void AUD_setSequencerDeviceSpecs(AUD_Sound* sequencer); extern void AUD_setSequencerSpecs(AUD_Sound* sequencer, AUD_Specs specs); diff --git a/intern/audaspace/intern/AUD_SequencerEntry.cpp b/intern/audaspace/intern/AUD_SequencerEntry.cpp index 23dc3f383b5..110e5c6a931 100644 --- a/intern/audaspace/intern/AUD_SequencerEntry.cpp +++ b/intern/audaspace/intern/AUD_SequencerEntry.cpp @@ -45,7 +45,7 @@ AUD_SequencerEntry::AUD_SequencerEntry(AUD_Reference sound, float m_end(end), m_skip(skip), m_muted(false), - m_relative(false), + m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits::max()), @@ -72,10 +72,13 @@ void AUD_SequencerEntry::setSound(AUD_Reference sound) void AUD_SequencerEntry::move(float begin, float end, float skip) { - m_begin = begin; - m_skip = skip; - m_end = end; - m_pos_status++; + if(m_begin != begin || m_skip != skip || m_end != end) + { + m_begin = begin; + m_skip = skip; + m_end = end; + m_pos_status++; + } } void AUD_SequencerEntry::mute(bool mute) @@ -88,6 +91,25 @@ int AUD_SequencerEntry::getID() const return m_id; } +AUD_AnimateableProperty* AUD_SequencerEntry::getAnimProperty(AUD_AnimateablePropertyType type) +{ + switch(type) + { + case AUD_AP_VOLUME: + return &m_volume; + case AUD_AP_PITCH: + return &m_pitch; + case AUD_AP_PANNING: + return &m_panning; + case AUD_AP_LOCATION: + return &m_location; + case AUD_AP_ORIENTATION: + return &m_orientation; + default: + return NULL; + } +} + bool AUD_SequencerEntry::isRelative() { return m_relative; diff --git a/intern/audaspace/intern/AUD_SequencerEntry.h b/intern/audaspace/intern/AUD_SequencerEntry.h index 316ccccf643..950e0fd9550 100644 --- a/intern/audaspace/intern/AUD_SequencerEntry.h +++ b/intern/audaspace/intern/AUD_SequencerEntry.h @@ -76,6 +76,8 @@ public: int getID() const; + AUD_AnimateableProperty* getAnimProperty(AUD_AnimateablePropertyType type); + /** * Checks whether the source location, velocity and orientation are relative * to the listener. diff --git a/intern/audaspace/intern/AUD_SequencerFactory.cpp b/intern/audaspace/intern/AUD_SequencerFactory.cpp index e26dd7d9bb5..dd856dc0701 100644 --- a/intern/audaspace/intern/AUD_SequencerFactory.cpp +++ b/intern/audaspace/intern/AUD_SequencerFactory.cpp @@ -48,6 +48,8 @@ AUD_SequencerFactory::AUD_SequencerFactory(AUD_Specs specs, float fps, bool mute { AUD_Quaternion q; m_orientation.write(q.get()); + float f = 1; + m_volume.write(&f); } AUD_SequencerFactory::~AUD_SequencerFactory() diff --git a/intern/audaspace/intern/AUD_SequencerHandle.cpp b/intern/audaspace/intern/AUD_SequencerHandle.cpp index a3853d2b71c..dead6fdf07b 100644 --- a/intern/audaspace/intern/AUD_SequencerHandle.cpp +++ b/intern/audaspace/intern/AUD_SequencerHandle.cpp @@ -66,7 +66,7 @@ void AUD_SequencerHandle::stop() m_handle->stop(); } -void AUD_SequencerHandle::update(float position) +void AUD_SequencerHandle::update(float position, float frame) { if(!m_handle.isNull()) { @@ -111,7 +111,16 @@ void AUD_SequencerHandle::update(float position) m_status = m_entry->m_status; } - // AUD_XXX TODO: Animation data + float value; + + m_entry->m_volume.read(frame, &value); + m_handle->setVolume(value); + m_entry->m_pitch.read(frame, &value); + m_handle->setPitch(value); + m_entry->m_panning.read(frame, &value); + AUD_SoftwareDevice::setPanning(m_handle.get(), value); + + // AUD_XXX: TODO: animation data if(m_entry->m_muted) m_handle->setVolume(0); diff --git a/intern/audaspace/intern/AUD_SequencerHandle.h b/intern/audaspace/intern/AUD_SequencerHandle.h index 2e58d815fe1..49d74a85fea 100644 --- a/intern/audaspace/intern/AUD_SequencerHandle.h +++ b/intern/audaspace/intern/AUD_SequencerHandle.h @@ -54,7 +54,7 @@ public: ~AUD_SequencerHandle(); int compare(AUD_Reference entry) const; void stop(); - void update(float position); + void update(float position, float frame); void seek(float position); }; diff --git a/intern/audaspace/intern/AUD_SequencerReader.cpp b/intern/audaspace/intern/AUD_SequencerReader.cpp index ee113d87a02..c20132e27e1 100644 --- a/intern/audaspace/intern/AUD_SequencerReader.cpp +++ b/intern/audaspace/intern/AUD_SequencerReader.cpp @@ -144,19 +144,27 @@ void AUD_SequencerReader::read(int& length, bool& eos, sample_t* buffer) AUD_Specs specs = m_factory->m_specs; int pos = 0; float time = float(m_position) / float(specs.rate); - int len; + float value, frame; + int len, cfra; while(pos < length) { - len = int(ceil((int(floor(time * m_factory->m_fps)) + 1) / m_factory->m_fps * specs.rate)) - m_position; + frame = time * m_factory->m_fps; + cfra = int(floor(frame)); + + len = int(ceil((cfra + 1) / m_factory->m_fps * specs.rate)) - m_position; len = AUD_MIN(length - pos, len); len = AUD_MAX(len, 1); for(AUD_HandleIterator it = m_handles.begin(); it != m_handles.end(); it++) { - (*it)->update(time); + (*it)->update(time, frame); } + m_factory->m_volume.read(frame, &value); + + m_device.setVolume(value); + m_device.read(reinterpret_cast(buffer + specs.channels * pos), len); pos += len; diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.cpp b/intern/audaspace/intern/AUD_SoftwareDevice.cpp index f8ce9ece02c..1c93ebe9ad0 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.cpp +++ b/intern/audaspace/intern/AUD_SoftwareDevice.cpp @@ -62,8 +62,8 @@ typedef enum /******************************************************************************/ AUD_SoftwareDevice::AUD_SoftwareHandle::AUD_SoftwareHandle(AUD_SoftwareDevice* device, AUD_Reference reader, AUD_Reference pitch, AUD_Reference resampler, AUD_Reference mapper, bool keep) : - m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_volume(1.0f), m_loopcount(0), - m_relative(false), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits::max()), + m_reader(reader), m_pitch(pitch), m_resampler(resampler), m_mapper(mapper), m_keep(keep), m_user_pitch(1.0f), m_user_volume(1.0f), m_user_pan(0.0f), m_volume(1.0f), m_loopcount(0), + m_relative(true), m_volume_max(1.0f), m_volume_min(0), m_distance_max(std::numeric_limits::max()), m_distance_reference(1.0f), m_attenuation(1.0f), m_cone_angle_outer(M_PI), m_cone_angle_inner(M_PI), m_cone_volume_outer(0), m_flags(AUD_RENDER_CONE), m_stop(NULL), m_stop_data(NULL), m_status(AUD_STATUS_PLAYING), m_device(device) { @@ -211,7 +211,7 @@ void AUD_SoftwareDevice::AUD_SoftwareHandle::update() m_mapper->setMonoAngle(phi); } else - m_mapper->setMonoAngle(0); + m_mapper->setMonoAngle(m_relative ? m_user_pan * M_PI / 2.0 : 0); } void AUD_SoftwareDevice::AUD_SoftwareHandle::setSpecs(AUD_Specs specs) @@ -768,6 +768,12 @@ void AUD_SoftwareDevice::mix(data_t* buffer, int length) unlock(); } +void AUD_SoftwareDevice::setPanning(AUD_IHandle* handle, float pan) +{ + AUD_SoftwareDevice::AUD_SoftwareHandle* h = dynamic_cast(handle); + h->m_user_pan = pan; +} + void AUD_SoftwareDevice::setSpecs(AUD_Specs specs) { m_specs.specs = specs; diff --git a/intern/audaspace/intern/AUD_SoftwareDevice.h b/intern/audaspace/intern/AUD_SoftwareDevice.h index 1148f4842aa..da317834d2c 100644 --- a/intern/audaspace/intern/AUD_SoftwareDevice.h +++ b/intern/audaspace/intern/AUD_SoftwareDevice.h @@ -81,6 +81,9 @@ protected: /// The user set volume of the source. float m_user_volume; + /// The user set panning for non-3D sources + float m_user_pan; + /// The calculated final volume of the source. float m_volume; @@ -278,6 +281,9 @@ private: int m_flags; public: + + static void setPanning(AUD_IHandle* handle, float pan); + virtual AUD_DeviceSpecs getSpecs() const; virtual AUD_Reference play(AUD_Reference reader, bool keep = false); virtual AUD_Reference play(AUD_Reference factory, bool keep = false); diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 0c07451b3b2..58b2cacfbcc 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -360,21 +360,6 @@ class RENDER_PT_game_display(RenderButtonsPanel, bpy.types.Panel): flow.prop(gs, "show_mouse", text="Mouse Cursor") -class RENDER_PT_game_sound(RenderButtonsPanel, bpy.types.Panel): - bl_label = "Sound" - COMPAT_ENGINES = {'BLENDER_GAME'} - - def draw(self, context): - layout = self.layout - - scene = context.scene - - layout.prop(scene, "audio_distance_model") - - layout.prop(scene, "audio_doppler_speed", text="Speed") - layout.prop(scene, "audio_doppler_factor") - - class WorldButtonsPanel(): bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 3ba54aa67c6..9b4b8089c4a 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -595,11 +595,8 @@ class RENDER_PT_encoding(RenderButtonsPanel, bpy.types.Panel): col = split.column() col.prop(rd, "ffmpeg_audio_bitrate") - col.prop(rd, "ffmpeg_audio_mixrate") - col = split.column() col.prop(rd, "ffmpeg_audio_volume", slider=True) - col.prop(rd, "ffmpeg_audio_channels") class RENDER_PT_bake(RenderButtonsPanel, bpy.types.Panel): diff --git a/release/scripts/startup/bl_ui/properties_scene.py b/release/scripts/startup/bl_ui/properties_scene.py index e2dc9de064f..aec9d88511c 100644 --- a/release/scripts/startup/bl_ui/properties_scene.py +++ b/release/scripts/startup/bl_ui/properties_scene.py @@ -43,6 +43,32 @@ class SCENE_PT_scene(SceneButtonsPanel, bpy.types.Panel): layout.prop(scene, "background_set", text="Background") +class SCENE_PT_audio(SceneButtonsPanel, bpy.types.Panel): + bl_label = "Audio" + COMPAT_ENGINES = {'BLENDER_RENDER', 'BLENDER_GAME'} + + def draw(self, context): + layout = self.layout + scene = context.scene + rd = context.scene.render + + layout.prop(scene, "audio_distance_model") + + layout.prop(scene, "audio_doppler_speed", text="Speed") + layout.prop(scene, "audio_doppler_factor") + + layout.prop(scene, "audio_volume") + layout.operator("sound.update_animation_flags") + layout.operator("sound.bake_animation") + + split = layout.split() + + col = split.column() + col.prop(rd, "ffmpeg_audio_mixrate", text="Rate") + col = split.column() + col.prop(rd, "ffmpeg_audio_channels", text="") + + class SCENE_PT_unit(SceneButtonsPanel, bpy.types.Panel): bl_label = "Units" COMPAT_ENGINES = {'BLENDER_RENDER'} diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index fd1b9dc080b..5320297dce2 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -640,6 +640,8 @@ class SEQUENCER_PT_sound(SequencerButtonsPanel, bpy.types.Panel): layout.prop(strip, "volume") layout.prop(strip, "attenuation") + layout.prop(strip, "pitch") + layout.prop(strip, "pan") col = layout.column(align=True) col.label(text="Trim Duration:") diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h index b791e29a38e..244fda33a52 100644 --- a/source/blender/blenkernel/BKE_fcurve.h +++ b/source/blender/blenkernel/BKE_fcurve.h @@ -199,7 +199,7 @@ struct FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int struct FCurve *iter_step_fcurve (struct FCurve *fcu_iter, const char rna_path[]); /* high level function to get an fcurve from C without having the rna */ -struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, const char *prop_name, int index); +struct FCurve *id_data_find_fcurve(ID *id, void *data, struct StructRNA *type, const char *prop_name, int index, char *driven); /* Get list of LinkData's containing pointers to the F-Curves which control the types of data indicated * e.g. numMatches = list_find_data_fcurves(matches, &act->curves, "pose.bones[", "MyFancyBone"); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 549dc475320..5ccb34338af 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -96,6 +96,16 @@ void sound_move_scene_sound(struct Scene *scene, void* handle, int startframe, i void sound_update_scene_sound(void* handle, struct bSound* sound); +void sound_set_cfra(int cfra); + +void sound_set_scene_volume(struct Scene *scene, float volume); + +void sound_set_scene_sound_volume(void* handle, float volume, char animated); + +void sound_set_scene_sound_pitch(void* handle, float pitch, char animated); + +void sound_set_scene_sound_pan(void* handle, float pan, char animated); + void sound_update_sequencer(struct Main* main, struct bSound* sound); void sound_play_scene(struct Scene *scene); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 1f45cc56117..aa8f817ae3c 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -174,7 +174,7 @@ void copy_fcurves (ListBase *dst, ListBase *src) /* ----------------- Finding F-Curves -------------------------- */ /* high level function to get an fcurve from C without having the rna */ -FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index) +FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *prop_name, int index, char *driven) { /* anim vars */ AnimData *adt= BKE_animdata_from_id(id); @@ -184,6 +184,9 @@ FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *pro PointerRNA ptr; PropertyRNA *prop; char *path; + + if(driven) + *driven = 0; /* only use the current action ??? */ if (ELEM(NULL, adt, adt->action)) @@ -201,11 +204,12 @@ FCurve *id_data_find_fcurve(ID *id, void *data, StructRNA *type, const char *pro fcu= list_find_fcurve(&adt->action->curves, path, index); /* if not animated, check if driven */ -#if 0 if ((fcu == NULL) && (adt->drivers.first)) { - fcu= list_find_fcurve(&adt->drivers, path, but->rnaindex); + fcu= list_find_fcurve(&adt->drivers, path, index); + if(fcu && driven) + *driven = 1; + fcu = NULL; } -#endif MEM_freeN(path); } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 42793e4b4a4..74126fd57a1 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -473,9 +473,10 @@ Scene *add_scene(const char *name) BLI_strncpy(sce->r.engine, "BLENDER_RENDER", sizeof(sce->r.engine)); - sce->audio.distance_model = 2.0; - sce->audio.doppler_factor = 1.0; - sce->audio.speed_of_sound = 343.3; + sce->audio.distance_model = 2.0f; + sce->audio.doppler_factor = 1.0f; + sce->audio.speed_of_sound = 343.3f; + sce->audio.volume = 1.0f; BLI_strncpy(sce->r.pic, U.renderdir, sizeof(sce->r.pic)); @@ -1000,6 +1001,8 @@ void scene_update_for_newframe(Main *bmain, Scene *sce, unsigned int lay) { float ctime = BKE_curframe(sce); Scene *sce_iter; + + sound_set_cfra(sce->r.cfra); /* clear animation overrides */ // XXX TODO... diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 688fdd8ff49..9e8cdb964b7 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -3163,7 +3163,7 @@ void sequence_effect_speed_rebuild_map(Scene *scene, Sequence * seq, int force) /* XXX - new in 2.5x. should we use the animation system this way? * The fcurve is needed because many frames need evaluating at once - campbell */ - fcu= id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0); + fcu= id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "speed_factor", 0, NULL); if (!v->frameMap || v->length != seq->len) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index e4dc3a31cb1..9ff3ce7afe2 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1775,7 +1775,7 @@ static ImBuf* seq_render_effect_strip_impl( facf= fac; } else { - fcu = id_data_find_fcurve(&context.scene->id, seq, &RNA_Sequence, "effect_fader", 0); + fcu = id_data_find_fcurve(&context.scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL); if (fcu) { fac = facf = evaluate_fcurve(fcu, cfra); if( context.scene->r.mode & R_FIELDS ) { @@ -3496,6 +3496,7 @@ Sequence *alloc_sequence(ListBase *lb, int cfra, int machine) seq->mul= 1.0; seq->blend_opacity = 100.0; seq->volume = 1.0f; + seq->pitch = 1.0f; seq->scene_sound = NULL; return seq; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index 64ba9ed362a..6e8b26c6ca6 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -32,10 +32,11 @@ #include "BKE_context.h" #include "BKE_library.h" #include "BKE_packedFile.h" -#include "BKE_fcurve.h" #include "BKE_animsys.h" #include "BKE_sequencer.h" +// evil global ;-) +static int sound_cfra; struct bSound* sound_new_file(struct Main *bmain, const char *filename) { @@ -411,6 +412,31 @@ void sound_update_scene_sound(void* handle, struct bSound* sound) AUD_updateSequenceSound(handle, sound->playback_handle); } +void sound_set_cfra(int cfra) +{ + sound_cfra = cfra; +} + +void sound_set_scene_volume(struct Scene *scene, float volume) +{ + AUD_setSequencerAnimData(scene->sound_scene, AUD_AP_VOLUME, CFRA, &volume, (scene->audio.flag & AUDIO_VOLUME_ANIMATED) != 0); +} + +void sound_set_scene_sound_volume(void* handle, float volume, char animated) +{ + AUD_setSequenceAnimData(handle, AUD_AP_VOLUME, sound_cfra, &volume, animated); +} + +void sound_set_scene_sound_pitch(void* handle, float pitch, char animated) +{ + AUD_setSequenceAnimData(handle, AUD_AP_PITCH, sound_cfra, &pitch, animated); +} + +void sound_set_scene_sound_pan(void* handle, float pan, char animated) +{ + AUD_setSequenceAnimData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated); +} + void sound_update_sequencer(struct Main* main, struct bSound* sound) { struct Scene* scene; diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 87f2a72cfe0..51cb4cc64ed 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -11507,12 +11507,6 @@ static void do_versions(FileData *fd, Library *lib, Main *main) kb->slidermax = kb->slidermin + 1.0f; } } - - { - Scene *scene; - for (scene=main->scene.first; scene; scene=scene->id.next) - scene->r.ffcodecdata.audio_channels = 2; - } } if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 1)) { @@ -11750,7 +11744,21 @@ static void do_versions(FileData *fd, Library *lib, Main *main) /* put compatibility code here until next subversion bump */ { - + + { + Scene *scene; + Sequence *seq; + + for (scene=main->scene.first; scene; scene=scene->id.next) + { + scene->r.ffcodecdata.audio_channels = 2; + scene->audio.volume = 1.0f; + SEQ_BEGIN(scene->ed, seq) { + seq->pitch = 1.0f; + } + SEQ_END + } + } } /* WATCH IT!!!: pointers from libdata have not been converted yet here! */ diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index b7e8fee922b..f0a0bcff3f3 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -41,6 +41,7 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "DNA_anim_types.h" #include "DNA_packedFile_types.h" #include "DNA_scene_types.h" #include "DNA_space_types.h" @@ -49,11 +50,14 @@ #include "DNA_userdef_types.h" #include "BKE_context.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_packedFile.h" +#include "BKE_scene.h" #include "BKE_sound.h" +#include "BKE_sequencer.h" #include "RNA_access.h" #include "RNA_define.h" @@ -293,6 +297,97 @@ static void SOUND_OT_unpack(wmOperatorType *ot) RNA_def_string(ot->srna, "id", "", MAX_ID_NAME-2, "Sound Name", "Sound datablock name to unpack."); /* XXX, weark!, will fail with library, name collisions */ } +/* ******************************************************* */ + +static int update_animation_flags_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Sequence* seq; + Scene* scene = CTX_data_scene(C); + struct FCurve* fcu; + char driven; + + SEQ_BEGIN(scene->ed, seq) { + fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "volume", 0, &driven); + if(fcu || driven) + seq->flag |= SEQ_AUDIO_VOLUME_ANIMATED; + else + seq->flag &= ~SEQ_AUDIO_VOLUME_ANIMATED; + + fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pitch", 0, &driven); + if(fcu || driven) + seq->flag |= SEQ_AUDIO_PITCH_ANIMATED; + else + seq->flag &= ~SEQ_AUDIO_PITCH_ANIMATED; + + fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "pan", 0, &driven); + if(fcu || driven) + seq->flag |= SEQ_AUDIO_PAN_ANIMATED; + else + seq->flag &= ~SEQ_AUDIO_PAN_ANIMATED; + } + SEQ_END + + fcu = id_data_find_fcurve(&scene->id, scene, &RNA_Scene, "audio_volume", 0, &driven); + if(fcu || driven) + scene->audio.flag |= AUDIO_VOLUME_ANIMATED; + else + scene->audio.flag &= ~AUDIO_VOLUME_ANIMATED; + + return OPERATOR_FINISHED; +} + +void SOUND_OT_update_animation_flags(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Update animation"; + ot->description= "Update animation flags"; + ot->idname= "SOUND_OT_update_animation_flags"; + + /* api callbacks */ + ot->exec= update_animation_flags_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER; +} + +/* ******************************************************* */ + +static int bake_animation_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main* bmain = CTX_data_main(C); + Scene* scene = CTX_data_scene(C); + int oldfra = scene->r.cfra; + int cfra; + + update_animation_flags_exec(C, NULL); + + for(cfra = scene->r.sfra; cfra <= scene->r.efra; cfra++) + { + scene->r.cfra = cfra; + scene_update_for_newframe(bmain, scene, scene->lay); + } + + scene->r.cfra = oldfra; + scene_update_for_newframe(bmain, scene, scene->lay); + + return OPERATOR_FINISHED; +} + +void SOUND_OT_bake_animation(wmOperatorType *ot) +{ + /* identifiers */ + ot->name= "Bake animation"; + ot->description= "Bakes the animation cache so that it's up to date"; + ot->idname= "SOUND_OT_bake_animation"; + + /* api callbacks */ + ot->exec= bake_animation_exec; + + /* flags */ + ot->flag= OPTYPE_REGISTER; +} + + /* ******************************************************* */ void ED_operatortypes_sound(void) @@ -300,4 +395,6 @@ void ED_operatortypes_sound(void) WM_operatortype_append(SOUND_OT_open); WM_operatortype_append(SOUND_OT_pack); WM_operatortype_append(SOUND_OT_unpack); + WM_operatortype_append(SOUND_OT_update_animation_flags); + WM_operatortype_append(SOUND_OT_bake_animation); } diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 937c33d6a65..b39f0a68854 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -149,6 +149,8 @@ typedef struct AudioData { int distance_model; short flag; short pad; + float volume; + float pad2; } AudioData; typedef struct SceneRenderLayer { @@ -1131,9 +1133,10 @@ typedef struct Scene { #define F_DUPLI 3 /* audio->flag */ -#define AUDIO_MUTE 1 -#define AUDIO_SYNC 2 -#define AUDIO_SCRUB 4 +#define AUDIO_MUTE (1<<0) +#define AUDIO_SYNC (1<<1) +#define AUDIO_SCRUB (1<<2) +#define AUDIO_VOLUME_ANIMATED (1<<3) #define FFMPEG_MULTIPLEX_AUDIO 1 /* deprecated, you can choose none as audiocodec now */ #define FFMPEG_AUTOSPLIT_OUTPUT 2 diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index b9bea7a89b0..aa04dc9ac13 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -155,7 +155,7 @@ typedef struct Sequence { void *scene_sound; float volume; - float level, pan; /* level in dB (0=full), pan -1..1 */ + float pitch, pan; /* pitch (-0.1..10), pan -2..2 */ int scenenr; /* for scene selection */ int multicam_source; /* for multicam source selection */ float strobe; @@ -284,6 +284,11 @@ typedef struct SpeedControlVars { #define SEQ_USE_PROXY_CUSTOM_FILE (1<<21) #define SEQ_USE_EFFECT_DEFAULT_FADE (1<<22) +// flags for whether those properties are animated or not +#define SEQ_AUDIO_VOLUME_ANIMATED (1<<24) +#define SEQ_AUDIO_PITCH_ANIMATED (1<<25) +#define SEQ_AUDIO_PAN_ANIMATED (1<<26) + #define SEQ_INVALID_EFFECT (1<<31) /* convenience define for all selection flags */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 3a3a805f3ce..8f24048bc04 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -337,6 +337,15 @@ static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA * sound_update_fps(scene); } +static void rna_Scene_volume_set(PointerRNA *ptr, float value) +{ + Scene *scene= (Scene*)(ptr->data); + + scene->audio.volume = value; + if(scene->sound_scene) + sound_set_scene_volume(scene, value); +} + static void rna_Scene_framelen_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) { scene->r.framelen= (float)scene->r.framapto/(float)scene->r.images; @@ -2469,30 +2478,35 @@ static void rna_def_scene_render_data(BlenderRNA *brna) /* 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_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, ffmpeg_audio_codec_items); RNA_def_property_ui_text(prop, "Audio Codec", "FFMpeg audio codec to use"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "ffmpeg_audio_bitrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "ffcodecdata.audio_bitrate"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 32, 384); 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_audio_mixrate", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "ffcodecdata.audio_mixrate"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 8000, 192000); RNA_def_property_ui_text(prop, "Samplerate", "Audio samplerate(samples/s)"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "ffmpeg_audio_volume", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "ffcodecdata.audio_volume"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Volume", "Audio volume"); RNA_def_property_update(prop, NC_SCENE|ND_RENDER_OPTIONS, NULL); prop= RNA_def_property(srna, "ffmpeg_audio_channels", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "ffcodecdata.audio_channels"); + RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); RNA_def_property_enum_items(prop, audio_channel_items); RNA_def_property_ui_text(prop, "Audio Channels", "Sets the audio channel count"); #endif @@ -3464,6 +3478,13 @@ void RNA_def_scene(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Distance Model", "Distance model for distance attenuation calculation"); RNA_def_property_update(prop, NC_SCENE, NULL); + prop= RNA_def_property(srna, "audio_volume", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "audio.volume"); + RNA_def_property_range(prop, 0.0f, 1.0f); + RNA_def_property_ui_text(prop, "Volume", "Audio volume"); + RNA_def_property_update(prop, NC_SCENE, NULL); + RNA_def_property_float_funcs(prop, NULL, "rna_Scene_volume_set", NULL); + /* Game Settings */ prop= RNA_def_property(srna, "game_settings", PROP_POINTER, PROP_NONE); RNA_def_property_flag(prop, PROP_NEVER_NULL); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 3dab8266c2f..0c889fd111f 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -43,6 +43,7 @@ #include "BKE_animsys.h" #include "BKE_global.h" #include "BKE_sequencer.h" +#include "BKE_sound.h" #include "MEM_guardedalloc.h" @@ -527,6 +528,33 @@ static void rna_Sequence_attenuation_set(PointerRNA *ptr, float value) seq->volume = from_dB(value); } +static void rna_Sequence_volume_set(PointerRNA *ptr, float value) +{ + Sequence *seq= (Sequence*)(ptr->data); + + seq->volume = value; + if(seq->scene_sound) + sound_set_scene_sound_volume(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0); +} + +static void rna_Sequence_pitch_set(PointerRNA *ptr, float value) +{ + Sequence *seq= (Sequence*)(ptr->data); + + seq->pitch = value; + if(seq->scene_sound) + sound_set_scene_sound_pitch(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0); +} + +static void rna_Sequence_pan_set(PointerRNA *ptr, float value) +{ + Sequence *seq= (Sequence*)(ptr->data); + + seq->pan = value; + if(seq->scene_sound) + sound_set_scene_sound_pan(seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0); +} + static int rna_Sequence_input_count_get(PointerRNA *ptr) { @@ -558,9 +586,6 @@ static void rna_Sequence_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *p Editing *ed= seq_give_editing(scene, FALSE); free_imbuf_seq(scene, &ed->seqbase, FALSE, TRUE); - - if(RNA_struct_is_a(ptr->type, &RNA_SoundSequence)) - seq_update_sound_bounds(scene, ptr->data); } static void rna_Sequence_update_reopen_files(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) @@ -1368,13 +1393,27 @@ static void rna_def_sound(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "volume"); RNA_def_property_range(prop, 0.0f, 100.0f); RNA_def_property_ui_text(prop, "Volume", "Playback volume of the sound"); + RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_volume_set", NULL); RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); prop= RNA_def_property(srna, "attenuation", PROP_FLOAT, PROP_NONE); RNA_def_property_range(prop, -100.0f, +40.0f); RNA_def_property_ui_text(prop, "Attenuation/dB", "Attenuation in decibel"); RNA_def_property_float_funcs(prop, "rna_Sequence_attenuation_get", "rna_Sequence_attenuation_set", NULL); + RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); + prop= RNA_def_property(srna, "pitch", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "pitch"); + RNA_def_property_range(prop, 0.1f, 10.0f); + RNA_def_property_ui_text(prop, "Pitch", "Playback pitch of the sound"); + RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_pitch_set", NULL); + RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); + + prop= RNA_def_property(srna, "pan", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "pan"); + RNA_def_property_range(prop, -2.0f, 2.0f); + RNA_def_property_ui_text(prop, "Pan", "Playback panning of the sound (only for Mono sources)"); + RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_pan_set", NULL); RNA_def_property_update(prop, NC_SCENE|ND_SEQUENCER, "rna_Sequence_update"); prop= RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);