Class AnalysisTagFinder
- java.lang.Object
-
- org.deepsymmetry.beatlink.LifecycleParticipant
-
- org.deepsymmetry.beatlink.data.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
(seeMetadataFinder.setPassive(boolean)
), because tags are loaded in response to metadata updates.- Author:
- James Elliott
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description static class
AnalysisTagFinder.CacheEntry
Wraps values we store in our hot cache, so we can keep track of the player, slot, track, file extension, and type tag the analysis section was associated with.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description 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.static AnalysisTagFinder
getInstance()
Get the singleton instance of this class.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.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.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.Map<String,Set<AnalysisTagListener>>
getTagListeners()
Get the sets of currently-registered analysis tag listeners.boolean
isRunning()
Check whether we are currently running.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.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.void
start()
Start finding analysis tags for all active players.void
stop()
Stop finding analysis tag information for all active players.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.String
toString()
-
Methods inherited from class org.deepsymmetry.beatlink.LifecycleParticipant
addLifecycleListener, deliverLifecycleAnnouncement, ensureRunning, getLifecycleListeners, removeLifecycleListener
-
-
-
-
Method Detail
-
isRunning
public boolean isRunning()
Check whether we are currently running. Unless theMetadataFinder
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 classLifecycleParticipant
- 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 desiredfileExtension
- identifies the specific analysis file we are interested in a tag fromtypeTag
- 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 desiredfileExtension
- identifies the specific analysis file we are interested in a tag fromtypeTag
- 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 informationfileExtension
- identifies the specific analysis file we are interested in a tag fromtypeTag
- 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
isnull
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 addfileExtension
- 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. Iflistener
isnull
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 removefileExtension
- identifies the specific analysis file for which the listener no longer wants tag updatestypeTag
- 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 theDeviceFinder
, so we can keep track of the comings and goings of players themselves. We also start theConnectionManager
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.
-
-