summaryrefslogtreecommitdiffstats
path: root/src/track/beats.h
blob: c3ae7e568e578bb5a278377496b84d027ff05bfd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
#pragma once

#include <QObject>
#include <QString>
#include <QList>
#include <QByteArray>
#include <QSharedPointer>

#include "util/memory.h"
#include "util/types.h"

namespace {
    double kMaxBpm = 500;
}

namespace mixxx {

class Beats;
typedef QSharedPointer<Beats> BeatsPointer;

class BeatIterator {
  public:
    virtual ~BeatIterator() = default;
    virtual bool hasNext() const = 0;
    virtual double next() = 0;
};

// Beats is a pure abstract base class for BPM and beat management classes. It
// provides a specification of all methods a beat-manager class must provide, as
// well as a capability model for representing optional features.
class Beats : public QObject {
    Q_OBJECT
  public:
    Beats() { }
    ~Beats() override = default;

    enum Capabilities {
        BEATSCAP_NONE          = 0x0000,
        BEATSCAP_ADDREMOVE     = 0x0001, // Add or remove a single beat
        BEATSCAP_TRANSLATE     = 0x0002, // Move all beat markers earlier or later
        BEATSCAP_SCALE         = 0x0004, // Scale beat distance by a fixed ratio
        BEATSCAP_MOVEBEAT      = 0x0008, // Move a single Beat
        BEATSCAP_SETBPM        = 0x0010  // Set new bpm, beat grid only
    };
    typedef int CapabilitiesFlags; // Allows us to do ORing

    enum BPMScale {
        DOUBLE,
        HALVE,
        TWOTHIRDS,
        THREEFOURTHS,
        FOURTHIRDS,
        THREEHALVES,
    };

    virtual Beats::CapabilitiesFlags getCapabilities() const = 0;

    // Serialization
    virtual QByteArray toByteArray() const = 0;
    virtual BeatsPointer clone() const = 0;

    // A string representing the version of the beat-processing code that
    // produced this Beats instance. Used by BeatsFactory for associating a
    // given serialization with the version that produced it.
    virtual QString getVersion() const = 0;
    // A sub-version can be used to represent the preferences used to generate
    // the beats object.
    virtual QString getSubVersion() const = 0;

    ////////////////////////////////////////////////////////////////////////////
    // Beat calculations
    ////////////////////////////////////////////////////////////////////////////

    // TODO: We may want all of these find functions to return an integer
    //       instead of a double.
    // TODO: We may want to implement these with common code that returns
    //       the triple of closest, next, and prev.

    // Starting from sample dSamples, return the sample of the next beat in the
    // track, or -1 if none exists. If dSamples refers to the location of a
    // beat, dSamples is returned.
    virtual double findNextBeat(double dSamples) const = 0;

    // Starting from sample dSamples, return the sample of the previous beat in
    // the track, or -1 if none exists. If dSamples refers to the location of
    // beat, dSamples is returned.
    virtual double findPrevBeat(double dSamples) const = 0;

    // Starting from sample dSamples, fill the samples of the previous beat
    // and next beat.  Either can be -1 if none exists.  If dSamples refers
    // to the location of the beat, the first value is dSamples, and the second
    // value is the next beat position.  Non- -1 values are guaranteed to be
    // even.  Returns false if *at least one* sample is -1.  (Can return false
    // with one beat successfully filled)
    virtual bool findPrevNextBeats(double dSamples,
                                   double* dpPrevBeatSamples,
                                   double* dpNextBeatSamples) const = 0;

    // Starting from sample dSamples, return the sample of the closest beat in
    // the track, or -1 if none exists.  Non- -1 values are guaranteed to be
    // even.
    virtual double findClosestBeat(double dSamples) const = 0;

    // Find the Nth beat from sample dSamples. Works with both positive and
    // negative values of n. Calling findNthBeat with n=0 is invalid. Calling
    // findNthBeat with n=1 or n=-1 is equivalent to calling findNextBeat and
    // findPrevBeat, respectively. If dSamples refers to the location of a beat,
    // then dSamples is returned. If no beat can be found, returns -1.
    virtual double findNthBeat(double dSamples, int n) const = 0;

    int numBeatsInRange(double dStartSample, double dEndSample);

    // Find the sample N beats away from dSample. The number of beats may be
    // negative and does not need to be an integer.
    double findNBeatsFromSample(double fromSample, double beats) const;


    // Adds to pBeatsList the position in samples of every beat occurring between
    // startPosition and endPosition. BeatIterator must be iterated while
    // holding a strong references to the Beats object to ensure that the Beats
    // object is not deleted. Caller takes ownership of the returned BeatIterator;
    virtual std::unique_ptr<BeatIterator> findBeats(double startSample, double stopSample) const = 0;

    // Return whether or not a sample lies between startPosition and endPosition
    virtual bool hasBeatInRange(double startSample, double stopSample) const = 0;

    // Return the average BPM over the entire track if the BPM is
    // valid, otherwise returns -1
    virtual double getBpm() const = 0;

    // Return the average BPM over the range from startSample to endSample,
    // specified in samples if the BPM is valid, otherwise returns -1
    virtual double getBpmRange(double startSample, double stopSample) const = 0;

    // Return the average BPM over the range of n*2 beats centered around
    // curSample.  (An n of 4 results in an averaging of 8 beats).  Invalid
    // BPM returns -1.
    virtual double getBpmAroundPosition(double curSample, int n) const = 0;

    virtual double getMaxBpm() const {
        return kMaxBpm;
    }

    ////////////////////////////////////////////////////////////////////////////
    // Beat mutations
    ////////////////////////////////////////////////////////////////////////////

    // Add a beat at location dBeatSample. Beats instance must have the
    // capability BEATSCAP_ADDREMOVE.
    virtual void addBeat(double dBeatSample) = 0;

    // Remove a beat at location dBeatSample. Beats instance must have the
    // capability BEATSCAP_ADDREMOVE.
    virtual void removeBeat(double dBeatSample) = 0;

    // Translate all beats in the song by dNumSamples samples. Beats that lie
    // before the start of the track or after the end of the track are not
    // removed. Beats instance must have the capability BEATSCAP_TRANSLATE.
    virtual void translate(double dNumSamples) = 0;

    // Scale the position of every beat in the song by dScalePercentage. Beats
    // class must have the capability BEATSCAP_SCALE.
    virtual void scale(enum BPMScale scale) = 0;

    // Adjust the beats so the global average BPM matches dBpm. Beats class must
    // have the capability BEATSCAP_SET.
    virtual void setBpm(double dBpm) = 0;

    virtual SINT getSampleRate() const = 0;

  signals:
    void updated();
};

} // namespace mixxx