Sound: Make sound handles only be in evaluated datablocks
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 2 May 2019 12:31:33 +0000 (14:31 +0200)
committerSergey Sharybin <sergey.vfx@gmail.com>
Fri, 3 May 2019 13:50:40 +0000 (15:50 +0200)
Quite straightforward change, which makes it so audio handles are
only created inside of evaluated datablocks.

Exception is adding sound strip to the sequencer, which needs an
audio handle to query length and number of channels. This is done
by temporarily loading sound file into an original datablock, and
then tossing it away.

There is an assert in sound.c which verifies that audio system is
used from an evaluated domain, which should help porting all the
cases which are likely missed by this commit.

Some annoying parts:

- `BKE_sound_update_scene()` is iterating over all bases, and does
  special ID tags to see whether sound has been handled or not
  already. This can not be done the old fashion now.

  Ideally, this will be done as a speaker datablock evaluation,
  but seems that would require a lock since audio API is not safe
  for threading. So this is not a desired way i'd say.

  Possible solution here would be to iterate over ID datablocks
  using dependency graph query API.

- Frame jump needs to call `BKE_sound_seek_scene()` directly
  because there might be some flags assigned to the scene which
  could be clear after operator execution is over.

  Need to verify if that's the case though. This is a bit hairy
  code, so sticking to a safest and known to work approach for
  now.

- Removed check for format when opening new sound file.
  Maybe we can have some utility function which queries channel
  and duration information, leaving the caller's code clean and
  tidy.

Tested following cases:
- Adding/removing/moving sequencer's sound strips.
- Adding/moving speakers in viewport.
- Rendering audio.

Reviewers: brecht

Differential Revision: https://developer.blender.org/D4779

15 files changed:
source/blender/blenkernel/BKE_sound.h
source/blender/blenkernel/intern/scene.c
source/blender/blenkernel/intern/sequencer.c
source/blender/blenkernel/intern/sound.c
source/blender/blenloader/intern/readfile.c
source/blender/depsgraph/intern/builder/deg_builder_relations.cc
source/blender/depsgraph/intern/depsgraph_tag.cc
source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc
source/blender/editors/animation/anim_ops.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sound/CMakeLists.txt
source/blender/editors/sound/sound_ops.c
source/blender/makesdna/DNA_ID.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c

index d95be9fde9734f8ed8e136c09f3e9301fbb6e789..0c1ab2cc4c3540c205d4158f22f69820ee7d3f01 100644 (file)
@@ -71,12 +71,17 @@ void BKE_sound_cache(struct bSound *sound);
 
 void BKE_sound_delete_cache(struct bSound *sound);
 
-void BKE_sound_reset_pointers(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,
@@ -88,7 +93,7 @@ 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_pointers(struct Scene *scene);
+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);
 
@@ -154,6 +159,11 @@ 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);
+
 /* Evaluation. */
 
 struct Depsgraph;
index 14e011fca3ba7125c169a6d6b5a068ff55a383ac..733e76fef2d51cf798ed6863f092e394c1808aeb 100644 (file)
@@ -309,7 +309,7 @@ void BKE_scene_copy_data(Main *bmain, Scene *sce_dst, const Scene *sce_src, cons
                                                             flag_subdata);
   }
 
-  BKE_sound_reset_scene_pointers(sce_dst);
+  BKE_sound_reset_scene_runtime(sce_dst);
 
   /* Copy sequencer, this is local data! */
   if (sce_src->ed) {
@@ -399,7 +399,7 @@ Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type)
       sce_copy->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties);
     }
 
-    BKE_sound_reset_scene_pointers(sce_copy);
+    BKE_sound_reset_scene_runtime(sce_copy);
 
     /* grease pencil */
     sce_copy->gpd = NULL;
@@ -779,7 +779,7 @@ void BKE_scene_init(Scene *sce)
   srv = sce->r.views.last;
   BLI_strncpy(srv->suffix, STEREO_RIGHT_SUFFIX, sizeof(srv->suffix));
 
-  BKE_sound_reset_scene_pointers(sce);
+  BKE_sound_reset_scene_runtime(sce);
 
   /* color management */
   colorspace_name = IMB_colormanagement_role_colorspace_name_get(COLOR_ROLE_DEFAULT_SEQUENCER);
@@ -1509,7 +1509,7 @@ 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_input_scene(depsgraph);
+  Scene *scene = DEG_get_evaluated_scene(depsgraph);
   BKE_sound_ensure_scene(scene);
   BKE_sound_update_scene(bmain, scene);
 }
@@ -2398,23 +2398,17 @@ void BKE_scene_cursor_quat_to_rot(View3DCursor *cursor, const float quat[4], boo
 void BKE_scene_eval_sequencer_sequences(Depsgraph *depsgraph, Scene *scene)
 {
   DEG_debug_print_eval(depsgraph, __func__, scene->id.name, scene);
-  /* TODO(sergey): For now we keep sound handlers in an original IDs, but it
-   * should really be moved to an evaluated one. */
-  if (!DEG_is_active(depsgraph)) {
-    return;
-  }
-  Scene *scene_orig = (Scene *)DEG_get_original_id(&scene->id);
-  if (scene_orig->ed == NULL) {
+  if (scene->ed == NULL) {
     return;
   }
-  BKE_sound_ensure_scene(scene_orig);
+  BKE_sound_ensure_scene(scene);
   Sequence *seq;
-  SEQ_BEGIN (scene_orig->ed, seq) {
+  SEQ_BEGIN (scene->ed, seq) {
     if (seq->sound != NULL && seq->scene_sound == NULL) {
-      seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene_orig, seq);
+      seq->scene_sound = BKE_sound_add_scene_sound_defaults(scene, seq);
     }
   }
   SEQ_END;
-  BKE_sequencer_update_muting(scene_orig->ed);
-  BKE_sequencer_update_sound_bounds_all(scene_orig);
+  BKE_sequencer_update_muting(scene->ed);
+  BKE_sequencer_update_sound_bounds_all(scene);
 }
index f593713b79cac3e1ff6ab101a1e3cad1b714dd45..74541c13c4f322a5d957276db4f05f760c197b3a 100644 (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);
   }
 }
@@ -5491,17 +5488,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;
@@ -5526,8 +5524,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);
 
@@ -5536,6 +5533,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
index 18093173f7ce087544b9c0cf6840fc875cea2b45..9e5fb3dac6375f18d754428623b7344411ee3dbc 100644 (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>
@@ -64,6 +65,28 @@ 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;
@@ -80,7 +103,7 @@ 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);
+  BKE_sound_reset_runtime(sound);
 
   return sound;
 }
@@ -128,6 +151,17 @@ void BKE_sound_free(bSound *sound)
     sound->packedfile = NULL;
   }
 
+  BKE_sound_free_audio(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);
@@ -143,11 +177,6 @@ void BKE_sound_free(bSound *sound)
   BKE_sound_free_waveform(sound);
 
 #endif /* WITH_AUDASPACE */
-  if (sound->spinlock) {
-    BLI_spin_end(sound->spinlock);
-    MEM_freeN(sound->spinlock);
-    sound->spinlock = NULL;
-  }
 }
 
 /**
@@ -160,7 +189,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))
@@ -180,8 +209,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)
@@ -194,31 +222,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
 
@@ -370,6 +382,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);
@@ -396,44 +410,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;
@@ -450,32 +470,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;
-    }
+  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;
@@ -508,6 +530,8 @@ void BKE_sound_destroy_scene(Scene *scene)
 
 void BKE_sound_reset_scene_specs(Scene *scene)
 {
+  sound_verify_evaluated_id(&scene->id);
+
   AUD_Specs specs;
 
   specs.channels = AUD_Device_getChannels(sound_device);
@@ -518,6 +542,7 @@ void BKE_sound_reset_scene_specs(Scene *scene)
 
 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);
   }
@@ -525,6 +550,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);
   }
@@ -534,6 +561,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);
@@ -542,6 +571,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,
@@ -565,6 +595,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;
@@ -604,12 +635,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,
@@ -631,6 +664,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,
@@ -656,6 +690,8 @@ void BKE_sound_set_scene_sound_pan(void *handle, float pan, char 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) {
@@ -665,6 +701,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);
   }
@@ -678,6 +716,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);
 
@@ -720,6 +760,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;
@@ -751,9 +793,10 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
     }
   }
 
-  if (scene->audio.flag & AUDIO_SCRUB && !animation_playing) {
+  Scene *scene_orig = (Scene *)DEG_get_original_id(&scene->id);
+  if (scene_orig->audio.flag & AUDIO_SCRUB && !animation_playing) {
     AUD_Handle_setPosition(scene->playback_handle, cur_time);
-    if (scene->audio.flag & AUDIO_SYNC) {
+    if (scene_orig->audio.flag & AUDIO_SYNC) {
       AUD_seekSynchronizer(scene->playback_handle, cur_time);
     }
     AUD_Handle_resume(scene->playback_handle);
@@ -769,7 +812,7 @@ void BKE_sound_seek_scene(Main *bmain, Scene *scene)
     }
   }
   else {
-    if (scene->audio.flag & AUDIO_SYNC) {
+    if (scene_orig->audio.flag & AUDIO_SYNC) {
       AUD_seekSynchronizer(scene->playback_handle, cur_time);
     }
     else {
@@ -784,6 +827,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;
@@ -802,6 +847,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;
@@ -834,6 +881,8 @@ void BKE_sound_free_waveform(bSound *sound)
 
 void BKE_sound_read_waveform(bSound *sound, short *stop)
 {
+  sound_verify_evaluated_id(&sound->id);
+
   AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
   SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform");
 
@@ -880,11 +929,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;
@@ -947,6 +999,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;
 
@@ -956,7 +1010,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) {
@@ -993,6 +1048,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;
@@ -1157,7 +1213,7 @@ char **BKE_sound_get_device_names(void)
 
 #endif /* WITH_AUDASPACE */
 
-void BKE_sound_reset_scene_pointers(Scene *scene)
+void BKE_sound_reset_scene_runtime(Scene *scene)
 {
   scene->sound_scene = NULL;
   scene->playback_handle = NULL;
@@ -1173,7 +1229,7 @@ void BKE_sound_ensure_scene(struct Scene *scene)
   BKE_sound_create_scene(scene);
 }
 
-void BKE_sound_reset_pointers(bSound *sound)
+void BKE_sound_reset_runtime(bSound *sound)
 {
   sound->cache = NULL;
   sound->playback_handle = NULL;
@@ -1187,14 +1243,39 @@ void BKE_sound_ensure_loaded(Main *bmain, bSound *sound)
   BKE_sound_load(bmain, sound);
 }
 
-void BKE_sound_evaluate(Depsgraph *depsgraph, Main *bmain, bSound *sound)
+void BKE_sound_jack_sync_callback_set(SoundJackSyncCallback callback)
 {
-  DEG_debug_print_eval(depsgraph, __func__, sound->id.name, sound);
-  /* TODO(sergey): For now we keep sound handlers in an original IDs, but it
-   * should really be moved to an evaluated one. */
-  if (!DEG_is_active(depsgraph)) {
+#if defined(WITH_AUDASPACE) && defined(WITH_JACK)
+  sound_jack_sync_callback = callback;
+#else
+  (void)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;
   }
-  bSound *sound_orig = (bSound *)DEG_get_original_id(&sound->id);
-  BKE_sound_ensure_loaded(bmain, sound_orig);
+
+  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);
+  }
+#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);
 }
index 3326e2c02dc43e92f770265f1f2ca6eb32a27abe..9661fd0bc614f2184ed8794210ac7be40921bce4 100644 (file)
@@ -6678,7 +6678,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_reset_scene_pointers(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);
@@ -8423,7 +8423,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_reset_pointers(sound);
+      BKE_sound_reset_runtime(sound);
 
       sound->id.tag &= ~LIB_TAG_NEED_LINK;
     }
index 8fef35570fed88c731e098423e8e5a1448914071..64772dcc64b39acc205c13dfc11a32a4160266ba 100644 (file)
@@ -2391,6 +2391,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
index d8e895364ca8461792e3c04a1f3459598bb2fdec..f7d7b76cb690d6d8b968f67b34bcdf9d2b07b4f0 100644 (file)
@@ -218,9 +218,6 @@ void depsgraph_tag_to_component_opcode(const ID *id,
     case ID_RECALC_SEQUENCER:
       *component_type = NodeType::SEQUENCER;
       break;
-    case ID_RECALC_AUDIO_JUMP:
-      *component_type = NodeType::AUDIO;
-      break;
     case ID_RECALC_ALL:
     case ID_RECALC_PSYS_ALL:
       BLI_assert(!"Should not happen");
@@ -623,8 +620,6 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag)
       return "EDITORS";
     case ID_RECALC_SEQUENCER:
       return "SEQUENCER";
-    case ID_RECALC_AUDIO_JUMP:
-      return "AUDIO_JUMP";
     case ID_RECALC_ALL:
       return "ALL";
   }
index 6d5714d56060865a5ac92c140fd1160d02070499..bb4300e5330f841abe29c034eda2326dde9614ed 100644 (file)
@@ -1516,9 +1516,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
index 45bb8f3b11e1e7eb420d6e898880dd781cac3bd7..f95429fd47ccdd5d28f1b980a15c2bed74d862a2 100644 (file)
@@ -52,6 +52,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 +91,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 +116,7 @@ static void change_frame_apply(bContext *C, wmOperator *op)
   FRAMENUMBER_MIN_CLAMP(CFRA);
 
   /* do updates */
-  BKE_sound_seek_scene(bmain, scene);
+  BKE_sound_seek_scene(CTX_data_main(C), DEG_get_evaluated_scene(CTX_data_depsgraph(C)));
   WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
 }
 
index a87660d2cb7e74dcd219fd3d9ea76d54e091610e..e35a2679b8fd0c4083956e7e476427c5b664d2d6 100644 (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"
@@ -2832,7 +2833,8 @@ static int frame_jump_exec(bContext *C, wmOperator *op)
 
     areas_do_frame_follow(C, true);
 
-    BKE_sound_seek_scene(bmain, scene);
+    /* TODO(sergey): Make more reusable. */
+    BKE_sound_seek_scene(bmain, DEG_get_evaluated_scene(CTX_data_depsgraph(C)));
 
     WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
   }
@@ -4523,11 +4525,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);
   }
@@ -4536,7 +4539,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);
index c2a88041a85cc9673c241410f84ecc7a340b9d71..7f4b5a45aa369a007cd9fc7ed3e4757a97a8ca61 100644 (file)
@@ -19,6 +19,7 @@ set(INC
   ../include
   ../../blenkernel
   ../../blenlib
+  ../../depsgraph
   ../../makesdna
   ../../makesrna
   ../../windowmanager
index 25c05e2d1d0f157ddaebb3a56b80d646f16f4869..8ac49e447fe6315025556ac9ca480cfb09b6bd98 100644 (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);
index 42ee4e9a6c8c5d8af92d002102a46c1ad72e150c..14b3d97cef4ac6a1a9e7d071a2aadcdf14f2e66a 100644 (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
@@ -608,10 +606,6 @@ typedef enum IDRecalcFlag {
    * Use this tag with a scene ID which owns the sequences. */
   ID_RECALC_SEQUENCER = (1 << 14),
 
-  /* Frame changed in a way that caused audio jump.
-   * Use this on a scene ID. */
-  ID_RECALC_AUDIO_JUMP = (1 << 15),
-
   /***************************************************************************
    * Pseudonyms, to have more semantic meaning in the actual code without
    * using too much low-level and implementation specific tags. */
index 13b6260e2b9e2c0f67513358ebddbaf5f4d1434e..a13b28b7853adad4360c1a1dcafd42fd09d956ee 100644 (file)
@@ -86,6 +86,7 @@
 #include "RNA_enum_types.h"
 
 #include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
 
 /* Motion in pixels allowed before we don't consider single/double click,
  * or detect the start of a tweak event. */
@@ -3090,10 +3091,12 @@ void wm_event_do_handlers(bContext *C)
       wm_event_free_all(win);
     }
     else {
+      Depsgraph *depsgraph = CTX_data_depsgraph(C);
       Scene *scene = WM_window_get_active_scene(win);
+      Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
 
       if (scene) {
-        int is_playing_sound = BKE_sound_scene_playing(scene);
+        const int is_playing_sound = BKE_sound_scene_playing(scene_eval);
 
         if (is_playing_sound != -1) {
           bool is_playing_screen;
@@ -3113,7 +3116,6 @@ 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);
               }
index 97ba9190351b4c3d7100581ccf4d5d709f31fd7f..5529aec1aa53ded4e822afc82b31b910de74783b 100644 (file)
@@ -64,6 +64,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"
 #include "COM_compositor.h"
 
 #include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
 
 #include "DRW_engine.h"
 
@@ -194,6 +197,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)
 {
@@ -201,6 +228,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();