Class AnalysisTagFinder


  • public class AnalysisTagFinder
    extends LifecycleParticipant

    Watches for new metadata to become available for tracks loaded on players, and queries the appropriate player for any desired track analysis sections (identified by the analysis file extension and four-character tag type code) when that happens. Clients can express interest in any number of different tag types, and each unique combination will be retrieved once, and sent to any listeners who registered interest in that type. This allows new tags to be supported, as they are discovered and parsed by Crate Digger without any code changes to Beat Link.

    Maintains a hot cache of analysis tag information for any track currently loaded in a player, either on the main playback deck, or as a hot cue, since those tracks could start playing instantly.

    Implicitly honors the active/passive setting of the MetadataFinder (see MetadataFinder.setPassive(boolean)), because tags are loaded in response to metadata updates.

    Author:
    James Elliott
    • Method Detail

      • isRunning

        public boolean isRunning()
        Check whether we are currently running. Unless the MetadataFinder is in passive mode, we will automatically request waveforms from the appropriate player when a new track is loaded that is not found in the hot cache or a downloaded analysis file.
        Specified by:
        isRunning in class LifecycleParticipant
        Returns:
        true if waveforms are being kept track of for all active players
        See Also:
        MetadataFinder.isPassive()
      • getLoadedAnalysisTags

        public Map<DeckReference,​Map<String,​AnalysisTagFinder.CacheEntry>> getLoadedAnalysisTags()
        Get the analysis tags available for all tracks currently loaded in any player, either on the play deck, or in a hot cue. Returns a map of deck references to maps of typeTag + fileExtension to the actual cache entries.
        Returns:
        the cache entries associated with all current players, including for any tracks loaded in their hot cue slots
        Throws:
        IllegalStateException - if the AnalysisTagFinder is not running
      • getLatestTrackAnalysisFor

        public RekordboxAnlz.TaggedSection getLatestTrackAnalysisFor​(int player,
                                                                     String fileExtension,
                                                                     String typeTag)
        Look up the analysis tag of a specific type we have for the track loaded in the main deck of a given player number.
        Parameters:
        player - the device number whose song structure information for the playing track is desired
        fileExtension - identifies the specific analysis file we are interested in a tag from
        typeTag - the four-character type code identifying the specific section of the analysis file desired
        Returns:
        the specified parsed track analysis tag for the track loaded on that player, if available
        Throws:
        IllegalStateException - if the AnalysisTagFinder is not running
      • getLatestTrackAnalysisFor

        public RekordboxAnlz.TaggedSection getLatestTrackAnalysisFor​(DeviceUpdate update,
                                                                     String fileExtension,
                                                                     String typeTag)
        Look up the track analysis tag of a specified type we have for a given player, identified by a status update received from that player.
        Parameters:
        update - a status update from the player for which track analysis information is desired
        fileExtension - identifies the specific analysis file we are interested in a tag from
        typeTag - the four-character type code identifying the specific section of the analysis file desired
        Returns:
        the desired parsed track analysis section for the track loaded on that player, if available
        Throws:
        IllegalStateException - if the AnalysisTagFinder is not running
      • requestAnalysisTagFrom

        public RekordboxAnlz.TaggedSection requestAnalysisTagFrom​(DataReference dataReference,
                                                                  String fileExtension,
                                                                  String typeTag)
        Ask the specified player for the specified track analysis information from the specified media slot, first checking if we have a cached copy.
        Parameters:
        dataReference - uniquely identifies the track from which we want analysis information
        fileExtension - identifies the specific analysis file we are interested in a tag from
        typeTag - the four-character type code identifying the specific section of the analysis file desired
        Returns:
        the parsed track analysis information, if it was found, or null
        Throws:
        IllegalStateException - if the AnalysisTagFinder is not running
      • stringToProtocolNumber

        public NumberField stringToProtocolNumber​(String s)
        Converts a short (up to four character) string to the byte-reversed integer value used to represent that string in dbserver protocol requests for track analysis tags.
        Parameters:
        s - the string to be converted
        Returns:
        the numeric field the protocol uses to represent that string.
      • addAnalysisTagListener

        public void addAnalysisTagListener​(AnalysisTagListener listener,
                                           String fileExtension,
                                           String typeTag)

        Adds the specified listener to receive updates when track analysis information of a specific type for a player changes. If listener is null or already present in the set of registered listeners for the specified file extension and tag type, no exception is thrown and no action is performed.

        Updates are delivered to listeners on the Swing Event Dispatch thread, so it is safe to interact with user interface elements within the event handler.

        Even so, any code in the listener method must finish quickly, or it will freeze the user interface, add latency for other listeners, and updates will back up. If you want to perform lengthy processing of any sort, do so on another thread.

        Parameters:
        listener - the track analysis update listener to add
        fileExtension - identifies the specific analysis file for which the listener wants tag updates (such as ".DAT" and ".EXT")
        typeTag - the four-character type code identifying the specific section of the analysis file desired
      • removeAnalysisTagListener

        public void removeAnalysisTagListener​(AnalysisTagListener listener,
                                              String fileExtension,
                                              String typeTag)
        Removes the specified listener so that it no longer receives updates when track analysis information of a specific type for a player changes. If listener is null or not present in the set of registered listeners for that tag type, no exception is thrown and no action is performed.
        Parameters:
        listener - the track analysis update listener to remove
        fileExtension - identifies the specific analysis file for which the listener no longer wants tag updates
        typeTag - the four-character type code identifying the specific section of the analysis file no longer desired
      • getTagListeners

        public Map<String,​Set<AnalysisTagListener>> getTagListeners()
        Get the sets of currently-registered analysis tag listeners. Returns a map whose keys are strings formed by concatenating each pair of typeTag and fileExtension strings that a registered listener has requested, and whose values are the sets of listeners interested in that type of analysis tag.
        Returns:
        the listeners that are currently registered for track analysis updates, indexed by typeTag + fileExtension
      • start

        public void start()
                   throws Exception

        Start finding analysis tags for all active players. Starts the MetadataFinder if it is not already running, because we need it to send us metadata updates to notice when new tracks are loaded. This in turn starts the DeviceFinder, so we can keep track of the comings and goings of players themselves. We also start the ConnectionManager in order to make queries to obtain analysis information.

        Throws:
        Exception - if there is a problem starting the required components
      • stop

        public void stop()
        Stop finding analysis tag information for all active players.
      • getInstance

        public static AnalysisTagFinder getInstance()
        Get the singleton instance of this class.
        Returns:
        the only instance of this class which exists.