1 #pragma once
2 
3 #include <QByteArray>
4 #include <QList>
5 #include <QSharedPointer>
6 #include <QString>
7 
8 #include "audio/types.h"
9 #include "util/memory.h"
10 #include "util/types.h"
11 
12 namespace {
13     double kMaxBpm = 500;
14 }
15 
16 namespace mixxx {
17 
18 class Beats;
19 typedef QSharedPointer<Beats> BeatsPointer;
20 
21 class BeatIterator {
22   public:
23     virtual ~BeatIterator() = default;
24     virtual bool hasNext() const = 0;
25     virtual double next() = 0;
26 };
27 
28 // Beats is the base class for BPM and beat management classes. It
29 // provides a specification of all methods a beat-manager class must provide, as
30 // well as a capability model for representing optional features.
31 class Beats {
32   public:
33     virtual ~Beats() = default;
34 
35     enum Capabilities {
36         BEATSCAP_NONE          = 0x0000,
37         BEATSCAP_ADDREMOVE     = 0x0001, // Add or remove a single beat
38         BEATSCAP_TRANSLATE     = 0x0002, // Move all beat markers earlier or later
39         BEATSCAP_SCALE         = 0x0004, // Scale beat distance by a fixed ratio
40         BEATSCAP_MOVEBEAT      = 0x0008, // Move a single Beat
41         BEATSCAP_SETBPM        = 0x0010  // Set new bpm, beat grid only
42     };
43     typedef int CapabilitiesFlags; // Allows us to do ORing
44 
45     enum BPMScale {
46         DOUBLE,
47         HALVE,
48         TWOTHIRDS,
49         THREEFOURTHS,
50         FOURTHIRDS,
51         THREEHALVES,
52     };
53 
54     virtual Beats::CapabilitiesFlags getCapabilities() const = 0;
55 
56     // Serialization
57     virtual QByteArray toByteArray() const = 0;
58 
59     // A string representing the version of the beat-processing code that
60     // produced this Beats instance. Used by BeatsFactory for associating a
61     // given serialization with the version that produced it.
62     virtual QString getVersion() const = 0;
63     // A sub-version can be used to represent the preferences used to generate
64     // the beats object.
65     virtual QString getSubVersion() const = 0;
66 
67     ////////////////////////////////////////////////////////////////////////////
68     // Beat calculations
69     ////////////////////////////////////////////////////////////////////////////
70 
71     // TODO: We may want all of these find functions to return an integer
72     //       instead of a double.
73     // TODO: We may want to implement these with common code that returns
74     //       the triple of closest, next, and prev.
75 
76     // Starting from sample dSamples, return the sample of the next beat in the
77     // track, or -1 if none exists. If dSamples refers to the location of a
78     // beat, dSamples is returned.
79     virtual double findNextBeat(double dSamples) const = 0;
80 
81     // Starting from sample dSamples, return the sample of the previous beat in
82     // the track, or -1 if none exists. If dSamples refers to the location of
83     // beat, dSamples is returned.
84     virtual double findPrevBeat(double dSamples) const = 0;
85 
86     // Starting from sample dSamples, fill the samples of the previous beat
87     // and next beat.  Either can be -1 if none exists.  If dSamples refers
88     // to the location of the beat, the first value is dSamples, and the second
89     // value is the next beat position.  Non- -1 values are guaranteed to be
90     // even.  Returns false if *at least one* sample is -1.  (Can return false
91     // with one beat successfully filled)
92     virtual bool findPrevNextBeats(double dSamples,
93                                    double* dpPrevBeatSamples,
94                                    double* dpNextBeatSamples) const = 0;
95 
96     // Starting from sample dSamples, return the sample of the closest beat in
97     // the track, or -1 if none exists.  Non- -1 values are guaranteed to be
98     // even.
99     virtual double findClosestBeat(double dSamples) const = 0;
100 
101     // Find the Nth beat from sample dSamples. Works with both positive and
102     // negative values of n. Calling findNthBeat with n=0 is invalid. Calling
103     // findNthBeat with n=1 or n=-1 is equivalent to calling findNextBeat and
104     // findPrevBeat, respectively. If dSamples refers to the location of a beat,
105     // then dSamples is returned. If no beat can be found, returns -1.
106     virtual double findNthBeat(double dSamples, int n) const = 0;
107 
108     int numBeatsInRange(double dStartSample, double dEndSample) const;
109 
110     // Find the sample N beats away from dSample. The number of beats may be
111     // negative and does not need to be an integer.
112     double findNBeatsFromSample(double fromSample, double beats) const;
113 
114 
115     // Adds to pBeatsList the position in samples of every beat occurring between
116     // startPosition and endPosition. BeatIterator must be iterated while
117     // holding a strong references to the Beats object to ensure that the Beats
118     // object is not deleted. Caller takes ownership of the returned BeatIterator;
119     virtual std::unique_ptr<BeatIterator> findBeats(double startSample, double stopSample) const = 0;
120 
121     // Return whether or not a sample lies between startPosition and endPosition
122     virtual bool hasBeatInRange(double startSample, double stopSample) const = 0;
123 
124     // Return the average BPM over the entire track if the BPM is
125     // valid, otherwise returns -1
126     virtual double getBpm() const = 0;
127 
128     // Return the average BPM over the range of n*2 beats centered around
129     // curSample.  (An n of 4 results in an averaging of 8 beats).  Invalid
130     // BPM returns -1.
131     virtual double getBpmAroundPosition(double curSample, int n) const = 0;
132 
getMaxBpm()133     virtual double getMaxBpm() const {
134         return kMaxBpm;
135     }
136 
137     virtual audio::SampleRate getSampleRate() const = 0;
138 
139     ////////////////////////////////////////////////////////////////////////////
140     // Beat mutations
141     ////////////////////////////////////////////////////////////////////////////
142 
143     // Translate all beats in the song by dNumSamples samples. Beats that lie
144     // before the start of the track or after the end of the track are not
145     // removed. Beats instance must have the capability BEATSCAP_TRANSLATE.
146     virtual BeatsPointer translate(double dNumSamples) const = 0;
147 
148     // Scale the position of every beat in the song by dScalePercentage. Beats
149     // class must have the capability BEATSCAP_SCALE.
150     virtual BeatsPointer scale(enum BPMScale scale) const = 0;
151 
152     // Adjust the beats so the global average BPM matches dBpm. Beats class must
153     // have the capability BEATSCAP_SET.
154     virtual BeatsPointer setBpm(double dBpm) = 0;
155 };
156 
157 } // namespace mixxx
158