+
+ Music and Audio
+
+ Music and audio-locked objects may seem interchangeable on the surface, but when translating
+ between audio samples and beats, keep in mind that a sample is only a quantised approximation
+ of the actual time (in minutes) of a beat.
+ Thus if a gui user points to the frame occupying the start of a music-locked object on 1|3|0, it does not
+ mean that this frame is the actual location in time of 1|3|0.
+
+ You cannot use a frame measurement to determine beat distance except under special circumstances
+ (e.g. where the user has requested that a beat lie on a SMPTE frame or if the tempo is known to be constant over the duration).
+
+ This means is that a user operating on a musical grid must supply the desired beat position and/or current beat quantization in order for the
+ sample space the user is operating at to be translated correctly to the object.
+
+ The current approach is to interpret the supplied frame using the grid division the user has currently selected.
+ If the user has no musical grid set, they are actually operating in sample space (even SMPTE frames are rounded to audio frame), so
+ the supplied audio frame is interpreted as the desired musical location (beat_at_frame()).
+
+ tldr: Beat, being a function of time, has nothing to do with sample rate, but time quantization can get in the way of precision.
+
+ When frame_at_beat() is called, the position calculation is performed in pulses and minutes.
+ The result is rounded to audio frames.
+ When beat_at_frame() is called, the frame is converted to minutes, with no rounding performed on the result.
+
+ So :
+ frame_at_beat (beat_at_frame (frame)) == frame
+ but :
+ beat_at_frame (frame_at_beat (beat)) != beat due to the time quantization of frame_at_beat().
+
+ Doing the second one will result in a beat distance error of up to 0.5 audio samples.
+ So instead work in pulses and/or beats and only use beat position to caclulate frame position (e.g. after tempo change).
+ For audio-locked objects, use frame position to calculate beat position.
+
+ The above pointless example would then do:
+ beat_at_pulse (pulse_at_beat (beat)) to avoid rounding.
+