Example #1
0
        public bool shouldSoundMarkerStopPlaybackAfterUserLeftTriggerRange(SoundMarker marker)
        {
            IEnumerable <SoundMarker> syncedMarkers = syncedMarkersFromMarker(marker);

            if (syncedMarkers == null)
            {
                return(true);
            }

            /*
             *  There is at least 1 Synchronised SoundMarker
             *   - Check if ANY of synced markers are already playing (in user range)
             *   - If NONE are in range, let's STOP their playback!
             *   - Notify the calling SoundMarker if it should stop it's own playback
             */

            bool atLeastOneSyncedMarkerIsInTriggerRange = atLeastOneMarkerIsInTriggerRange(syncedMarkers);

            if (!atLeastOneSyncedMarkerIsInTriggerRange)
            {
                // The LAST SoundMarker that is in the synced collection, let's STOP the others!
                foreach (SoundMarker tmpMarker in syncedMarkers)
                {
                    tmpMarker.StopAudioPlayback();
                }
            }

            Debug.Log(string.Format("STOP syncedMarkers.Count: {0} - atLeastOneSyncedMarkerIsInTriggerRange: {1}",
                                    syncedMarkers.Count(), atLeastOneSyncedMarkerIsInTriggerRange ? "true" : "false"));

            // Stop playing if 'atLeastOne...' is NOT in range
            return(!atLeastOneSyncedMarkerIsInTriggerRange);
        }
        public bool unloadOnDemandAudioForSoundMarkerIfAllowed(SoundMarker marker, SoundFile soundFile) {
            if (!onDemandIsActive) { return false; }

            Debug.LogWarning("ON-DEMAND should NOT be Loaded: " + soundFile.filename, this);
            // FIRST - make sure no other SoundMarkers are using the SoundFile
            IEnumerable<SoundMarker> otherMarkersUsingSoundFile = layoutManager.SoundMarkersUsingSoundFileID(
                soundFile.filename, 
                hotspotIDToExclude: marker.hotspot.id);
            foreach (SoundMarker otherMarker in otherMarkersUsingSoundFile) {
                if (otherMarker.onDemandAudioShouldBeLoaded) { return false; }
            }

            // UNLOAD Synced Marker friends if none of them need to be loaded
            IEnumerable<SoundMarker> syncedMarkers = layoutManager.layout.getSynchronisedMarkers(marker.hotspot.id);
            Debug.LogError("unloadOnDemandAudioForSoundMarkerIsPossible: " + marker.gameObject.name);

            if (syncedMarkers == null || !atLeastOneSyncedMarkerClipShouldBeLoaded(syncedMarkers)) {
                Debug.LogError ("   UNLOAD ON DEMAND!");
                // We should UNLOAD this AudioClip...
                layoutManager.UnloadSoundMarkerAndSyncedClips(marker, syncedMarkers);
                canvasControl.editSoundOverlay.refreshDebugText();
                
                return true;
            }

            return false;
        }
Example #3
0
        /// <summary>
        /// </summary>
        /// <param name="soundObj"></param>
        /// <param name="removeFromList"></param>
        /// <param name="eraseHotspotData"></param>
        public void DeleteAndDestroySoundMarker(SoundMarker soundObj, bool removeFromList = true, bool eraseHotspotData = true)
        {
            if (soundObj == null)
            {
                return;
            }

            // TODO: Implement object pooling
            if (removeFromList)
            {
                soundObj.markerDelegate = null;
                soundMarkers.Remove(soundObj);
            }
            if (eraseHotspotData)
            {
                layoutManager.EraseHotspot(soundObj.hotspot);
            }

            if (soundObj.transform.parent != null)
            {
                Destroy(soundObj.transform.parent.gameObject);
            }
            else
            {
                Destroy(soundObj);
            }
        }
        public void CanvasListWillReturn(CanvasController.CanvasUIScreen fromScreen, HashSet <CanvasListCell <SoundMarker> > currentSelectedCells)
        {
            if (fromScreen == CanvasController.CanvasUIScreen.SoundMarkerList &&
                soundMarkerList.listMode == CanvasSoundMarkerList.Mode.SyncronisedMarkers)
            {
                SoundMarker selMarker = objectSelection.selectedMarker;
                if (selMarker == null)
                {
                    return;
                }

                // Save associated cells
                HashSet <string> markerIDs = new HashSet <string>();

                markerIDs.Add(selMarker.hotspot.id);
                foreach (CanvasListCell <SoundMarker> cell in currentSelectedCells)
                {
                    markerIDs.Add(cell.datum.hotspot.id);
                }

                // Synchronise trigger states and playback
                foreach (SoundMarker marker in MainController.soundMarkers)
                {
                    if (markerIDs.Contains(marker.hotspot.id))
                    {
                        marker.hotspot.SetTriggerPlayback(true);
                        marker.PlayAudioFromBeginning();
                    }
                }

                // Save all the synchronised markers
                Layout curLayout = GetCurrentLayout();
                curLayout.setSynchronisedMarkerIDs(markerIDs);
            }
        }
Example #5
0
        public void TriggerPlaybackToggled(bool isOn)
        {
            if (canvasDelegate == null)
            {
                return;
            }
            SoundMarker selectedMarker = canvasDelegate.objectSelection.selectedMarker;

            if (selectedMarker == null && selectedMarker.hotspot != null)
            {
                return;
            }

            AnimateToggle(triggerPlaybackToggle, isOn); // Animate

            // Only allow loop to be turned off if trigger is on
            loopAudioToggle.interactable = (isOn == true);
            if (!isOn && !loopAudioToggle.isOn)
            {
                loopAudioToggle.isOn = true;
            }
            else
            {
                SetTriggerVisualInteractiveState(loopAudioToggle);
            }

            // Save the data to the Hotspot
            selectedMarker.SetTriggerPlayback(isOn);
        }
Example #6
0
        public void SoundColorButtonClicked()
        {
            // Just cycle through colors for now
            if (canvasDelegate == null)
            {
                return;
            }
            SoundMarker selectedSound = canvasDelegate.objectSelection.selectedMarker;

            if (selectedSound == null)
            {
                return;
            }

            selectedSound.SetToNextColor();

            Color newCol = selectedSound.color;

            repositionImage.color = newCol;
            soundIconImage.color  = newCol;
            soundColorImage.color = newCol;
            minRadiusSlider.SetColorTint(newCol);
            maxRadiusSlider.SetColorTint(newCol);

            UnityEngine.UI.ColorBlock cols = soundSrcButton.colors;
            cols.normalColor      = newCol;
            cols.highlightedColor = newCol.ColorWithBrightness(-0.15f);
            cols.pressedColor     = newCol.ColorWithBrightness(-0.3f);
            soundSrcButton.colors = cols;

            canvasDelegate.objectSelection.SetSelectionRadiusColor(newCol);
        }
        public void RecycleSoundMarker(SoundMarker marker, bool removeFromSoundMarkerList, bool eraseHotspotData)
        {
            _unusedMarkers.Push(marker);
            if (removeFromSoundMarkerList)
            {
                MainController.soundMarkers.Remove(marker);
            }

            if (eraseHotspotData)
            {
                _poolingDelegate.getLayoutManager().EraseHotspot(marker.hotspot);
            }

            marker.markerDelegate = null;
            marker.NullifyHotspot();
            marker.gameObject.SetActive(false);

            Anchor anchorToDestroy = marker.GetComponentInParent <Anchor>();

            marker.transform.parent        = _poolingDelegate.getPoolingTransform();
            marker.transform.localPosition = Vector3.zero;

            if (anchorToDestroy != null && anchorToDestroy is Anchor)
            {
                Object.Destroy(anchorToDestroy.gameObject);
            }
        }
Example #8
0
        /// <summary>
        /// Place the next sound marker
        /// </summary>
        private void PlaceSoundTapped()
        {
            // Place a new sound with default config
            SoundMarker soundIconObj = null;

            // Create and position the prefab.
            if (canvasControl.placeSoundsOverlay.placeSoundsOnCursor && cursorTransform != null)
            {
                soundIconObj = SoundMarker.CreatePrefab(cursorTransform, soundMarkerPrefab, anchorWrapperTransform);
            }
            else
            {
                soundIconObj = SoundMarker.CreatePrefab(firstPersonCamera.transform, soundMarkerPrefab, anchorWrapperTransform);
            }
            Anchor  anchorParent = soundIconObj.transform.parent.GetComponent <Anchor>();
            Vector3 anchorPos    = anchorParent.transform.localPosition;

            // Create a new hotspot for the json file and save it.
            soundMarkers.Add(soundIconObj);

            Hotspot h = layoutManager.AddNewHotspot(
                localPos: anchorPos,
                rotation: Vector3.zero,
                minDist: defaultMinDistance * 0.5f,
                maxDist: canvasControl.placeSoundsOverlay.maxRadiusSlider.radiusValue);

            layoutManager.Bind(soundIconObj, h, !playbackIsStopped);

            soundIconObj.SetIconAndRangeToRandomValue();
        }
        // ------------------------------------------------------
        #endregion
        // ------------------------------------------------------
        #region IObjectSelection
        // ------------------------------------------------------

        public void ObjectSelectionSoundSourceIconSelected(SoundMarker sso) {
            if (sso != null) {
                objectSelection.setShape(sso.soundShape);
                objectSelection.SetSelectionRadiusColor(sso.color);
            }
            canvasControl.ObjectSelectionSoundSourceIconSelected(sso);
            canvasControl.SetCanvasScreenActive(CanvasController.CanvasUIScreen.EditSound);
        }
Example #10
0
        public void SyncPlaybackButtonClicked()
        {
            SoundMarker      selMarker       = objectSelection.selectedMarker;
            HashSet <string> syncedMarkerIDs = GetCurrentLayout().getSynchronisedMarkers(selMarker.hotspot.id);

            soundMarkerList.setMode(CanvasSoundMarkerList.Mode.SyncronisedMarkers,
                                    selectedMarker: selMarker, syncedMarkerIDs: syncedMarkerIDs);
            SetCanvasScreenActive(CanvasUIScreen.SoundMarkerList);
        }
        // - - - - - - - - - - - - - - - - - - -

        private SoundMarker initNewSoundMarker(Transform atTransform)
        {
            // Place a new sound with default config
            SoundMarker newMarker = Object.Instantiate(_poolingDelegate.getSoundMarkerPrefab(),
                                                       parent: atTransform).GetComponent <SoundMarker>();

            newMarker.transform.localPosition = Vector3.zero;

            return(newMarker);
        }
Example #12
0
        // ============
        // SOUND FILE METHODS
        public void Bind(SoundMarker obj, Hotspot hotspot, bool startPlayback, bool reloadSoundClips)
        {
            AudioClip clip = soundDictionary.TryGetValue(hotspot.soundID, out SoundFile sf)
                ? sf.clip                          // If the sound is found, use it
                : SoundFile.defaultSoundFile.clip; // Fallback to default

            // bind these together
            obj.SetHotspot(hotspot, true); // with override color etc
            obj.LaunchNewClip(clip, playAudio: startPlayback);
        }
        // Update is called once per frame
        void Update()
        {
            if (Input.GetMouseButtonDown(0))
            {
                if (!selectionEnabled)
                {
                    return;
                }

                int pointerID = -1;
                if (Input.touchCount > 0)
                {
                    pointerID = Input.GetTouch(0).fingerId;
                }

                if (UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(pointerID))
                {
                    return;
                }

                Ray        raycast = Camera.main.ScreenPointToRay(Input.mousePosition);
                RaycastHit raycastHit;

                bool soundIconSelected = false;
                // LayerMask layerMask = 1 << 9; // SoundIcons
                if (Physics.Raycast(raycast, out raycastHit, maxDistance: float.MaxValue, layerMask: raycastLayerMask))
                {
                    // if (Physics.Raycast(raycast, out raycastHit, layerMask)) {
                    SoundMarker soundMarker = raycastHit.collider.GetComponent <SoundMarker>();
                    if (soundMarker != null)
                    {
                        // Debug.Log("Sound Marker: " + soundMarker);
                        SetSelectedSoundMarker(soundMarker);
                        soundIconSelected = true;
                    }
                }

                if (!soundIconSelected && selectionDelegate != null)
                {
                    bool shouldDeselect = selectionDelegate.ObjectShouldDeselectAllSounds();

                    if (shouldDeselect)
                    {
                        if (objSelectionRadius == null)
                        {
                            CreateNewObjSelectionRadius();
                        }

                        DeselectSound();
                        Debug.Log("DESELECTING ALL SOUNDS");
                    }
                    selectionDelegate.ObjectSelectionEmptySpaceTapped(shouldDeselect);
                }
            }
        }
        // Assume this will only be called once during initialisation
        private void preallocateMarkers(int numMarkers = 64)
        {
            Debug.Log("preallocateMarkers numMarkers: " + numMarkers);
            Transform transform = _poolingDelegate.getPoolingTransform();

            for (int i = 0; i < numMarkers; i++)
            {
                SoundMarker marker = initNewSoundMarker(transform);
                marker.gameObject.SetActive(false);
                _unusedMarkers.Push(marker);
            }
        }
Example #15
0
        public void SoundNameTextfieldFinishedEditing(string str)
        {
            UpdateBottomPanel(animated: true, delay: 0, Ease.InOutExpo, bottomMargin: 0, animDuration: 0.1f);

            SoundMarker selectedSound = canvasDelegate.objectSelection.selectedMarker;

            if (selectedSound == null)
            {
                return;
            }
            selectedSound.hotspot.SetName(str);
        }
        void unloadSoundMarkerAndSyncedClips(SoundMarker marker, IEnumerable <SoundMarker> syncedMarkers)
        {
            SoundFile markerSF = marker.hotspot.soundFile;

            if (!markerSF.isDefaultSoundFile && (markerSF.loadState == LoadState.Success || markerSF.clip != null))
            {
                // Unload the first marker
                // marker.SetAudioPauseState(true);
                marker.OnDemandNullifyAudioClip();

                if (destroyImmediate)
                {
                    UnityEngine.GameObject.DestroyImmediate(markerSF.clip, allowDestroyingAssets: false);
                }
                else
                {
                    UnityEngine.GameObject.Destroy(markerSF.clip);
                }

                markerSF.clip      = null;
                markerSF.loadState = LoadState.NotLoaded;
            }

            // - - - - - - - - - - - - - - - - - - -
            // Unload Synced Markers
            if (syncedMarkers != null)
            {
                foreach (SoundMarker syncedMarker in syncedMarkers)
                {
                    SoundFile syncedSF = syncedMarker.hotspot.soundFile;

                    if (!syncedSF.isDefaultSoundFile && (syncedSF.loadState == LoadState.Success || syncedSF.clip != null))
                    {
                        // syncedMarker.SetAudioPauseState(true);
                        syncedMarker.OnDemandNullifyAudioClip();

                        if (destroyImmediate)
                        {
                            UnityEngine.GameObject.DestroyImmediate(syncedSF.clip, allowDestroyingAssets: false);
                        }
                        else
                        {
                            UnityEngine.GameObject.Destroy(syncedSF.clip);
                        }
                        syncedSF.clip      = null;
                        syncedSF.loadState = LoadState.NotLoaded;
                    }
                }
            }
            // - - - - - - - - - - - - - - - - - - -

            _managerDelegate?.OnDemandLoadingLoadedAudioClipsChanged(this);
        }
        // ------------------------------------------------

        public void SoundMarkerSelected(SoundMarker selectedSound)
        {
            // Change the InputField text
            soundNameInputField.text  = selectedSound.hotspot.name;
            soundLabelResizeText.text = selectedSound.hotspot.name;

            // Change the 2D UI representation
            soundIconImage.sprite = selectedSound.iconSprite;

            // Set the trigger and loop toggles
            triggerPlaybackToggle.isOn   = selectedSound.hotspot.triggerPlayback;
            loopAudioToggle.isOn         = selectedSound.hotspot.loopAudio;
            loopAudioToggle.interactable = (triggerPlaybackToggle.isOn == true);
            SetTriggerVisualInteractiveState(loopAudioToggle);

            pitchSlider.value  = selectedSound.hotspot.pitchBend;
            volumeSlider.value = selectedSound.hotspot.soundVolume;

            // Change the colour of the UI
            Color newCol = selectedSound.color;

            repositionImage.color = newCol;
            soundIconImage.color  = newCol;
            soundColorImage.color = newCol;

            minRadiusSlider.SetColorTint(newCol);
            maxRadiusSlider.SetColorTint(newCol);

            minRadiusSlider.SetSliderRadius(selectedSound.soundMinDist, notifyDelegate: false);
            maxRadiusSlider.SetSliderRadius(selectedSound.soundMaxDist, notifyDelegate: false);

            UnityEngine.UI.ColorBlock cols = soundSrcButton.colors;
            cols.normalColor      = newCol;
            cols.highlightedColor = newCol.ColorWithBrightness(-0.15f);
            cols.pressedColor     = newCol.ColorWithBrightness(-0.3f);
            soundSrcButton.colors = cols;

            if (selectedSound.hotspot.soundFile.isDefaultSoundFile)
            {
                soundFilenameText.text = "Tap to change sound";
            }
            else
            {
                soundFilenameText.text = "\"" + selectedSound.hotspot.soundFile.filenameWithExtension + "\"";
            }

            int   charLimit            = 21;
            int   charsOver            = soundFilenameText.text.Length - charLimit;
            float percentOverCharLimit = (charsOver > 0) ? (charsOver / 8f) : 0;

            soundFilenameText.fontSize = 36 - (int)(8 * percentOverCharLimit);
        }
 public void UnloadSoundMarkerAndSyncedClips(SoundMarker marker, IEnumerable <SoundMarker> syncedMarkers)
 {
     if (_operationQueue.Count < 1)
     {
         unloadSoundMarkerAndSyncedClips(marker, syncedMarkers);
         this.performNextOperationInQueue();
     }
     else
     {
         UnityEngine.Debug.LogWarning("ENQUEUE UnloadSoundMarkerAndSyncedClips");
         _operationQueue.Enqueue(new UnloadSoundMarkerAndSyncedClipsOperation(marker, syncedMarkers));
     }
 }
Example #19
0
        public void Bind(SoundMarker obj, SoundFile sf, bool reloadSoundClips)
        {
            // bind these
            obj.hotspot.Set(sf.filename);
            obj.LaunchNewClip(sf.clip);

            // When a new binding occurs, we SHOULD refresh the loaded sound clips
            // if (reloadSoundClips) { LoadSoundClipsExclusivelyForCurrentLayout(() => { }); }
            if (reloadSoundClips && layout.onDemandActive)
            {
                RefreshLoadStateForSoundMarkers(MainController.soundMarkers, () => { });
            }
        }
        public static void SetupUnanchoredMarker(SoundMarker marker, Vector3 pos, Quaternion rot, Transform anchorWrapperT)
        {
            Pose p = new Pose() // {position = pos, rotation = rot }
            {
                position = pos,
                rotation = Quaternion.identity // anchorWrapperTransform.rotation * rot
            };
            Anchor anchor = Session.CreateAnchor(p);

            marker.transform.SetParent(anchor.transform);
            marker.transform.localPosition = Vector3.zero;
            anchor.transform.parent        = anchorWrapperT;
        }
Example #21
0
        public void setSelectedMarkersColourAndIcon(int colourIndex, int iconIndex)
        {
            SoundMarker selectedMarker = canvasDelegate.objectSelection.selectedMarker;

            if (selectedMarker == null)
            {
                return;
            }

            selectedMarker.SetIconColourAndIndex(colourIndex, iconIndex);

            soundAppearanceImage.sprite = selectedMarker.iconSprite;
            updateUIColor(selectedMarker.color);
        }
Example #22
0
        // ------------------------------------------------

        private void updateSyncedMarkersUI(SoundMarker soundMarker)
        {
            // Syncronisation button subtitle
            syncSubtitleText.text = "Edit synchronised Sound Markers";
            if (canvasDelegate != null)
            {
                System.Collections.Generic.HashSet <string> syncedMarkers = canvasDelegate.SynchronisedMarkerIDsWithMarkerID(soundMarker.hotspot.id);
                if (syncedMarkers != null && syncedMarkers.Count > 1)
                {
                    syncSubtitleText.text = string.Format("Synced with {0} Sound Marker{1}",
                                                          syncedMarkers.Count - 1, (syncedMarkers.Count == 2 ? "" : "s"));
                }
            }
        }
Example #23
0
        public void EchoSliderChanged(float newVal)
        {
            if (canvasDelegate == null)
            {
                return;
            }
            SoundMarker selectedMarker = canvasDelegate.objectSelection.selectedMarker;

            if (selectedMarker == null && selectedMarker.hotspot != null)
            {
                return;
            }

            selectedMarker.SetEchoMagnitude(newVal);
        }
Example #24
0
        public void DistortionSliderChanged(float newVal)
        {
            if (canvasDelegate == null)
            {
                return;
            }
            SoundMarker selectedMarker = canvasDelegate.objectSelection.selectedMarker;

            if (selectedMarker == null && selectedMarker.hotspot != null)
            {
                return;
            }

            selectedMarker.SetDistortion(newVal);
        }
Example #25
0
        public void FreqCutoffSliderChanged(float newVal)
        {
            if (canvasDelegate == null)
            {
                return;
            }
            SoundMarker selectedMarker = canvasDelegate.objectSelection.selectedMarker;

            if (selectedMarker == null && selectedMarker.hotspot != null)
            {
                return;
            }

            selectedMarker.SetFrequencyCutoff(newVal);
        }
 public void LoadSoundMarkerAndSyncedClips(SoundMarker marker, Layout layout, Action <HashSet <SoundMarker> > completion)
 {
     if (_operationQueue.Count < 1)
     {
         loadSoundMarkerAndSyncedClips(marker, layout, completion: (HashSet <SoundMarker> markerSet) => {
             completion(markerSet);
             this.performNextOperationInQueue();
         });
     }
     else
     {
         UnityEngine.Debug.LogWarning("ENQUEUE LoadSoundMarkerAndSyncedClips");
         _operationQueue.Enqueue(new LoadSoundMarkerAndSyncedClipsOperation(marker, layout, completion));
     }
 }
        public void loadOnDemandAudioForSoundMarker(SoundMarker marker, SoundFile soundFile) {
            if (!onDemandIsActive) { return; }

            Debug.LogWarning("ON-DEMAND SHOULD be Loaded: " + soundFile.filename);
            // Debug.Log("loadOnDemandAudioForSoundMarker: " + soundFile.filename);
            layoutManager.LoadSoundMarkerAndSyncedClips(marker, completion:
                (HashSet<SoundMarker> loadedMarkers) => {
                    Debug.LogWarning(   "loadOnDemandAudioForSoundMarker COMPLETE!");
                    
                    canvasControl.editSoundOverlay.refreshDebugText();
                    // foreach (var loadedMarker in loadedMarkers) {
                        
                    // }
                });
        }
Example #28
0
        // ------------------------------------------------------
        #region ISoundMarkerDelegate
        // ------------------------------------------------------

        // IEnumerable collection does not include the marker that was passed
        private IEnumerable <SoundMarker> syncedMarkersFromMarker(SoundMarker marker)
        {
            HashSet <string> syncedMarkerIDs = GetCurrentLayout().getSynchronisedMarkers(marker.hotspot.id);

            if (syncedMarkerIDs == null || syncedMarkerIDs.Count < 1)
            {
                return(null);
            }

            return(MainController.soundMarkers.Where(
                       (sm) => {
                return sm.hotspot.id != marker.hotspot.id &&  // Ignore the caller marker
                syncedMarkerIDs.Contains(sm.hotspot.id);
            }));
        }
        public void PitchSliderChanged(float newVal)
        {
            if (canvasDelegate == null)
            {
                return;
            }
            SoundMarker selectedMarker = canvasDelegate.objectSelection.selectedSound;

            if (selectedMarker == null && selectedMarker.hotspot != null)
            {
                return;
            }

            selectedMarker.SetPitchBend(newVal);
        }
        void loadSoundMarkerAndSyncedClips(SoundMarker marker, Layout layout, Action <HashSet <SoundMarker> > completion)
        {
            HashSet <SoundFile>   loadingOrLoadedSoundFiles = new HashSet <SoundFile>();
            HashSet <SoundMarker> loadingOrLoadedMarkers    = new HashSet <SoundMarker>();

            LambdaWaiter <SoundFile> lambdaWaiter = new LambdaWaiter <SoundFile>();

            // Load the SoundFile for the marker passed in
            SoundFile markerSF = marker.hotspot.soundFile;

            loadingOrLoadedSoundFiles.Add(markerSF);
            loadingOrLoadedMarkers.Add(marker);
            if (!markerSF.isDefaultSoundFile)
            {
                LoadClipInSoundFileOnCoroutine(markerSF, marker,
                                               lambdaWaiter.AddCallback((SoundFile returnedSoundFile) => {
                }));
            }

            // - - - - - - - - - - - - - - - - - - -
            // Load the Synced Markers
            IEnumerable <SoundMarker> syncedMarkers = layout.getSynchronisedMarkers(marker.hotspot.id);

            if (syncedMarkers != null)
            {
                foreach (SoundMarker syncedMarker in syncedMarkers)
                {
                    SoundFile syncedSF = syncedMarker.hotspot.soundFile;
                    loadingOrLoadedSoundFiles.Add(syncedSF);
                    loadingOrLoadedMarkers.Add(syncedMarker);
                    if (!markerSF.isDefaultSoundFile)
                    {
                        LoadClipInSoundFileOnCoroutine(syncedSF, syncedMarker,
                                                       lambdaWaiter.AddCallback((SoundFile returnedSoundFile) => {
                        }));
                    }
                }
            }
            // - - - - - - - - - - - - - - - - - - -
            // Wait for loading to complete

            lambdaWaiter.WaitForAllCallbacks(() => {
                if (completion != null)
                {
                    completion(loadingOrLoadedMarkers);
                }
            });
        }