Sound: Port to a copy-on-write concept

This change makes it so sound handles are created for evaluated scene,
sequencer and speakers. This allows to have properly evaluated animation
on them.

For the viewport playback sound uses regular dependency graph.

For the final render sound uses dependency graph created for render pipeline,
which now also contains sequencer and sound datablocks.

All the direct sound update calls are replaced with corresponding dependency
graph recalc tag.
This commit is contained in:
Sergey Sharybin 2019-06-04 16:52:48 +02:00
parent 863b7b3668
commit bbaa1bffe9
Notes: blender-bot 2023-02-14 04:40:22 +01:00
Referenced by issue #65806, Can't Access bpy.context inside Application Timer
Referenced by issue #62653, Crashing with animation rendering and sound
44 changed files with 887 additions and 279 deletions

View File

@ -116,7 +116,8 @@ bool BKE_movieclip_put_frame_if_possible(struct MovieClip *clip,
struct MovieClipUser *user,
struct ImBuf *ibuf);
/* Evaluation. */
/* Dependency graph evaluation. */
void BKE_movieclip_eval_update(struct Depsgraph *depsgraph, struct MovieClip *clip);
void BKE_movieclip_eval_selection_update(struct Depsgraph *depsgraph, struct MovieClip *clip);

View File

@ -246,6 +246,14 @@ void BKE_scene_cursor_from_mat4(struct View3DCursor *cursor,
const float mat[4][4],
bool use_compat);
/* Dependency graph evaluation. */
/* Evaluate parts of sequences which needs to be done as a part of a dependency graph evaluation.
* This does NOT include actual rendering of the strips, but rather makes them up-to-date for
* animation playback and makes them ready for the sequencer's rendering pipeline to render them.
*/
void BKE_scene_eval_sequencer_sequences(struct Depsgraph *depsgraph, struct Scene *scene);
#ifdef __cplusplus
}
#endif

View File

@ -32,6 +32,7 @@
struct Main;
struct Sequence;
struct bSound;
struct Depsgraph;
typedef struct SoundWaveform {
int length;
@ -71,10 +72,17 @@ void BKE_sound_cache(struct bSound *sound);
void BKE_sound_delete_cache(struct bSound *sound);
void BKE_sound_reset_runtime(struct bSound *sound);
void BKE_sound_load(struct Main *main, struct bSound *sound);
void BKE_sound_ensure_loaded(struct Main *bmain, struct bSound *sound);
void BKE_sound_free(struct bSound *sound);
/* Is used by sequencer to temporarily load audio to access information about channels and
* duration. */
void BKE_sound_load_audio(struct Main *main, struct bSound *sound);
void BKE_sound_free_audio(struct bSound *sound);
void BKE_sound_copy_data(struct Main *bmain,
struct bSound *sound_dst,
const struct bSound *sound_src,
@ -86,7 +94,9 @@ void BKE_sound_make_local(struct Main *bmain, struct bSound *sound, const bool l
AUD_Device *BKE_sound_mixdown(struct Scene *scene, AUD_DeviceSpecs specs, int start, float volume);
#endif
void BKE_sound_reset_scene_runtime(struct Scene *scene);
void BKE_sound_create_scene(struct Scene *scene);
void BKE_sound_ensure_scene(struct Scene *scene);
void BKE_sound_destroy_scene(struct Scene *scene);
@ -150,4 +160,15 @@ float BKE_sound_get_length(struct bSound *sound);
char **BKE_sound_get_device_names(void);
typedef void (*SoundJackSyncCallback)(struct Main *bmain, int mode, float time);
void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback);
void BKE_sound_jack_scene_update(struct Scene *scene, int mode, float time);
/* Dependency graph evaluation. */
struct Depsgraph;
void BKE_sound_evaluate(struct Depsgraph *depsgraph, struct Main *bmain, struct bSound *sound);
#endif /* __BKE_SOUND_H__ */

View File

@ -37,6 +37,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_windowmanager_types.h"
@ -308,8 +309,7 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
flag_subdata);
}
/* before scene copy */
BKE_sound_create_scene(sce_dst);
BKE_sound_reset_scene_runtime(sce_dst);
/* Copy sequencer, this is local data! */
if (sce_src->ed) {
@ -399,8 +399,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
sce_copy->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties);
}
/* before scene copy */
BKE_sound_create_scene(sce_copy);
BKE_sound_reset_scene_runtime(sce_copy);
/* grease pencil */
sce_copy->gpd = NULL;
@ -779,7 +778,7 @@ void BKE_scene_init(Scene *sce)
srv = sce->r.views.last;
BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
BKE_sound_create_scene(sce);
BKE_sound_reset_scene_runtime(sce);
/* color management */
colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_SEQUENCER);
@ -1507,6 +1506,30 @@ static void prepare_mesh_for_viewport_render(Main *bmain, const ViewLayer *view_
}
}
static void scene_update_sound(Depsgraph *depsgraph, Main *bmain)
{
Scene *scene = DEG_get_evaluated_scene(depsgraph);
const int recalc = scene->id.recalc;
BKE_sound_ensure_scene(scene);
if (recalc & ID_RECALC_AUDIO_SEEK) {
BKE_sound_seek_scene(bmain, scene);
}
if (recalc & ID_RECALC_AUDIO_FPS) {
BKE_sound_update_fps(scene);
}
if (recalc & ID_RECALC_AUDIO_VOLUME) {
BKE_sound_set_scene_volume(scene, scene->audio.volume);
}
if (recalc & ID_RECALC_AUDIO_MUTE) {
const bool is_mute = (scene->audio.flag & AUDIO_MUTE);
BKE_sound_mute_scene(scene, is_mute);
}
if (recalc & ID_RECALC_AUDIO_LISTENER) {
BKE_sound_update_scene_listener(scene);
}
BKE_sound_update_scene(bmain, scene);
}
/* TODO(sergey): This actually should become view_layer_graph or so.
* Same applies to update_for_newframe.
*
@ -1542,10 +1565,9 @@ static void scene_graph_update_tagged(Depsgraph *depsgraph, Main *bmain, bool on
* by depgraph or manual, no layer check here, gets correct flushed.
*/
DEG_evaluate_on_refresh(depsgraph);
/* Update sound system animation (TODO, move to depsgraph). */
BKE_sound_update_scene(bmain, scene);
/* Notify python about depsgraph update */
/* Update sound system. */
scene_update_sound(depsgraph, bmain);
/* Notify python about depsgraph update. */
if (run_callbacks) {
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_DEPSGRAPH_UPDATE_POST);
}
@ -1590,8 +1612,8 @@ void BKE_scene_graph_update_for_newframe(Depsgraph *depsgraph, Main *bmain)
* by depgraph or manual, no layer check here, gets correct flushed.
*/
DEG_evaluate_on_framechange(bmain, depsgraph, ctime);
/* Update sound system animation (TODO, move to depsgraph). */
BKE_sound_update_scene(bmain, scene);
/* Update sound system animation. */
scene_update_sound(depsgraph, bmain);
/* Notify editors and python about recalc. */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_FRAME_CHANGE_POST);
/* Inform editors about possible changes. */
@ -2420,3 +2442,31 @@ void BKE_scene_cursor_from_mat4(View3DCursor *cursor, const float mat[4][4], boo
}
/** \} */
/* Dependency graph evaluation. */
void BKE_scene_eval_sequencer_sequences(Depsgraph *depsgraph, Scene *scene)
{
DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene);
if (scene->ed == NULL) {
return;
}
BKE_sound_ensure_scene(scene);
Sequence *seq;
SEQ_BEGIN (scene->ed, seq) {
if (seq->sound != NULL && seq->scene_sound == NULL) {
seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
}
if (seq->scene_sound) {
BKE_sound_set_scene_sound_volume(
seq->scene_sound, seq->volume, (seq->flag & SEQ_AUDIO_VOLUME_ANIMATED) != 0);
BKE_sound_set_scene_sound_pitch(
seq->scene_sound, seq->pitch, (seq->flag & SEQ_AUDIO_PITCH_ANIMATED) != 0);
BKE_sound_set_scene_sound_pan(
seq->scene_sound, seq->pan, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
}
}
SEQ_END;
BKE_sequencer_update_muting(scene->ed);
BKE_sequencer_update_sound_bounds_all(scene);
}

View File

@ -808,10 +808,7 @@ void BKE_sequence_calc_disp(Scene *scene, Sequence *seq)
seq->handsize = (float)((seq->enddisp - seq->startdisp) / 25);
}
if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SCENE)) {
BKE_sequencer_update_sound_bounds(scene, seq);
}
else if (seq->type == SEQ_TYPE_META) {
if (seq->type == SEQ_TYPE_META) {
seq_update_sound_bounds_recursive(scene, seq);
}
}
@ -5505,17 +5502,18 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
Strip *strip;
StripElem *se;
AUD_SoundInfo info;
sound = BKE_sound_new_file(bmain, seq_load->path); /* handles relative paths */
/* Load the original sound, so we can access number of channels and length information.
* We free the sound handle on the original bSound datablock before existing this function, it is
* to be allocated on an evaluated version after this. */
BKE_sound_load_audio(bmain, sound);
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
if (sound->playback_handle == NULL) {
BKE_id_free(bmain, sound);
return NULL;
}
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
BKE_id_free(bmain, sound);
return NULL;
@ -5537,8 +5535,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
BLI_split_dirfile(seq_load->path, strip->dir, se->name, sizeof(strip->dir), sizeof(se->name));
seq->scene_sound = BKE_sound_add_scene_sound(
scene, seq, seq_load->start_frame, seq_load->start_frame + seq->len, 0);
seq->scene_sound = NULL;
BKE_sequence_calc_disp(scene, seq);
@ -5547,6 +5544,11 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad
seq_load_apply(bmain, scene, seq, seq_load);
BKE_sound_free_audio(sound);
/* TODO(sergey): Shall we tag here or in the oeprator? */
DEG_relations_tag_update(bmain);
return seq;
}
#else // WITH_AUDASPACE
@ -5755,10 +5757,7 @@ static Sequence *seq_dupli(const Scene *scene_src,
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
seqn->strip->stripdata = MEM_dupallocN(seq->strip->stripdata);
if (seq->scene_sound) {
seqn->scene_sound = BKE_sound_add_scene_sound_defaults(scene_dst, seqn);
}
seqn->scene_sound = NULL;
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) {
id_us_plus((ID *)seqn->sound);
}

View File

@ -38,6 +38,7 @@
#include "DNA_screen_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_windowmanager_types.h"
#ifdef WITH_AUDASPACE
# include <AUD_Sound.h>
@ -55,12 +56,36 @@
#include "BKE_sequencer.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
#ifdef WITH_AUDASPACE
/* evil globals ;-) */
static int sound_cfra;
static char **audio_device_names = NULL;
#endif
BLI_INLINE void sound_verify_evaluated_id(ID *id)
{
UNUSED_VARS_NDEBUG(id);
/* This is a bit tricky and not quite reliable, but good enough check.
*
* We don't want audio system handles to be allocated on amn original datablocks, and only want
* them to be allocated on a datablocks which are result of dependency graph evaluation.
*
* Datablocks which are covered by a copy-on-write system of dependency graph will have
* LIB_TAG_COPIED_ON_WRITE tag set on them. But if some of datablocks during its evaluation
* decides to re-allocate it's nested one (for example, object evaluation could re-allocate mesh
* when evaluating modifier stack). Such datablocks will have LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT
* tag set on them.
*
* Additionally, we also allow datablocks outside of main database. Those can not be "original"
* and could be used as a temporary evaluated result during operations like baking.
*
* NOTE: We conder ID evaluated if ANY of those flags is set. We do NOT require ALL of them. */
BLI_assert(id->tag &
(LIB_TAG_COPIED_ON_WRITE | LIB_TAG_COPIED_ON_WRITE_EVAL_RESULT | LIB_TAG_NO_MAIN));
}
bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
{
bSound *sound;
@ -77,7 +102,10 @@ bSound *BKE_sound_new_file(Main *bmain, const char *filepath)
BLI_strncpy(sound->name, filepath, FILE_MAX);
/* sound->type = SOUND_TYPE_FILE; */ /* XXX unused currently */
BKE_sound_load(bmain, sound);
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound->spinlock);
BKE_sound_reset_runtime(sound);
return sound;
}
@ -125,6 +153,18 @@ void BKE_sound_free(bSound *sound)
sound->packedfile = NULL;
}
BKE_sound_free_audio(sound);
BKE_sound_free_waveform(sound);
if (sound->spinlock) {
BLI_spin_end(sound->spinlock);
MEM_freeN(sound->spinlock);
sound->spinlock = NULL;
}
}
void BKE_sound_free_audio(bSound *sound)
{
#ifdef WITH_AUDASPACE
if (sound->handle) {
AUD_Sound_free(sound->handle);
@ -136,15 +176,9 @@ void BKE_sound_free(bSound *sound)
AUD_Sound_free(sound->cache);
sound->cache = NULL;
}
BKE_sound_free_waveform(sound);
#else
UNUSED_VARS(sound);
#endif /* WITH_AUDASPACE */
if (sound->spinlock) {
BLI_spin_end(sound->spinlock);
MEM_freeN(sound->spinlock);
sound->spinlock = NULL;
}
}
/**
@ -157,7 +191,7 @@ void BKE_sound_free(bSound *sound)
*
* \param flag: Copying options (see BKE_library.h's LIB_ID_COPY_... flags for more).
*/
void BKE_sound_copy_data(Main *bmain,
void BKE_sound_copy_data(Main *UNUSED(bmain),
bSound *sound_dst,
const bSound *UNUSED(sound_src),
const int UNUSED(flag))
@ -166,8 +200,8 @@ void BKE_sound_copy_data(Main *bmain,
sound_dst->cache = NULL;
sound_dst->waveform = NULL;
sound_dst->playback_handle = NULL;
sound_dst->spinlock =
NULL; /* Think this is OK? Otherwise, easy to create new spinlock here... */
sound_dst->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound_dst->spinlock);
/* Just to be sure, should not have any value actually after reading time. */
sound_dst->ipo = NULL;
@ -177,8 +211,7 @@ void BKE_sound_copy_data(Main *bmain,
sound_dst->packedfile = dupPackedFile(sound_dst->packedfile);
}
/* Initialize whole runtime (audaspace) stuff. */
BKE_sound_load(bmain, sound_dst);
BKE_sound_reset_runtime(sound_dst);
}
void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
@ -191,31 +224,15 @@ void BKE_sound_make_local(Main *bmain, bSound *sound, const bool lib_local)
static const char *force_device = NULL;
# ifdef WITH_JACK
static SoundJackSyncCallback sound_jack_sync_callback = NULL;
static void sound_sync_callback(void *data, int mode, float time)
{
// Ugly: Blender doesn't like it when the animation is played back during rendering
if (G.is_rendering) {
if (sound_jack_sync_callback == NULL) {
return;
}
Main *bmain = (Main *)data;
Scene *scene;
scene = bmain->scenes.first;
while (scene) {
if (scene->audio.flag & AUDIO_SYNC) {
if (mode) {
BKE_sound_play_scene(scene);
}
else {
BKE_sound_stop_scene(scene);
}
if (scene->playback_handle) {
AUD_Handle_setPosition(scene->playback_handle, time);
}
}
scene = scene->id.next;
}
sound_jack_sync_callback(bmain, mode, time);
}
# endif
@ -298,7 +315,7 @@ void BKE_sound_init_main(Main *bmain)
AUD_setSynchronizerCallback(sound_sync_callback, bmain);
}
# else
(void)bmain; /* unused */
UNUSED_VARS(bmain);
# endif
}
@ -367,6 +384,8 @@ bSound *BKE_sound_new_limiter(Main *bmain, bSound *source, float start, float en
void BKE_sound_cache(bSound *sound)
{
sound_verify_evaluated_id(&sound->id);
sound->flags |= SOUND_FLAGS_CACHING;
if (sound->cache) {
AUD_Sound_free(sound->cache);
@ -393,44 +412,50 @@ void BKE_sound_delete_cache(bSound *sound)
void BKE_sound_load(Main *bmain, bSound *sound)
{
if (sound) {
if (sound->cache) {
AUD_Sound_free(sound->cache);
sound->cache = NULL;
}
sound_verify_evaluated_id(&sound->id);
BKE_sound_load_audio(bmain, sound);
}
if (sound->handle) {
AUD_Sound_free(sound->handle);
sound->handle = NULL;
sound->playback_handle = NULL;
}
void BKE_sound_load_audio(Main *bmain, bSound *sound)
{
BKE_sound_free_waveform(sound);
if (sound->cache) {
AUD_Sound_free(sound->cache);
sound->cache = NULL;
}
if (sound->handle) {
AUD_Sound_free(sound->handle);
sound->handle = NULL;
sound->playback_handle = NULL;
}
BKE_sound_free_waveform(sound);
/* XXX unused currently */
# if 0
switch (sound->type) {
case SOUND_TYPE_FILE:
# endif
{
char fullpath[FILE_MAX];
{
char fullpath[FILE_MAX];
/* load sound */
PackedFile *pf = sound->packedfile;
/* load sound */
PackedFile *pf = sound->packedfile;
/* don't modify soundact->sound->name, only change a copy */
BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
BLI_path_abs(fullpath, ID_BLEND_PATH(bmain, &sound->id));
/* don't modify soundact->sound->name, only change a copy */
BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
BLI_path_abs(fullpath, ID_BLEND_PATH(bmain, &sound->id));
/* but we need a packed file then */
if (pf) {
sound->handle = AUD_Sound_bufferFile((unsigned char *)pf->data, pf->size);
}
else {
/* or else load it from disk */
sound->handle = AUD_Sound_file(fullpath);
}
/* but we need a packed file then */
if (pf) {
sound->handle = AUD_Sound_bufferFile((unsigned char *)pf->data, pf->size);
}
else {
/* or else load it from disk */
sound->handle = AUD_Sound_file(fullpath);
}
}
/* XXX unused currently */
# if 0
break;
@ -447,34 +472,34 @@ void BKE_sound_load(Main *bmain, bSound *sound)
break;
}
# endif
if (sound->flags & SOUND_FLAGS_MONO) {
void *handle = AUD_Sound_rechannel(sound->handle, AUD_CHANNELS_MONO);
AUD_Sound_free(sound->handle);
sound->handle = handle;
}
if (sound->flags & SOUND_FLAGS_MONO) {
void *handle = AUD_Sound_rechannel(sound->handle, AUD_CHANNELS_MONO);
AUD_Sound_free(sound->handle);
sound->handle = handle;
}
if (sound->flags & SOUND_FLAGS_CACHING) {
sound->cache = AUD_Sound_cache(sound->handle);
}
if (sound->flags & SOUND_FLAGS_CACHING) {
sound->cache = AUD_Sound_cache(sound->handle);
}
if (sound->cache) {
sound->playback_handle = sound->cache;
}
else {
sound->playback_handle = sound->handle;
}
BKE_sound_update_sequencer(bmain, sound);
if (sound->cache) {
sound->playback_handle = sound->cache;
}
else {
sound->playback_handle = sound->handle;
}
}
AUD_Device *BKE_sound_mixdown(Scene *scene, AUD_DeviceSpecs specs, int start, float volume)
{
sound_verify_evaluated_id(&scene->id);
return AUD_openMixdownDevice(specs, scene->sound_scene, volume, start / FPS);
}
void BKE_sound_create_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
/* should be done in version patch, but this gets called before */
if (scene->r.frs_sec_base == 0) {
scene->r.frs_sec_base = 1;
@ -507,16 +532,21 @@ void BKE_sound_destroy_scene(Scene *scene)
void BKE_sound_reset_scene_specs(Scene *scene)
{
AUD_Specs specs;
sound_verify_evaluated_id(&scene->id);
specs.channels = AUD_Device_getChannels(sound_device);
specs.rate = AUD_Device_getRate(sound_device);
if (scene->sound_scene) {
AUD_Specs specs;
AUD_Sequence_setSpecs(scene->sound_scene, specs);
specs.channels = AUD_Device_getChannels(sound_device);
specs.rate = AUD_Device_getRate(sound_device);
AUD_Sequence_setSpecs(scene->sound_scene, specs);
}
}
void BKE_sound_mute_scene(Scene *scene, int muted)
{
sound_verify_evaluated_id(&scene->id);
if (scene->sound_scene) {
AUD_Sequence_setMuted(scene->sound_scene, muted);
}
@ -524,6 +554,8 @@ void BKE_sound_mute_scene(Scene *scene, int muted)
void BKE_sound_update_fps(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
if (scene->sound_scene) {
AUD_Sequence_setFPS(scene->sound_scene, FPS);
}
@ -533,6 +565,8 @@ void BKE_sound_update_fps(Scene *scene)
void BKE_sound_update_scene_listener(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
AUD_Sequence_setSpeedOfSound(scene->sound_scene, scene->audio.speed_of_sound);
AUD_Sequence_setDopplerFactor(scene->sound_scene, scene->audio.doppler_factor);
AUD_Sequence_setDistanceModel(scene->sound_scene, scene->audio.distance_model);
@ -541,6 +575,7 @@ void BKE_sound_update_scene_listener(Scene *scene)
void *BKE_sound_scene_add_scene_sound(
Scene *scene, Sequence *sequence, int startframe, int endframe, int frameskip)
{
sound_verify_evaluated_id(&scene->id);
if (sequence->scene && scene != sequence->scene) {
const double fps = FPS;
return AUD_Sequence_add(scene->sound_scene,
@ -564,6 +599,7 @@ void *BKE_sound_scene_add_scene_sound_defaults(Scene *scene, Sequence *sequence)
void *BKE_sound_add_scene_sound(
Scene *scene, Sequence *sequence, int startframe, int endframe, int frameskip)
{
sound_verify_evaluated_id(&scene->id);
/* Happens when sequence's sound datablock was removed. */
if (sequence->sound == NULL) {
return NULL;
@ -603,12 +639,14 @@ void BKE_sound_mute_scene_sound(void *handle, char mute)
void BKE_sound_move_scene_sound(
Scene *scene, void *handle, int startframe, int endframe, int frameskip)
{
sound_verify_evaluated_id(&scene->id);
const double fps = FPS;
AUD_SequenceEntry_move(handle, startframe / fps, endframe / fps, frameskip / fps);
}
void BKE_sound_move_scene_sound_defaults(Scene *scene, Sequence *sequence)
{
sound_verify_evaluated_id(&scene->id);
if (sequence->scene_sound) {
BKE_sound_move_scene_sound(scene,
sequence->scene_sound,
@ -630,6 +668,7 @@ void BKE_sound_set_cfra(int cfra)
void BKE_sound_set_scene_volume(Scene *scene, float volume)
{
sound_verify_evaluated_id(&scene->id);
AUD_Sequence_setAnimationData(scene->sound_scene,
AUD_AP_VOLUME,
CFRA,
@ -649,12 +688,13 @@ void BKE_sound_set_scene_sound_pitch(void *handle, float pitch, char animated)
void BKE_sound_set_scene_sound_pan(void *handle, float pan, char animated)
{
printf("%s\n", __func__);
AUD_SequenceEntry_setAnimationData(handle, AUD_AP_PANNING, sound_cfra, &pan, animated);
}
void BKE_sound_update_sequencer(Main *main, bSound *sound)
{
BLI_assert(!"is not supposed to be used, is weird function.");
Scene *scene;
for (scene = main->scenes.first; scene; scene = scene->id.next) {
@ -664,6 +704,8 @@ void BKE_sound_update_sequencer(Main *main, bSound *sound)
static void sound_start_play_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
if (scene->playback_handle) {
AUD_Handle_stop(scene->playback_handle);
}
@ -677,6 +719,8 @@ static void sound_start_play_scene(Scene *scene)
void BKE_sound_play_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
AUD_Status status;
const float cur_time = (float)((double)CFRA / FPS);
@ -719,6 +763,8 @@ void BKE_sound_stop_scene(Scene *scene)
void BKE_sound_seek_scene(Main *bmain, Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
AUD_Status status;
bScreen *screen;
int animation_playing;
@ -783,6 +829,8 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
float BKE_sound_sync_scene(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
// Ugly: Blender doesn't like it when the animation is played back during rendering
if (G.is_rendering) {
return NAN_FLT;
@ -801,6 +849,8 @@ float BKE_sound_sync_scene(Scene *scene)
int BKE_sound_scene_playing(Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
// Ugly: Blender doesn't like it when the animation is played back during rendering
if (G.is_rendering) {
return -1;
@ -836,6 +886,9 @@ void BKE_sound_free_waveform(bSound *sound)
sound->tags &= ~SOUND_TAGS_WAVEFORM_NO_RELOAD;
}
/* TODO(sergey): Consider mamakinging this function fully autonomous, as in, not require having
* an existing playback handle. That would make it easy to read waveforms, which doesn't seem to
* be affected by evaluated scene (waveworm comes from file). */
void BKE_sound_read_waveform(bSound *sound, short *stop)
{
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
@ -884,11 +937,14 @@ static void sound_update_base(Scene *scene, Base *base, void *new_set)
Speaker *speaker;
float quat[4];
if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
return;
}
sound_verify_evaluated_id(&scene->id);
sound_verify_evaluated_id(&ob->id);
ob->id.tag &= ~LIB_TAG_DOIT;
// TODO(sergey): Bring the test back, or make it a part of dependency graph update.
// if ((ob->id.tag & LIB_TAG_DOIT) == 0) {
// return;
// }
// ob->id.tag &= ~LIB_TAG_DOIT;
if ((ob->type != OB_SPEAKER) || !ob->adt) {
return;
@ -951,6 +1007,8 @@ static void sound_update_base(Scene *scene, Base *base, void *new_set)
void BKE_sound_update_scene(Main *bmain, Scene *scene)
{
sound_verify_evaluated_id(&scene->id);
Base *base;
Scene *sce_it;
@ -960,7 +1018,8 @@ void BKE_sound_update_scene(Main *bmain, Scene *scene)
/* cheap test to skip looping over all objects (no speakers is a common case) */
if (!BLI_listbase_is_empty(&bmain->speakers)) {
BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
// TODO(sergey): Bring the test back, or make it a part of dependency graph update.
// BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true);
for (ViewLayer *view_layer = scene->view_layers.first; view_layer;
view_layer = view_layer->next) {
@ -997,6 +1056,7 @@ void *BKE_sound_get_factory(void *sound)
/* stupid wrapper because AUD_C-API.h includes Python.h which makesrna doesn't like */
float BKE_sound_get_length(bSound *sound)
{
sound_verify_evaluated_id(&sound->id);
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
return info.length;
@ -1159,4 +1219,81 @@ char **BKE_sound_get_device_names(void)
return names;
}
void BKE_sound_free_waveform(bSound *UNUSED(sound))
{
}
void BKE_sound_load_audio(Main *UNUSED(bmain), bSound *UNUSED(sound))
{
}
#endif /* WITH_AUDASPACE */
void BKE_sound_reset_scene_runtime(Scene *scene)
{
scene->sound_scene = NULL;
scene->playback_handle = NULL;
scene->sound_scrub_handle = NULL;
scene->speaker_handles = NULL;
}
void BKE_sound_ensure_scene(struct Scene *scene)
{
if (scene->sound_scene != NULL) {
return;
}
BKE_sound_create_scene(scene);
}
void BKE_sound_reset_runtime(bSound *sound)
{
sound->cache = NULL;
sound->playback_handle = NULL;
}
void BKE_sound_ensure_loaded(Main *bmain, bSound *sound)
{
if (sound->cache != NULL) {
return;
}
BKE_sound_load(bmain, sound);
}
void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback)
{
#if defined(WITH_AUDASPACE) && defined(WITH_JACK)
sound_jack_sync_callback = callback;
#else
UNUSED_VARS(callback);
#endif
}
void BKE_sound_jack_scene_update(Scene *scene, int mode, float time)
{
sound_verify_evaluated_id(&scene->id);
/* Ugly: Blender doesn't like it when the animation is played back during rendering. */
if (G.is_rendering) {
return;
}
if (mode) {
BKE_sound_play_scene(scene);
}
else {
BKE_sound_stop_scene(scene);
}
#ifdef WITH_AUDASPACE
if (scene->playback_handle != NULL) {
AUD_Handle_setPosition(scene->playback_handle, time);
}
#else
UNUSED_VARS(time);
#endif
}
void BKE_sound_evaluate(Depsgraph *depsgraph, Main *bmain, bSound *sound)
{
DEG_debug_print_eval(depsgraph, __func__, sound->id.name, sound);
BKE_sound_ensure_loaded(bmain, sound);
}

View File

@ -6462,9 +6462,7 @@ static void lib_link_scene(FileData *fd, Main *main)
seq->scene_sound = NULL;
if (seq->scene) {
seq->scene = newlibadr(fd, sce->id.lib, seq->scene);
if (seq->scene) {
seq->scene_sound = BKE_sound_scene_add_scene_sound_defaults(sce, seq);
}
seq->scene_sound = NULL;
}
if (seq->clip) {
seq->clip = newlibadr_us(fd, sce->id.lib, seq->clip);
@ -6485,7 +6483,7 @@ static void lib_link_scene(FileData *fd, Main *main)
}
if (seq->sound) {
id_us_plus_no_lib((ID *)seq->sound);
seq->scene_sound = BKE_sound_add_scene_sound_defaults(sce, seq);
seq->scene_sound = NULL;
}
}
if (seq->type == SEQ_TYPE_TEXT) {
@ -6504,9 +6502,6 @@ static void lib_link_scene(FileData *fd, Main *main)
}
}
BKE_sequencer_update_muting(sce->ed);
BKE_sequencer_update_sound_bounds_all(sce);
/* rigidbody world relies on it's linked collections */
if (sce->rigidbody_world) {
RigidBodyWorld *rbw = sce->rigidbody_world;
@ -6685,7 +6680,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
memset(&sce->customdata_mask, 0, sizeof(sce->customdata_mask));
memset(&sce->customdata_mask_modal, 0, sizeof(sce->customdata_mask_modal));
BKE_sound_create_scene(sce);
BKE_sound_reset_scene_runtime(sce);
/* set users to one by default, not in lib-link, this will increase it for compo nodes */
id_us_ensure_real(&sce->id);
@ -8395,10 +8390,9 @@ static void direct_link_sound(FileData *fd, bSound *sound)
sound->waveform = NULL;
}
if (sound->spinlock) {
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound->spinlock);
}
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound->spinlock);
/* clear waveform loading flag */
sound->tags &= ~SOUND_TAGS_WAVEFORM_LOADING;
@ -8415,7 +8409,7 @@ static void lib_link_sound(FileData *fd, Main *main)
sound->ipo = newlibadr_us(
fd, sound->id.lib, sound->ipo); // XXX deprecated - old animation system
BKE_sound_load(main, sound);
BKE_sound_reset_runtime(sound);
sound->id.tag &= ~LIB_TAG_NEED_LINK;
}

View File

@ -85,6 +85,16 @@ void DEG_get_customdata_mask_for_object(const struct Depsgraph *graph,
* one. Assert will happen if it's not. */
struct Scene *DEG_get_evaluated_scene(const struct Depsgraph *graph);
/* Similar to DEG_get_evaluated_scene(), but allows to access non-fully evaluated pointer without
* causing asserts or crashes. Works the following way:
* - If the scene was never evaluated NULL returned.
* - Otherwise the last known state of the scene is returned.
*
* Use in exceptional case if it's absolutely must to.
*
* Allows to pass depsgraph == NULL, wil lreturn NULL in that case. */
struct Scene *DEG_get_evaluated_scene_if_exists(const struct Depsgraph *graph);
/* Get view layer at its evaluated state.
* This is a shortcut for accessing active view layer from evaluated scene. */
struct ViewLayer *DEG_get_evaluated_view_layer(const struct Depsgraph *graph);

View File

@ -58,6 +58,7 @@ extern "C" {
#include "DNA_lightprobe_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@ -89,6 +90,8 @@ extern "C" {
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
@ -1564,12 +1567,42 @@ void DepsgraphNodeBuilder::build_sound(bSound *sound)
if (built_map_.checkIsBuiltAndTag(sound)) {
return;
}
/* Placeholder so we can add relations and tag ID node for update. */
add_operation_node(&sound->id, NodeType::AUDIO, OperationCode::SOUND_EVAL);
add_id_node(&sound->id);
bSound *sound_cow = get_cow_datablock(sound);
add_operation_node(&sound->id,
NodeType::AUDIO,
OperationCode::SOUND_EVAL,
function_bind(BKE_sound_evaluate, _1, bmain_, sound_cow));
build_animdata(&sound->id);
build_parameters(&sound->id);
}
void DepsgraphNodeBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == NULL) {
return;
}
Scene *scene_cow = get_cow_datablock(scene_);
add_operation_node(&scene->id,
NodeType::SEQUENCER,
OperationCode::SEQUENCES_EVAL,
function_bind(BKE_scene_eval_sequencer_sequences, _1, scene_cow));
/* Make sure data for sequences is in the graph. */
Sequence *seq;
SEQ_BEGIN (scene->ed, seq) {
if (seq->sound != NULL) {
build_sound(seq->sound);
}
/* TODO(sergey): Movie clip, scene, camera, mask. */
}
SEQ_END;
}
void DepsgraphNodeBuilder::build_scene_audio(Scene *scene)
{
add_operation_node(&scene->id, NodeType::AUDIO, OperationCode::SOUND_EVAL);
}
/* **** ID traversal callbacks functions **** */
void DepsgraphNodeBuilder::modifier_walk(void *user_data,

View File

@ -212,6 +212,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder {
void build_lightprobe(LightProbe *probe);
void build_speaker(Speaker *speaker);
void build_sound(bSound *sound);
void build_scene_sequencer(Scene *scene);
void build_scene_audio(Scene *scene);
/* Per-ID information about what was already in the dependency graph.
* Allows to re-use certain values, to speed up following evaluation. */

View File

@ -31,13 +31,19 @@ void DepsgraphNodeBuilder::build_scene_render(Scene *scene)
{
scene_ = scene;
const bool build_compositor = (scene->r.scemode & R_DOCOMP);
const bool build_sequencer = (scene->r.scemode & R_DOSEQ);
IDNode *id_node = add_id_node(&scene->id);
id_node->linked_state = DEG_ID_LINKED_DIRECTLY;
add_time_source();
build_animdata(&scene->id);
build_scene_parameters(scene);
build_scene_audio(scene);
if (build_compositor) {
build_scene_compositor(scene);
}
if (build_sequencer) {
build_scene_sequencer(scene);
}
}
void DepsgraphNodeBuilder::build_scene_parameters(Scene *scene)

View File

@ -146,6 +146,11 @@ void DepsgraphNodeBuilder::build_view_layer(Scene *scene,
build_collection(NULL, fls->group);
}
}
/* Sequencer. */
if (linked_state == DEG_ID_LINKED_DIRECTLY) {
build_scene_audio(scene);
build_scene_sequencer(scene);
}
/* Collections. */
add_operation_node(
&scene->id,

View File

@ -58,6 +58,7 @@ extern "C" {
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_speaker_types.h"
#include "DNA_texture_types.h"
@ -84,6 +85,7 @@ extern "C" {
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
#include "BKE_shrinkwrap.h"
#include "BKE_sound.h"
@ -2324,6 +2326,35 @@ void DepsgraphRelationBuilder::build_sound(bSound *sound)
build_parameters(&sound->id);
}
void DepsgraphRelationBuilder::build_scene_sequencer(Scene *scene)
{
if (scene->ed == NULL) {
return;
}
/* Make sure dependencies from sequences data goes to the sequencer evaluation. */
ComponentKey sequencer_key(&scene->id, NodeType::SEQUENCER);
Sequence *seq;
bool has_audio_strips = false;
SEQ_BEGIN (scene->ed, seq) {
if (seq->sound != NULL) {
build_sound(seq->sound);
ComponentKey sound_key(&seq->sound->id, NodeType::AUDIO);
add_relation(sound_key, sequencer_key, "Sound -> Sequencer");
has_audio_strips = true;
}
/* TODO(sergey): Movie clip, scene, camera, mask. */
}
SEQ_END;
if (has_audio_strips) {
ComponentKey scene_audio_key(&scene->id, NodeType::AUDIO);
add_relation(sequencer_key, scene_audio_key, "Sequencer -> Audio");
}
}
void DepsgraphRelationBuilder::build_scene_audio(Scene * /*scene*/)
{
}
void DepsgraphRelationBuilder::build_copy_on_write_relations()
{
for (IDNode *id_node : graph_->id_nodes) {
@ -2387,6 +2418,10 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node)
(id_type == ID_CF && comp_node->type == NodeType::CACHE)) {
rel_flag &= ~RELATION_FLAG_NO_FLUSH;
}
/* TODO(sergey): Needs better solution for this. */
if (id_type == ID_SO) {
rel_flag &= ~RELATION_FLAG_NO_FLUSH;
}
/* Notes on exceptions:
* - Parameters component is where drivers are living. Changing any
* of the (custom) properties in the original datablock (even the

View File

@ -41,6 +41,7 @@
#include "intern/builder/deg_builder_rna.h"
#include "intern/depsgraph.h"
#include "intern/node/deg_node.h"
#include "intern/node/deg_node_id.h"
#include "intern/node/deg_node_component.h"
#include "intern/node/deg_node_operation.h"
@ -200,7 +201,9 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
void build_scene_compositor(Scene *scene);
void build_layer_collections(ListBase *lb);
void build_view_layer(Scene *scene, ViewLayer *view_layer);
void build_view_layer(Scene *scene,
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state);
void build_collection(LayerCollection *from_layer_collection,
Object *object,
Collection *collection);
@ -270,6 +273,8 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder {
void build_lightprobe(LightProbe *probe);
void build_speaker(Speaker *speaker);
void build_sound(bSound *sound);
void build_scene_sequencer(Scene *scene);
void build_scene_audio(Scene *scene);
void build_nested_datablock(ID *owner, ID *id);
void build_nested_nodetree(ID *owner, bNodeTree *ntree);

View File

@ -31,10 +31,16 @@ void DepsgraphRelationBuilder::build_scene_render(Scene *scene)
{
scene_ = scene;
const bool build_compositor = (scene->r.scemode & R_DOCOMP);
const bool build_sequencer = (scene->r.scemode & R_DOSEQ);
build_scene_parameters(scene);
build_animdata(&scene->id);
build_scene_audio(scene);
if (build_compositor) {
build_scene_compositor(scene);
}
if (build_sequencer) {
build_scene_sequencer(scene);
}
}
void DepsgraphRelationBuilder::build_scene_parameters(Scene *scene)

View File

@ -75,7 +75,9 @@ void DepsgraphRelationBuilder::build_layer_collections(ListBase *lb)
}
}
void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_layer)
void DepsgraphRelationBuilder::build_view_layer(Scene *scene,
ViewLayer *view_layer,
eDepsNode_LinkedState_Type linked_state)
{
/* Setup currently building context. */
scene_ = scene;
@ -132,10 +134,15 @@ void DepsgraphRelationBuilder::build_view_layer(Scene *scene, ViewLayer *view_la
&scene->id, NodeType::LAYER_COLLECTIONS, OperationCode::VIEW_LAYER_EVAL);
OperationKey scene_eval_key(&scene->id, NodeType::PARAMETERS, OperationCode::SCENE_EVAL);
add_relation(scene_view_layer_key, scene_eval_key, "View Layer -> Scene Eval");
/* Sequencer. */
if (linked_state == DEG_ID_LINKED_DIRECTLY) {
build_scene_audio(scene);
build_scene_sequencer(scene);
}
/* Build all set scenes. */
if (scene->set != NULL) {
ViewLayer *set_view_layer = BKE_view_layer_default_render(scene->set);
build_view_layer(scene->set, set_view_layer);
build_view_layer(scene->set, set_view_layer, DEG_ID_LINKED_VIA_SET);
}
}

View File

@ -329,10 +329,8 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
const Sequence *seq = static_cast<Sequence *>(ptr->data);
/* Sequencer strip */
node_identifier.type = NodeType::SEQUENCER;
node_identifier.component_name = seq->name;
return node_identifier;
}
else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) {

View File

@ -272,7 +272,7 @@ void DEG_graph_build_from_view_layer(Depsgraph *graph,
/* Hook up relationships between operations - to determine evaluation order. */
DEG::DepsgraphRelationBuilder relation_builder(bmain, deg_graph, &builder_cache);
relation_builder.begin_build();
relation_builder.build_view_layer(scene, view_layer);
relation_builder.build_view_layer(scene, view_layer, DEG::DEG_ID_LINKED_DIRECTLY);
relation_builder.build_copy_on_write_relations();
/* Finalize building. */
graph_build_finalize_common(deg_graph, bmain);

View File

@ -160,6 +160,19 @@ Scene *DEG_get_evaluated_scene(const Depsgraph *graph)
return scene_cow;
}
Scene *DEG_get_evaluated_scene_if_exists(const Depsgraph *graph)
{
if (graph == NULL) {
return NULL;
}
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);
Scene *scene_cow = deg_graph->scene_cow;
if (scene_cow == NULL || !DEG::deg_copy_on_write_is_expanded(&scene_cow->id)) {
return NULL;
}
return scene_cow;
}
ViewLayer *DEG_get_evaluated_view_layer(const Depsgraph *graph)
{
const DEG::Depsgraph *deg_graph = reinterpret_cast<const DEG::Depsgraph *>(graph);

View File

@ -215,6 +215,16 @@ void depsgraph_tag_to_component_opcode(const ID *id,
/* There is no such node in depsgraph, this tag is to be handled
* separately. */
break;
case ID_RECALC_SEQUENCER_STRIPS:
*component_type = NodeType::SEQUENCER;
break;
case ID_RECALC_AUDIO_SEEK:
case ID_RECALC_AUDIO_FPS:
case ID_RECALC_AUDIO_VOLUME:
case ID_RECALC_AUDIO_MUTE:
case ID_RECALC_AUDIO_LISTENER:
*component_type = NodeType::AUDIO;
break;
case ID_RECALC_ALL:
case ID_RECALC_PSYS_ALL:
BLI_assert(!"Should not happen");
@ -633,6 +643,18 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
return "POINT_CACHE";
case ID_RECALC_EDITORS:
return "EDITORS";
case ID_RECALC_SEQUENCER_STRIPS:
return "SEQUENCER_STRIPS";
case ID_RECALC_AUDIO_SEEK:
return "AUDIO_SEEK";
case ID_RECALC_AUDIO_FPS:
return "AUDIO_FPS";
case ID_RECALC_AUDIO_VOLUME:
return "AUDIO_VOLUME";
case ID_RECALC_AUDIO_MUTE:
return "AUDIO_MUTE";
case ID_RECALC_AUDIO_LISTENER:
return "AUDIO_LISTENER";
case ID_RECALC_ALL:
return "ALL";
}

View File

@ -59,6 +59,8 @@ extern "C" {
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "DNA_object_types.h"
#include "DNA_particle_types.h"
@ -84,6 +86,8 @@ extern "C" {
#include "BKE_library_query.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
}
#include "intern/depsgraph.h"
@ -467,6 +471,25 @@ void scene_setup_view_layers_after_remap(const Depsgraph *depsgraph,
* Still not an excuse to have those. */
}
void update_sequence_orig_pointers(const ListBase *sequences_orig, ListBase *sequences_cow)
{
Sequence *sequence_orig = reinterpret_cast<Sequence *>(sequences_orig->first);
Sequence *sequence_cow = reinterpret_cast<Sequence *>(sequences_cow->first);
while (sequence_orig != NULL) {
update_sequence_orig_pointers(&sequence_orig->seqbase, &sequence_cow->seqbase);
sequence_cow->orig_sequence = sequence_orig;
sequence_cow = sequence_cow->next;
sequence_orig = sequence_orig->next;
}
}
void update_scene_orig_pointers(const Scene *scene_orig, Scene *scene_cow)
{
if (scene_orig->ed != NULL) {
update_sequence_orig_pointers(&scene_orig->ed->seqbase, &scene_cow->ed->seqbase);
}
}
/* Check whether given ID is expanded or still a shallow copy. */
BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
{
@ -751,6 +774,7 @@ void update_id_after_copy(const Depsgraph *depsgraph,
scene_cow->toolsettings = scene_orig->toolsettings;
scene_cow->eevee.light_cache = scene_orig->eevee.light_cache;
scene_setup_view_layers_after_remap(depsgraph, id_node, reinterpret_cast<Scene *>(id_cow));
update_scene_orig_pointers(scene_orig, scene_cow);
break;
}
default:
@ -881,6 +905,205 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph,
namespace {
/* Backup of sequencer strips runtime data. */
/* Backup of a single strip. */
class SequenceBackup {
public:
SequenceBackup()
{
reset();
}
inline void reset()
{
scene_sound = NULL;
}
void init_from_sequence(Sequence *sequence)
{
scene_sound = sequence->scene_sound;
sequence->scene_sound = NULL;
}
void restore_to_sequence(Sequence *sequence)
{
sequence->scene_sound = scene_sound;
reset();
}
inline bool isEmpty() const
{
return (scene_sound == NULL);
}
void *scene_sound;
};
class SequencerBackup {
public:
SequencerBackup();
void init_from_scene(Scene *scene);
void restore_to_scene(Scene *scene);
typedef map<Sequence *, SequenceBackup> SequencesBackupMap;
SequencesBackupMap sequences_backup;
};
SequencerBackup::SequencerBackup()
{
}
void SequencerBackup::init_from_scene(Scene *scene)
{
Sequence *sequence;
SEQ_BEGIN (scene->ed, sequence) {
SequenceBackup sequence_backup;
sequence_backup.init_from_sequence(sequence);
if (!sequence_backup.isEmpty()) {
sequences_backup.insert(make_pair(sequence->orig_sequence, sequence_backup));
}
}
SEQ_END;
}
void SequencerBackup::restore_to_scene(Scene *scene)
{
Sequence *sequence;
SEQ_BEGIN (scene->ed, sequence) {
SequencesBackupMap::iterator it = sequences_backup.find(sequence->orig_sequence);
if (it == sequences_backup.end()) {
continue;
}
SequenceBackup &sequence_backup = it->second;
sequence_backup.restore_to_sequence(sequence);
}
SEQ_END;
/* Cleanup audio while the scene is still known. */
for (SequencesBackupMap::value_type &it : sequences_backup) {
SequenceBackup &sequence_backup = it.second;
if (sequence_backup.scene_sound != NULL) {
BKE_sound_remove_scene_sound(scene, sequence_backup.scene_sound);
}
}
}
/* Backup of scene runtime data. */
class SceneBackup {
public:
SceneBackup();
void reset();
void init_from_scene(Scene *scene);
void restore_to_scene(Scene *scene);
/* Sound/audio related pointers of the scene itself.
*
* NOTE: Scene can not disappear after relations update, because otherwise the entire dependency
* graph will be gone. This means we don't need to compare original scene pointer, or worry about
* freeing those if they cant' be restorted: we just copy them over to a new scene. */
void *sound_scene;
void *playback_handle;
void *sound_scrub_handle;
void *speaker_handles;
SequencerBackup sequencer_backup;
};
SceneBackup::SceneBackup()
{
reset();
}
void SceneBackup::reset()
{
sound_scene = NULL;
playback_handle = NULL;
sound_scrub_handle = NULL;
speaker_handles = NULL;
}
void SceneBackup::init_from_scene(Scene *scene)
{
sound_scene = scene->sound_scene;
playback_handle = scene->playback_handle;
sound_scrub_handle = scene->sound_scrub_handle;
speaker_handles = scene->speaker_handles;
/* Clear pointers stored in the scene, so they are not freed when copied-on-written datablock
* is freed for re-allocation. */
scene->sound_scene = NULL;
scene->playback_handle = NULL;
scene->sound_scrub_handle = NULL;
scene->speaker_handles = NULL;
sequencer_backup.init_from_scene(scene);
}
void SceneBackup::restore_to_scene(Scene *scene)
{
scene->sound_scene = sound_scene;
scene->playback_handle = playback_handle;
scene->sound_scrub_handle = sound_scrub_handle;
scene->speaker_handles = speaker_handles;
sequencer_backup.restore_to_scene(scene);
reset();
}
/* Backup of sound datablocks runtime data. */
class SoundBackup {
public:
SoundBackup();
void reset();
void init_from_sound(bSound *sound);
void restore_to_sound(bSound *sound);
void *cache;
void *waveform;
void *playback_handle;
};
SoundBackup::SoundBackup()
{
reset();
}
void SoundBackup::reset()
{
cache = NULL;
waveform = NULL;
playback_handle = NULL;
}
void SoundBackup::init_from_sound(bSound *sound)
{
cache = sound->cache;
waveform = sound->waveform;
playback_handle = sound->playback_handle;
sound->cache = NULL;
sound->waveform = NULL;
sound->playback_handle = NULL;
}
void SoundBackup::restore_to_sound(bSound *sound)
{
sound->cache = cache;
sound->waveform = waveform;
sound->playback_handle = playback_handle;
reset();
}
/* Identifier used to match modifiers to backup/restore their runtime data.
* Identification is happening using original modifier data pointer and the
* modifier type.
@ -921,7 +1144,8 @@ typedef map<ModifierDataBackupID, void *> ModifierRuntimeDataBackup;
/* Storage for backed up pose channel runtime data. */
typedef map<bPoseChannel *, bPoseChannel_Runtime> PoseChannelRuntimeDataBackup;
struct ObjectRuntimeBackup {
class ObjectRuntimeBackup {
public:
ObjectRuntimeBackup() : base_flag(0), base_local_view_bits(0)
{
/* TODO(sergey): Use something like BKE_object_runtime_reset(). */
@ -1099,6 +1323,8 @@ class RuntimeBackup {
/* Restore fields to the given ID. */
void restore_to_id(ID *id);
SceneBackup scene_backup;
SoundBackup sound_backup;
ObjectRuntimeBackup object_backup;
DrawDataList drawdata_backup;
DrawDataList *drawdata_ptr;
@ -1114,6 +1340,12 @@ void RuntimeBackup::init_from_id(ID *id)
case ID_OB:
object_backup.init_from_object(reinterpret_cast<Object *>(id));
break;
case ID_SCE:
scene_backup.init_from_scene(reinterpret_cast<Scene *>(id));
break;
case ID_SO:
sound_backup.init_from_sound(reinterpret_cast<bSound *>(id));
break;
default:
break;
}
@ -1133,6 +1365,12 @@ void RuntimeBackup::restore_to_id(ID *id)
case ID_OB:
object_backup.restore_to_object(reinterpret_cast<Object *>(id));
break;
case ID_SCE:
scene_backup.restore_to_scene(reinterpret_cast<Scene *>(id));
break;
case ID_SO:
sound_backup.restore_to_sound(reinterpret_cast<bSound *>(id));
break;
default:
break;
}
@ -1321,9 +1559,7 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow)
bool deg_copy_on_write_is_needed(const ID *id_orig)
{
const ID_Type id_type = GS(id_orig->name);
/* TODO(sergey): Make Sound copyable. It is here only because the code for dependency graph is
* being work in progress. */
return !ELEM(id_type, ID_IM, ID_SO);
return !ELEM(id_type, ID_IM);
}
} // namespace DEG

View File

@ -185,6 +185,9 @@ const char *operationCodeAsString(OperationCode opcode)
/* Generic datablock. */
case OperationCode::GENERIC_DATABLOCK_UPDATE:
return "GENERIC_DATABLOCK_UPDATE";
/* Sequencer. */
case OperationCode::SEQUENCES_EVAL:
return "SEQUENCES_EVAL";
/* instancing/duplication. */
case OperationCode::DUPLI:
return "DUPLI";

View File

@ -185,12 +185,16 @@ enum class OperationCode {
/* Images. -------------------------------------------------------------- */
IMAGE_ANIMATION,
/* Synchronization clips. ----------------------------------------------- */
/* Synchronization. ----------------------------------------------------- */
SYNCHRONIZE_TO_ORIGINAL,
/* Generic datablock ---------------------------------------------------- */
GENERIC_DATABLOCK_UPDATE,
/* Sequencer. ----------------------------------------------------------- */
SEQUENCES_EVAL,
/* Duplication/instancing system. --------------------------------------- */
DUPLI,
};

View File

@ -36,7 +36,6 @@
#include "BKE_sequencer.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "UI_view2d.h"
@ -52,6 +51,9 @@
#include "ED_sequencer.h"
#include "ED_util.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "anim_intern.h"
/* ********************** frame change operator ***************************/
@ -88,7 +90,6 @@ static bool change_frame_poll(bContext *C)
/* Set the new frame number */
static void change_frame_apply(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
float frame = RNA_float_get(op->ptr, "frame");
bool do_snap = RNA_boolean_get(op->ptr, "snap");
@ -114,7 +115,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
FRAMENUMBER_MIN_CLAMP(CFRA);
/* do updates */
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}

View File

@ -67,6 +67,7 @@
#include "WM_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "ED_anim_api.h"
#include "ED_armature.h"
@ -2740,7 +2741,6 @@ static void areas_do_frame_follow(bContext *C, bool middle)
/* function to be called outside UI context, or for redo */
static int frame_offset_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
int delta;
@ -2752,7 +2752,7 @@ static int frame_offset_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, false);
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@ -2784,7 +2784,6 @@ static void SCREEN_OT_frame_offset(wmOperatorType *ot)
/* function to be called outside UI context, or for redo */
static int frame_jump_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
wmTimer *animtimer = CTX_wm_screen(C)->animtimer;
@ -2814,7 +2813,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, true);
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@ -2847,7 +2846,6 @@ static void SCREEN_OT_frame_jump(wmOperatorType *ot)
/* function to be called outside UI context, or for redo */
static int keyframe_jump_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
bDopeSheet ads = {NULL};
@ -2930,7 +2928,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
else {
areas_do_frame_follow(C, true);
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@ -2963,7 +2961,6 @@ static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
/* function to be called outside UI context, or for redo */
static int marker_jump_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
TimeMarker *marker;
int closest = CFRA;
@ -2997,7 +2994,7 @@ static int marker_jump_exec(bContext *C, wmOperator *op)
areas_do_frame_follow(C, true);
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
@ -4206,7 +4203,8 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
if (screen->animtimer && screen->animtimer == event->customdata) {
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
wmTimer *wt = screen->animtimer;
ScreenAnimData *sad = wt->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
@ -4227,7 +4225,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
isfinite(time = BKE_sound_sync_scene(scene))) {
isfinite(time = BKE_sound_sync_scene(scene_eval))) {
double newfra = (double)time * FPS;
/* give some space here to avoid jumps */
@ -4320,7 +4318,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
}
if (sad->flag & ANIMPLAY_FLAG_JUMPED) {
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
#ifdef PROFILE_AUDIO_SYNCH
old_frame = CFRA;
#endif
@ -4442,11 +4440,12 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
{
bScreen *screen = CTX_wm_screen(C);
Scene *scene = CTX_data_scene(C);
Scene *scene_eval = DEG_get_evaluated_scene(CTX_data_depsgraph(C));
if (ED_screen_animation_playing(CTX_wm_manager(C))) {
/* stop playback now */
ED_screen_animation_timer(C, 0, 0, 0, 0);
BKE_sound_stop_scene(scene);
BKE_sound_stop_scene(scene_eval);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
@ -4455,7 +4454,7 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
int refresh = SPACE_ACTION;
if (mode == 1) { /* XXX only play audio forwards!? */
BKE_sound_play_scene(scene);
BKE_sound_play_scene(scene_eval);
}
ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode);

View File

@ -19,6 +19,7 @@ set(INC
../include
../../blenkernel
../../blenlib
../../depsgraph
../../makesdna
../../makesrna
../../windowmanager

View File

@ -62,6 +62,8 @@
# include <AUD_Special.h>
#endif
#include "DEG_depsgraph_query.h"
#include "ED_sound.h"
#include "ED_util.h"
@ -88,7 +90,6 @@ static int sound_open_exec(bContext *C, wmOperator *op)
bSound *sound;
PropertyPointerRNA *pprop;
PointerRNA idptr;
AUD_SoundInfo info;
Main *bmain = CTX_data_main(C);
RNA_string_get(op->ptr, "filepath", path);
@ -98,29 +99,8 @@ static int sound_open_exec(bContext *C, wmOperator *op)
sound_open_init(C, op);
}
if (sound->playback_handle == NULL) {
if (op->customdata) {
MEM_freeN(op->customdata);
}
BKE_id_free(bmain, sound);
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
}
info = AUD_getInfo(sound->playback_handle);
if (info.specs.channels == AUD_CHANNELS_INVALID) {
BKE_id_free(bmain, sound);
if (op->customdata) {
MEM_freeN(op->customdata);
}
BKE_report(op->reports, RPT_ERROR, "Unsupported audio format");
return OPERATOR_CANCELLED;
}
if (RNA_boolean_get(op->ptr, "mono")) {
sound->flags |= SOUND_FLAGS_MONO;
BKE_sound_load(bmain, sound);
}
if (RNA_boolean_get(op->ptr, "cache")) {
@ -140,6 +120,8 @@ static int sound_open_exec(bContext *C, wmOperator *op)
RNA_property_update(C, &pprop->ptr, pprop->prop);
}
DEG_relations_tag_update(bmain);
MEM_freeN(op->customdata);
return OPERATOR_FINISHED;
}
@ -361,8 +343,9 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
#ifdef WITH_AUDASPACE
char path[FILE_MAX];
char filename[FILE_MAX];
Scene *scene;
Main *bmain;
Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Main *bmain = CTX_data_main(C);
int split;
int bitrate, accuracy;
@ -380,18 +363,20 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
container = RNA_enum_get(op->ptr, "container");
codec = RNA_enum_get(op->ptr, "codec");
split = RNA_boolean_get(op->ptr, "split_channels");
scene = CTX_data_scene(C);
bmain = CTX_data_main(C);
specs.channels = scene->r.ffcodecdata.audio_channels;
specs.rate = scene->r.ffcodecdata.audio_mixrate;
specs.channels = scene_eval->r.ffcodecdata.audio_channels;
specs.rate = scene_eval->r.ffcodecdata.audio_mixrate;
BLI_strncpy(filename, path, sizeof(filename));
BLI_path_abs(filename, BKE_main_blendfile_path(bmain));
const double fps = (((double)scene_eval->r.frs_sec) / (double)scene_eval->r.frs_sec_base);
const int start_frame = scene_eval->r.sfra;
const int end_frame = scene_eval->r.efra;
if (split) {
result = AUD_mixdown_per_channel(scene->sound_scene,
SFRA * specs.rate / FPS,
(EFRA - SFRA + 1) * specs.rate / FPS,
result = AUD_mixdown_per_channel(scene_eval->sound_scene,
start_frame * specs.rate / fps,
(end_frame - start_frame + 1) * specs.rate / fps,
accuracy,
filename,
specs,
@ -400,9 +385,9 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
bitrate);
}
else {
result = AUD_mixdown(scene->sound_scene,
SFRA * specs.rate / FPS,
(EFRA - SFRA + 1) * specs.rate / FPS,
result = AUD_mixdown(scene_eval->sound_scene,
start_frame * specs.rate / fps,
(end_frame - start_frame + 1) * specs.rate / fps,
accuracy,
filename,
specs,
@ -411,7 +396,7 @@ static int sound_mixdown_exec(bContext *C, wmOperator *op)
bitrate);
}
BKE_sound_reset_scene_specs(scene);
BKE_sound_reset_scene_specs(scene_eval);
if (result) {
BKE_report(op->reports, RPT_ERROR, result);

View File

@ -52,7 +52,6 @@
#include "BKE_main.h"
#include "BKE_movieclip.h"
#include "BKE_report.h"
#include "BKE_sound.h"
#include "BKE_tracking.h"
#include "WM_api.h"
@ -74,6 +73,7 @@
#include "PIL_time.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_build.h"
#include "clip_intern.h" // own include
@ -999,7 +999,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
BKE_sound_seek_scene(CTX_data_main(C), scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}

View File

@ -35,7 +35,6 @@
#include "BKE_movieclip.h"
#include "BKE_tracking.h"
#include "BKE_report.h"
#include "BKE_sound.h"
#include "DEG_depsgraph.h"
@ -1356,7 +1355,7 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
if (CFRA != sc->user.framenr) {
CFRA = sc->user.framenr;
BKE_sound_seek_scene(CTX_data_main(C), scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}

View File

@ -33,7 +33,6 @@
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_sound.h"
#include "UI_view2d.h"
@ -49,6 +48,8 @@
#include "RNA_access.h"
#include "RNA_define.h"
#include "DEG_depsgraph.h"
#include "WM_api.h"
#include "WM_types.h"
@ -74,7 +75,6 @@ static bool graphview_cursor_poll(bContext *C)
/* Set the new frame number */
static void graphview_cursor_apply(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
SpaceGraph *sipo = CTX_wm_space_graph(C);
/* this isn't technically "frame", but it'll do... */
@ -105,7 +105,7 @@ static void graphview_cursor_apply(bContext *C, wmOperator *op)
}
SUBFRA = 0.0f;
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
}
/* set the cursor value */

View File

@ -61,7 +61,6 @@
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
#include "BKE_scene.h"
#include "DEG_depsgraph.h"
@ -3608,7 +3607,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
SUBFRA = 0.0f;
/* do updates */
BKE_sound_seek_scene(CTX_data_main(C), scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}

View File

@ -21,6 +21,7 @@ set(INC
../../blenlib
../../blentranslation
../../gpu
../../depsgraph
../../imbuf
../../makesdna
../../makesrna

View File

@ -64,6 +64,8 @@
# include <AUD_Sequence.h>
#endif
#include "DEG_depsgraph.h"
/* own include */
#include "sequencer_intern.h"
@ -351,6 +353,7 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -433,6 +436,7 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -515,6 +519,7 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
sequencer_add_apply_replace_sel(C, op, seq);
sequencer_add_apply_overlap(C, op, seq);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -627,8 +632,8 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
}
BKE_sequencer_sort(scene);
BKE_sequencer_update_muting(ed);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -956,6 +961,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
MEM_freeN(op->customdata);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -1105,6 +1111,7 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
* it was NOT called in blender 2.4x, but wont hurt */
BKE_sequencer_sort(scene);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;

View File

@ -260,11 +260,6 @@ static void drawseqwave(View2D *v2d,
return;
}
if (!sound->spinlock) {
sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
BLI_spin_init(sound->spinlock);
}
BLI_spin_lock(sound->spinlock);
if (!sound->waveform) {
if (!(sound->tags & SOUND_TAGS_WAVEFORM_LOADING)) {

View File

@ -64,6 +64,8 @@
#include "UI_view2d.h"
#include "UI_interface.h"
#include "DEG_depsgraph.h"
/* own include */
#include "sequencer_intern.h"
@ -1809,7 +1811,7 @@ static int sequencer_mute_exec(bContext *C, wmOperator *op)
}
}
BKE_sequencer_update_muting(ed);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -1860,7 +1862,7 @@ static int sequencer_unmute_exec(bContext *C, wmOperator *op)
}
}
BKE_sequencer_update_muting(ed);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -2370,6 +2372,7 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
ms = ms->prev;
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -2625,7 +2628,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
MEM_freeN(ms);
}
BKE_sequencer_update_muting(ed);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
@ -2686,7 +2689,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
BKE_sequence_base_shuffle(ed->seqbasep, seqm, scene);
}
BKE_sequencer_update_muting(ed);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm);
@ -2773,7 +2776,7 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
}
BKE_sequencer_sort(scene);
BKE_sequencer_update_muting(ed);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);

View File

@ -50,6 +50,7 @@ typedef struct PreviewJob {
typedef struct PreviewJobAudio {
struct PreviewJobAudio *next, *prev;
struct Main *bmain;
bSound *sound;
int lr; /* sample left or right */
int startframe;
@ -79,7 +80,9 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p
PreviewJobAudio *preview_next;
bSound *sound = previewjb->sound;
BKE_sound_load_audio(previewjb->bmain, sound);
BKE_sound_read_waveform(sound, stop);
BKE_sound_free_audio(sound);
if (*stop || G.is_break) {
BLI_mutex_lock(pj->mutex);
@ -153,6 +156,7 @@ void sequencer_preview_add_sound(const bContext *C, Sequence *seq)
/* attempt to lock mutex of job here */
audiojob->bmain = CTX_data_main(C);
audiojob->sound = seq->sound;
BLI_mutex_lock(pj->mutex);

View File

@ -1183,6 +1183,8 @@ static void recalcData_sequencer(TransInfo *t)
seq_prev = seq;
}
DEG_id_tag_update(&t->scene->id, ID_RECALC_SEQUENCER_STRIPS);
flushTransSeq(t);
}

View File

@ -448,9 +448,7 @@ typedef enum ID_Type {
/* No copy-on-write for these types.
* Keep in sync with check_datablocks_copy_on_writable and deg_copy_on_write_is_needed */
/* TODO(sergey): Make Sound copyable. It is here only because the code for dependency graph is
* being work in progress. */
#define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_LS, ID_PAL, ID_IM, ID_SO))
#define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_LS, ID_PAL, ID_IM))
#ifdef GS
# undef GS
@ -604,6 +602,16 @@ typedef enum IDRecalcFlag {
*/
ID_RECALC_COPY_ON_WRITE = (1 << 13),
/* Sequences in the sequencer did change.
* Use this tag with a scene ID which owns the sequences. */
ID_RECALC_SEQUENCER_STRIPS = (1 << 14),
ID_RECALC_AUDIO_SEEK = (1 << 15),
ID_RECALC_AUDIO_FPS = (1 << 16),
ID_RECALC_AUDIO_VOLUME = (1 << 17),
ID_RECALC_AUDIO_MUTE = (1 << 18),
ID_RECALC_AUDIO_LISTENER = (1 << 19),
/***************************************************************************
* Pseudonyms, to have more semantic meaning in the actual code without
* using too much low-level and implementation specific tags. */

View File

@ -232,6 +232,9 @@ typedef struct Sequence {
int cache_flag;
int _pad2[3];
struct Sequence *orig_sequence;
void *_pad3;
} Sequence;
typedef struct MetaStack {

View File

@ -669,7 +669,6 @@ const EnumPropertyItem rna_enum_transform_orientation_items[] = {
# include "BKE_pointcache.h"
# include "BKE_scene.h"
# include "BKE_mesh.h"
# include "BKE_sound.h"
# include "BKE_screen.h"
# include "BKE_sequencer.h"
# include "BKE_animsys.h"
@ -819,23 +818,17 @@ static void rna_Scene_camera_update(Main *bmain, Scene *UNUSED(scene_unused), Po
static void rna_Scene_fps_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
BKE_sound_update_fps(scene);
BKE_sequencer_update_sound_bounds_all(scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_FPS | ID_RECALC_SEQUENCER_STRIPS);
}
static void rna_Scene_listener_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
BKE_sound_update_scene_listener(scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_LISTENER);
}
static void rna_Scene_volume_set(PointerRNA *ptr, float value)
static void rna_Scene_volume_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
Scene *scene = (Scene *)(ptr->data);
scene->audio.volume = value;
if (scene->sound_scene) {
BKE_sound_set_scene_volume(scene, value);
}
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_VOLUME);
}
static const char *rna_Scene_statistics_string_get(Scene *scene,
@ -962,10 +955,12 @@ static void rna_Scene_show_subframe_update(Main *UNUSED(bmain),
scene->r.subframe = 0.0f;
}
static void rna_Scene_frame_update(Main *bmain, Scene *UNUSED(current_scene), PointerRNA *ptr)
static void rna_Scene_frame_update(Main *UNUSED(bmain),
Scene *UNUSED(current_scene),
PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
BKE_sound_seek_scene(bmain, scene);
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_SEEK);
WM_main_add_notifier(NC_SCENE | ND_FRAME, scene);
}
@ -1825,8 +1820,11 @@ static void rna_Scene_use_audio_set(PointerRNA *ptr, bool value)
else {
scene->audio.flag &= ~AUDIO_MUTE;
}
}
BKE_sound_mute_scene(scene, value);
static void rna_Scene_use_audio_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
DEG_id_tag_update(&scene->id, ID_RECALC_AUDIO_MUTE);
}
static int rna_Scene_sync_mode_get(PointerRNA *ptr)
@ -7420,7 +7418,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Scene_use_audio_get", "rna_Scene_use_audio_set");
RNA_def_property_ui_text(
prop, "Audio Muted", "Play back of audio from Sequence Editor will be muted");
RNA_def_property_update(prop, NC_SCENE, NULL);
RNA_def_property_update(prop, NC_SCENE, "rna_Scene_use_audio_update");
# if 0 /* XXX: Is this actually needed? */
prop = RNA_def_property(srna, "use_audio_sync", PROP_BOOLEAN, PROP_NONE);
@ -7467,7 +7465,7 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Volume", "Audio volume");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND);
RNA_def_property_update(prop, NC_SCENE, NULL);
RNA_def_property_float_funcs(prop, NULL, "rna_Scene_volume_set", NULL);
RNA_def_property_update(prop, NC_SCENE, "rna_Scene_volume_update");
/* Statistics */
func = RNA_def_function(srna, "statistics", "rna_Scene_statistics_string_get");

View File

@ -75,6 +75,8 @@ const EnumPropertyItem rna_enum_sequence_modifier_type_items[] = {
# include "WM_api.h"
# include "DEG_depsgraph.h"
# include "IMB_imbuf.h"
typedef struct SequenceSearchData {
@ -727,37 +729,9 @@ static int rna_Sequence_proxy_filepath_length(PointerRNA *ptr)
return strlen(path);
}
static void rna_Sequence_volume_set(PointerRNA *ptr, float value)
static void rna_Sequence_audio_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
{
Sequence *seq = (Sequence *)(ptr->data);
seq->volume = value;
if (seq->scene_sound) {
BKE_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) {
BKE_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) {
BKE_sound_set_scene_sound_pan(
seq->scene_sound, value, (seq->flag & SEQ_AUDIO_PAN_ANIMATED) != 0);
}
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
}
static int rna_Sequence_input_count_get(PointerRNA *ptr)
@ -801,9 +775,8 @@ static void rna_Sequence_reopen_files_update(Main *bmain, Scene *UNUSED(scene),
static void rna_Sequence_mute_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Scene *scene = (Scene *)ptr->id.data;
Editing *ed = BKE_sequencer_editing_get(scene, false);
BKE_sequencer_update_muting(ed);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
}
static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@ -2392,23 +2365,20 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 100.0f);
RNA_def_property_ui_text(prop, "Volume", "Playback volume of the sound");
RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND);
RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_volume_set", NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_audio_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_translation_context(prop, BLT_I18NCONTEXT_ID_SOUND);
RNA_def_property_float_funcs(prop, NULL, "rna_Sequence_pitch_set", NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_audio_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, NULL);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_audio_update");
prop = RNA_def_property(srna, "show_waveform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_AUDIO_DRAW_WAVEFORM);

View File

@ -2537,8 +2537,14 @@ void RE_RenderAnim(Render *re,
re->movie_ctx_arr[i] = mh->context_create();
if (!mh->start_movie(
re->movie_ctx_arr[i], scene, &re->r, width, height, re->reports, false, suffix)) {
if (!mh->start_movie(re->movie_ctx_arr[i],
re->pipeline_scene_eval,
&re->r,
width,
height,
re->reports,
false,
suffix)) {
is_error = true;
break;
}
@ -2744,7 +2750,7 @@ void RE_RenderAnim(Render *re,
BLI_callback_exec(
re->main, (ID *)scene, G.is_break ? BLI_CB_EVT_RENDER_CANCEL : BLI_CB_EVT_RENDER_COMPLETE);
BKE_sound_reset_scene_specs(scene);
BKE_sound_reset_scene_specs(re->pipeline_scene_eval);
RE_CleanAfterRender(re);

View File

@ -86,6 +86,7 @@
#include "RNA_enum_types.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
static void wm_notifier_clear(wmNotifier *note);
static void update_tablet_data(wmWindow *win, wmEvent *event);
@ -3154,13 +3155,17 @@ void wm_event_do_handlers(bContext *C)
else {
Scene *scene = WM_window_get_active_scene(win);
if (scene) {
int is_playing_sound = BKE_sound_scene_playing(scene);
CTX_wm_window_set(C, win);
CTX_data_scene_set(C, scene);
Depsgraph *depsgraph = CTX_data_depsgraph(C);
Scene *scene_eval = DEG_get_evaluated_scene_if_exists(depsgraph);
if (scene_eval) {
const int is_playing_sound = BKE_sound_scene_playing(scene_eval);
if (is_playing_sound != -1) {
bool is_playing_screen;
CTX_wm_window_set(C, win);
CTX_data_scene_set(C, scene);
is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
@ -3175,18 +3180,17 @@ void wm_event_do_handlers(bContext *C)
int ncfra = time * (float)FPS + 0.5f;
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
Depsgraph *depsgraph = CTX_data_depsgraph(C);
ED_update_for_newframe(CTX_data_main(C), depsgraph);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
}
}
CTX_data_scene_set(C, NULL);
CTX_wm_screen_set(C, NULL);
CTX_wm_window_set(C, NULL);
}
}
CTX_data_scene_set(C, NULL);
CTX_wm_screen_set(C, NULL);
CTX_wm_window_set(C, NULL);
}
while ((event = win->queue.first)) {

View File

@ -65,6 +65,8 @@
#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "BKE_keyconfig.h"
#include "BKE_addon.h"
@ -123,6 +125,7 @@
#include "COM_compositor.h"
#include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h"
#include "DRW_engine.h"
@ -195,6 +198,30 @@ void WM_init_opengl(Main *bmain)
opengl_is_init = true;
}
static void sound_jack_sync_callback(Main *bmain, int mode, float time)
{
/* Ugly: Blender doesn't like it when the animation is played back during rendering. */
if (G.is_rendering) {
return;
}
wmWindowManager *wm = bmain->wm.first;
for (wmWindow *window = wm->windows.first; window != NULL; window = window->next) {
Scene *scene = WM_window_get_active_scene(window);
if ((scene->audio.flag & AUDIO_SYNC) == 0) {
continue;
}
ViewLayer *view_layer = WM_window_get_active_view_layer(window);
Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false);
if (depsgraph == NULL) {
continue;
}
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
BKE_sound_jack_scene_update(scene_eval, mode, time);
}
}
/* only called once, for startup */
void WM_init(bContext *C, int argc, const char **argv)
{
@ -202,6 +229,7 @@ void WM_init(bContext *C, int argc, const char **argv)
if (!G.background) {
wm_ghost_init(C); /* note: it assigns C to ghost! */
wm_init_cursor_data();
BKE_sound_jack_sync_callback_set(sound_jack_sync_callback);
}
GHOST_CreateSystemPaths();