Audacity 3.2.0
BeatsFormat.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 BeatsFormat.cpp
6
7 Michael Papadopoulos
8
9**********************************************************************/
10
11#include "BeatsFormat.h"
13
14#include <cassert>
15
17 double units, double& major, double& minor, double &minorMinor,
18 int& mDigits
19) const
20{
21 const_cast<BeatsFormat*>(this)->UpdateSubdivision(units);
22
23 major = mTicks.major.duration;
24 minor = mTicks.minor.duration;
25 minorMinor = mTicks.minorMinor.duration;
26
27 mDigits = 0;
28}
29
31 wxString& s, double d, double units, double minor, int mDigits, TickType tickType
32) const
33{
34 if (d < 0) {
35 return;
36 }
37
38 const auto lower = static_cast<double>(mTimeSigLower);
39 double val = (mBpm * (lower / 4) * d) / (60 * mTimeSigUpper);
40 double beatApprox = (val - floor(val)) * mTimeSigUpper + 1;
41 int beat = round(beatApprox);
42
43 // Don't add decimal if it's a major tick or is on the beat
44 // Segment by distance with units
45 if (units < .4 * (60 / mBpm)* (4 / lower))
46 {
47 if (tickType == RulerFormat::t_major) {
48 s.Printf(wxT("%d"), (int)round(val + 1));
49 }
50 else if (tickType == RulerFormat::t_minor && abs(beat - beatApprox) < 1.0e-5f) {
51 s.Printf(wxT("%d.%d"), (int)floor(val + 1), (int)beat);
52 }
53 }
54 else if (units < .8 * (60 / mBpm) * (4 / lower))
55 {
56 if (tickType == RulerFormat::t_major) {
57 s.Printf(wxT("%d"), (int)round(val + 1));
58 }
59 else if (tickType == RulerFormat::t_minor && beat != 1) {
60 s.Printf(wxT("%d.%d"), (int)floor(val + 1), (int)beat);
61 }
62 }
63 else {
64 if (tickType == RulerFormat::t_major) {
65 s.Printf(wxT("%d"), (int)round(val + 1));
66 }
67 }
68}
69
70void BeatsFormat::SetData(double bpm, int timeSigUpper, int timeSigLower)
71{
72 // Check preconditions
73 assert(bpm > 0);
74 assert(timeSigUpper > 0);
75 assert(timeSigLower > 1);
76 assert((timeSigLower & (timeSigLower - 1)) == 0);
77
78 if (!(mBpm > 0 && mTimeSigUpper > 1 && mTimeSigLower > 1))
79 return;
80
81 if (mTimeSigLower & (mTimeSigLower - 1))
82 return;
83
84 mBpm = bpm;
85 mTimeSigUpper = timeSigUpper;
86 mTimeSigLower = timeSigLower;
87}
88
90{
91 Ticks ticks;
92
93 const auto lower = static_cast<double>(mTimeSigLower);
94 if (units < .025 * (60 / mBpm) * (4 / lower))
95 {
96 // measures
98 (60 * mTimeSigUpper) / (mBpm * (lower / 4)) };
99 // thirtysecondth notes (label every quarter note)
100 ticks.minor = { 1, 32, 60 / (mBpm * (lower * 2)) };
101 // hundredtwentyeighth notes
102 ticks.minorMinor = { 1, 128, 60 / (mBpm * (lower * 8)) };
103 }
104 else if (units < .05 * (60 / mBpm) * (4 / lower))
105 {
106 // measures
108 (60 * mTimeSigUpper) / (mBpm * (lower / 4)) };
109 // sixteenth notes (label every quarter note)
110 ticks.minor = { 1, 16, 60 / (mBpm * (lower)) };
111 // sixtyfourth notes
112 ticks.minorMinor = { 1, 64, 60 / (mBpm * (lower * 4)) };
113 }
114 else if (units < .1 * (60 / mBpm) * (4 / lower))
115 {
116 // measures
118 (60 * mTimeSigUpper) / (mBpm * (lower / 4)) };
119 // eigth notes (label every quarter note)
120 ticks.minor = { 1, 8, 60 / (mBpm * (lower / 2)) };
121 // thirtysecondth notes
122 ticks.minorMinor = { 1, 32, 60 / (mBpm * (lower * 2)) };
123 }
124 else if (units < .4 * (60 / mBpm) * (4 / lower))
125 {
126 // measures
128 (60 * mTimeSigUpper) / (mBpm * (lower / 4)) };
129 // eigth notes (label every quarter note)
130 ticks.minor = { 1, 8, 60 / (mBpm * (lower / 2)) };
131 // sixteenth notes
132 ticks.minorMinor = { 1, 16, 60 / (mBpm * (lower)) };
133 }
134 else if (units < .8 * (60 / mBpm) * (4 / lower))
135 {
136 // measures
138 (60 * mTimeSigUpper) / (mBpm * (lower / 4)) };
139 // quarter notes
140 ticks.minor = { 1, 4, 60 / (mBpm * (lower / 4)) };
141 // sixteenth notes
142 ticks.minorMinor = { 1, 16, 60 / (mBpm * (lower)) };
143 }
144 else if (units < 4 * (60 / mBpm) * (4 / lower))
145 {
146 // measures
148 (60 * mTimeSigUpper) / (mBpm * (lower / 4)) };
149 // quarter notes
150 ticks.minorMinor = { 1, 4, 60 / (mBpm * (lower / 4)) };
151 }
152 else if (units < 8 * (60 / mBpm) * (4 / lower))
153 {
154 // four-measures
155 ticks.major = { 4 * mTimeSigUpper, mTimeSigLower,
156 (60 * mTimeSigUpper) / (mBpm * (lower / 16)) };
157 // measures
158 ticks.minor = { 4, mTimeSigLower, 60 / (mBpm * (lower / 16)) };
159 // half measures
160 ticks.minorMinor = { 2, mTimeSigLower, 60 / (mBpm * (lower / 8)) };
161 }
162 else
163 {
164 int factor = pow(
165 2, std::floor(
166 log2(std::ceil(units) * (mBpm / 60) * (mTimeSigLower / 4))) -
167 2);
168 ticks.major = { factor * 4 * mTimeSigUpper, mTimeSigLower,
169 (60 * mTimeSigUpper) / (mBpm * (lower / (16 * factor))) };
170 ticks.minorMinor = { factor * 2, mTimeSigLower,
171 60 / (mBpm * (lower / (8 * factor))) };
172 }
173
174 mTicks = ticks;
175}
176
178{
179 return mTicks;
180}
181
183{
184 SetData(
186}
187
188BeatsFormat::~BeatsFormat() = default;
wxT("CloseDown"))
void SetLabelString(wxString &s, double d, double units, double minor, int mDigits, TickType tickType) const override
Definition: BeatsFormat.cpp:30
~BeatsFormat() override
void UpdateSubdivision(double units)
Definition: BeatsFormat.cpp:89
double mBpm
Definition: BeatsFormat.h:63
BeatsFormat()=delete
int mTimeSigLower
Definition: BeatsFormat.h:65
int mTimeSigUpper
Definition: BeatsFormat.h:64
Ticks mTicks
Definition: BeatsFormat.h:67
void SetData(double bpm, int timeSigUpper, int timeSigLower)
Definition: BeatsFormat.cpp:70
void SetTickSizes(double units, double &major, double &minor, double &minorMinor, int &mDigits) const override
Definition: BeatsFormat.cpp:16
const Ticks & GetSubdivision() const
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept
Definition: fast_float.h:2512