// ===================================================

        /*
         #       #######  #####  ###  #####
         #       #     # #     #  #  #     #
         #       #     # #        #  #
         #       #     # #  ####  #  #
         #       #     # #     #  #  #
         #       #     # #     #  #  #     #
         ####### #######  #####  ###  #####  */

        // ===================================================

        private void loadAllAudioClipsIntoMemory(List <SoundMarker> markers, Layout layout, Action completion)
        {
            if (_managerDelegate == null || layout == null)
            {
                return;
            }
            Dictionary <string, SoundFile> sfDict = _managerDelegate.getSoundDictionary();
            int numLoaded = _managerDelegate.getNumLoadedInSoundDictionary();

            // UnityEngine.Debug.LogWarning("loadAllAudioClipsIntoMemory: " + numLoaded);
            LambdaWaiter <SoundFile> lambdaWaiter = new LambdaWaiter <SoundFile>();

            HashSet <SoundFile> loadingOrLoadedSoundFiles = new HashSet <SoundFile>();

            foreach (SoundMarker marker in markers)
            {
                SoundFile sf;
                if (!sfDict.TryGetValue(marker.hotspot.soundID, out sf))
                {
                    continue;
                }

                // The Marker SHOULD be loaded
                loadingOrLoadedSoundFiles.Add(sf);

                LoadClipInSoundFileOnCoroutine(sf, marker,
                                               lambdaWaiter.AddCallback((SoundFile returnedSoundFile) => {
                }));
            }

            foreach (SoundFile sf in sfDict.Values)
            {
                if (loadingOrLoadedSoundFiles.Contains(sf))
                {
                    continue;
                }
                loadingOrLoadedSoundFiles.Add(sf);

                // sf.loadState = LoadState.Loading;
                _managerDelegate?.StartCoroutineOn(SoundFile.LoadClipInSoundFile(sf,
                                                                                 lambdaWaiter.AddCallback((SoundFile returnedSoundFile) => {
                })));
            }

            lambdaWaiter.WaitForAllCallbacks(() => {
                _managerDelegate?.OnDemandLoadingLoadedAudioClipsChanged(this);
                if (completion != null)
                {
                    completion();
                }
            });
        }
        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);
                }
            });
        }
        void refreshLoadStateForSoundMarkers(List <SoundMarker> markers, Layout layout, Action completion)
        {
            if (_managerDelegate == null || layout == null)
            {
                return;
            }
            Dictionary <string, SoundFile> sfDict = _managerDelegate.getSoundDictionary();
            int numLoaded = _managerDelegate.getNumLoadedInSoundDictionary();

            // UnityEngine.Debug.LogWarning("refreshLoadStateForSoundMarkers NumLoadedAudioClips: " + numLoaded);

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

            HashSet <string>    loadingOrLoadedMarkerIDs  = new HashSet <string>();
            HashSet <SoundFile> loadingOrLoadedSoundFiles = new HashSet <SoundFile>();

            foreach (SoundMarker marker in markers)
            {
                if (loadingOrLoadedMarkerIDs.Contains(marker.hotspot.id))
                {
                    continue;
                }                                                                       // Already covered by a SyncedMarker

                SoundFile sf;
                if (!sfDict.TryGetValue(marker.hotspot.soundID, out sf))
                {
                    continue;
                }

                // if (marker.onDemandAudioShouldBeLoaded) {
                //     UnityEngine.Debug.LogWarning("   Marker " + sf.filename + " onDemandAudioShouldBeLoaded: " + marker.onDemandAudioShouldBeLoaded);
                // } else {
                //     UnityEngine.Debug.LogWarning("   Marker " + sf.filename + " onDemandAudioShouldBeLoaded: " + marker.onDemandAudioShouldBeLoaded);
                // }
                if (!marker.onDemandAudioShouldBeLoaded)
                {
                    continue;
                }

                // The Marker SHOULD be loaded
                loadingOrLoadedSoundFiles.Add(sf);
                loadingOrLoadedMarkerIDs.Add(marker.hotspot.id);

                LoadClipInSoundFileOnCoroutine(sf, marker,
                                               lambdaWaiter.AddCallback((SoundFile returnedSoundFile) => {
                }));

                // Also make sure any synced markers are loaded or loading...
                // IEnumerable<string> syncedMarkerIDs = layout.getSynchronisedMarkerIDs(marker.hotspot.id);
                IEnumerable <SoundMarker> syncedMarkers = layout.getSynchronisedMarkers(marker.hotspot.id);
                if (syncedMarkers == null)
                {
                    continue;
                }

                foreach (SoundMarker syncedMarker in syncedMarkers)
                {
                    if (loadingOrLoadedMarkerIDs.Contains(syncedMarker.hotspot.id))
                    {
                        continue;
                    }                                                                             // Marker already loaded or loading...

                    SoundFile syncedSoundFile;
                    if (!sfDict.TryGetValue(syncedMarker.hotspot.soundID, out syncedSoundFile))
                    {
                        continue;
                    }

                    // UnityEngine.Debug.Log("   SyncedMarker " + sf.filename + " SHOULD be loaded");
                    loadingOrLoadedSoundFiles.Add(syncedSoundFile);
                    loadingOrLoadedMarkerIDs.Add(syncedMarker.hotspot.id);

                    if (syncedSoundFile.isDefaultSoundFile)
                    {
                        continue;
                    }
                    // Execute the below if the AudioClip is not loaded
                    LoadClipInSoundFileOnCoroutine(syncedSoundFile, syncedMarker,
                                                   lambdaWaiter.AddCallback((SoundFile returnedSoundFile) => {
                    }));
                }
            }

            // Unload SoundClips that aren't being used in the current layout
            int numDestroyed = unloadSoundFilesExceptThoseInSet(loadingOrLoadedSoundFiles, sfDict);

            UnityEngine.Debug.Log("RefreshLoadStateForSoundMarkers... " + markers.Count + " Markers, "
                                  + loadingOrLoadedSoundFiles.Count + " SoundClip(s) are loading or loaded... "
                                  + (sfDict.Values.Count - loadingOrLoadedSoundFiles.Count + " NOT loaded. "
                                     + numDestroyed + " DESTROYED!"));
            lambdaWaiter.WaitForAllCallbacks(() => {
                _managerDelegate?.OnDemandLoadingLoadedAudioClipsChanged(this);
                if (completion != null)
                {
                    completion();
                }
            });
        }