Audacity 3.2.0
Public Member Functions | Static Public Attributes | Private Attributes | List of all members
anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter Class Referencefinal
Inheritance diagram for anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter:
[legend]
Collaboration diagram for anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter:
[legend]

Public Member Functions

 BeatsFormatter (const FormatterContext &context, int fracPart, bool timeFormat)
 
bool CheckField (size_t fieldIndex, int value) const noexcept
 Check that field exists and has enough digits to fit the value. More...
 
bool CheckFracField (int newLts) const noexcept
 
void UpdateFields (size_t barsDigits)
 
void UpdateFormat (const AudacityProject &project)
 
void UpdateFormatForValue (double value, bool canShrink) override
 Potentially updates the format so it can fit the value. Default implementation is empty. More...
 
void UpdateResultString (ConversionResult &result) const
 
ConversionResult ValueToString (double value, bool) const override
 
std::optional< double > StringToValue (const wxString &valueString) const override
 
double SingleStep (double value, int digitIndex, bool upwards) const override
 
void UpdatePrefs () override
 
- Public Member Functions inherited from NumericConverterFormatter
virtual ~NumericConverterFormatter ()
 
virtual void UpdateFormatForValue (double value, bool canShrink)
 Potentially updates the format so it can fit the value. Default implementation is empty. More...
 
virtual ConversionResult ValueToString (double value, bool nearest) const =0
 
virtual std::optional< double > StringToValue (const wxString &value) const =0
 
virtual double SingleStep (double value, int digitIndex, bool upwards) const =0
 
const wxString & GetPrefix () const
 
const NumericFieldsGetFields () const
 
const DigitInfosGetDigitInfos () const
 
- Public Member Functions inherited from Observer::Publisher< NumericConverterFormatChangedMessage >
 Publisher (ExceptionPolicy *pPolicy=nullptr, Alloc a={})
 Constructor supporting type-erased custom allocation/deletion. More...
 
 Publisher (Publisher &&)=default
 
Publisheroperator= (Publisher &&)=default
 
Subscription Subscribe (Callback callback)
 Connect a callback to the Publisher; later-connected are called earlier. More...
 
Subscription Subscribe (Object &obj, Return(Object::*callback)(Args...))
 Overload of Subscribe takes an object and pointer-to-member-function. More...
 
- Public Member Functions inherited from PrefsListener
 PrefsListener ()
 
virtual ~PrefsListener ()
 
virtual void UpdatePrefs ()=0
 

Static Public Attributes

static constexpr std::array< size_t, 3 > MIN_DIGITS { 3, 2, 2 }
 
static constexpr std::array< size_t, 3 > UPPER_BOUNDS
 
- Static Public Attributes inherited from Observer::Publisher< NumericConverterFormatChangedMessage >
static constexpr bool notifies_all
 

Private Attributes

const FormatterContext mContext
 
Observer::Subscription mTimeSignatureChangedSubscription
 
double mTempo { 0.0 }
 
int mUpperTimeSignature { 0 }
 
int mLowerTimeSignature { 0 }
 
const int mFracPart
 
const int mFieldValueOffset
 
std::array< double, 3 > mFieldLengths {}
 
wxString mBarString
 
wxString mBeatString
 

Additional Inherited Members

- Public Types inherited from Observer::Publisher< NumericConverterFormatChangedMessage >
using message_type = NumericConverterFormatChangedMessage
 
using CallbackReturn = std::conditional_t< true, void, bool >
 
using Callback = std::function< CallbackReturn(const NumericConverterFormatChangedMessage &) >
 Type of functions that can be connected to the Publisher. More...
 
- Static Public Member Functions inherited from PrefsListener
static void Broadcast (int id=0)
 Call this static function to notify all PrefsListener objects. More...
 
- Protected Member Functions inherited from Observer::Publisher< NumericConverterFormatChangedMessage >
CallbackReturn Publish (const NumericConverterFormatChangedMessage &message)
 Send a message to connected callbacks. More...
 
- Protected Member Functions inherited from PrefsListener
virtual void UpdateSelectedPrefs (int id)
 
- Protected Attributes inherited from NumericConverterFormatter
wxString mPrefix
 
NumericFields mFields
 
DigitInfos mDigits
 

Detailed Description

Definition at line 40 of file BeatsNumericConverterFormatter.cpp.

Constructor & Destructor Documentation

◆ BeatsFormatter()

anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::BeatsFormatter ( const FormatterContext context,
int  fracPart,
bool  timeFormat 
)
inline

Definition at line 51 of file BeatsNumericConverterFormatter.cpp.

52 : mContext { context }
53 , mFracPart { fracPart }
54 , mFieldValueOffset { timeFormat ? 1 : 0 }
55 {
57
58 if (!project)
59 return;
60
61 mBarString = BarString.Translation();
62 mBeatString = BeatString.Translation();
63
65
66 // Subscribing requires non-const reference
69 .Subscribe(
70 [this](const auto&)
71 {
72 // Receiving this message means that project is
73 // alive and well
75 Publish({});
76 });
77 }
const auto project
std::shared_ptr< const AudacityProject > GetProject() const
Returns a potentially null pointer to the project.
Subscription Subscribe(Callback callback)
Connect a callback to the Publisher; later-connected are called earlier.
Definition: Observer.h:199
CallbackReturn Publish(const NumericConverterFormatChangedMessage &message)
Send a message to connected callbacks.
Definition: Observer.h:207
static ProjectTimeSignature & Get(AudacityProject &project)

References anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BarString, anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatString, ProjectTimeSignature::Get(), and project.

Here is the call graph for this function:

Member Function Documentation

◆ CheckField()

bool anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::CheckField ( size_t  fieldIndex,
int  value 
) const
inlinenoexcept

Check that field exists and has enough digits to fit the value.

Definition at line 80 of file BeatsNumericConverterFormatter.cpp.

81 {
82 if (fieldIndex >= mFields.size())
83 return false;
84
85 const auto digitsCount = mFields[fieldIndex].digits;
86
87 // Format always allows at least two digits
88 const auto lowerRange =
89 digitsCount > MIN_DIGITS[fieldIndex] ? Get10Pow(digitsCount - 1) : 0;
90
91 const auto upperRange = Get10Pow(digitsCount);
92
93 return value >= int(lowerRange) && value < int(upperRange);
94 }

References anonymous_namespace{BeatsNumericConverterFormatter.cpp}::Get10Pow().

Here is the call graph for this function:

◆ CheckFracField()

bool anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::CheckFracField ( int  newLts) const
inlinenoexcept

Definition at line 96 of file BeatsNumericConverterFormatter.cpp.

97 {
98 if (mFracPart > newLts)
100 else
101 return mFields.size() == 2;
102 }
bool CheckField(size_t fieldIndex, int value) const noexcept
Check that field exists and has enough digits to fit the value.

◆ SingleStep()

double anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::SingleStep ( double  value,
int  digitIndex,
bool  upwards 
) const
inlineoverridevirtual

Implements NumericConverterFormatter.

Definition at line 303 of file BeatsNumericConverterFormatter.cpp.

304 {
305 if (digitIndex < 0 || size_t(digitIndex) >= mDigits.size())
306 return value;
307
308 const auto& digit = mDigits[digitIndex];
309 const auto& fieldIndex = digit.field;
310 const auto& field = mFields[fieldIndex];
311
312 const auto stepSize = mFieldLengths[fieldIndex] *
313 std::pow(10, field.digits - digit.index - 1);
314
315 return upwards ? value + stepSize : value - stepSize;
316 }
#define field(n, t)
Definition: ImportAUP.cpp:165

References field.

◆ StringToValue()

std::optional< double > anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::StringToValue ( const wxString &  valueString) const
inlineoverridevirtual

Implements NumericConverterFormatter.

Definition at line 268 of file BeatsNumericConverterFormatter.cpp.

269 {
270 if (
271 mFields.size() > 0 &&
272 valueString.Mid(mFields[0].pos, 1) == wxChar('-'))
273 return std::nullopt;
274
275 double t = 0.0;
276 size_t lastIndex = 0;
277
278 for (size_t i = 0; i < mFields.size(); i++)
279 {
280 const auto& field = mFields[i];
281
282 const size_t labelIndex = field.label.empty() ?
284 valueString.find(field.label, lastIndex);
285
286 long val;
287
288 const auto fieldStringValue = valueString.Mid(
289 lastIndex,
290 labelIndex == wxString::npos ? labelIndex : labelIndex - lastIndex);
291
292 if (!fieldStringValue.ToLong(&val))
293 return std::nullopt;
294
295 t += (val - mFieldValueOffset) * mFieldLengths[i];
296
297 lastIndex = labelIndex + field.label.Length();
298 }
299
300 return t;
301 }
constexpr size_t npos(-1)

References field, and Tuple::detail::npos().

Here is the call graph for this function:

◆ UpdateFields()

void anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::UpdateFields ( size_t  barsDigits)
inline

Definition at line 104 of file BeatsNumericConverterFormatter.cpp.

105 {
106 mFields.clear();
107 mDigits.clear();
108
109 // Range is assumed to allow 999 bars.
110 auto& barsField =
111 mFields.emplace_back(NumericField::WithDigits(barsDigits));
112
113 barsField.label = L" " + mBarString + L" ";
114
115 // Beats format is 1 based. For the time point "0" the expected output is
116 // "1 bar 1 beat [1]" For this reason we use (uts + 1) as the "range". On
117 // top of that, we want at least two digits to be shown. NumericField
118 // accepts range as in [0, range), so add 1.
119
120 auto& beatsField = mFields.emplace_back(NumericField::ForRange(
121 std::max<size_t>(UPPER_BOUNDS[1], mUpperTimeSignature + 1)));
122
123 beatsField.label = L" " + mBeatString;
124
125 const auto hasFracPart = mFracPart > mLowerTimeSignature;
126
127 if (hasFracPart)
128 {
129 beatsField.label += L" ";
130 // See the reasoning above about the range
131 auto& fracField = mFields.emplace_back(NumericField::ForRange(
132 std::max(11, mFracPart / mLowerTimeSignature + 1)));
133 }
134
135 // Fill the aux mDigits structure
136 size_t pos = 0;
137 for (size_t i = 0; i < mFields.size(); i++)
138 {
139 mFields[i].pos = pos;
140
141 for (size_t j = 0; j < mFields[i].digits; j++)
142 {
143 mDigits.push_back(DigitInfo { i, j, pos });
144 pos++;
145 }
146
147 pos += mFields[i].label.length();
148 }
149 }
static NumericField WithDigits(size_t digits, bool zeropad=true)
static NumericField ForRange(size_t range, bool zeropad=true, size_t minDigits=0)

References NumericField::ForRange(), and NumericField::WithDigits().

Here is the call graph for this function:

◆ UpdateFormat()

void anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::UpdateFormat ( const AudacityProject project)
inline

Definition at line 151 of file BeatsNumericConverterFormatter.cpp.

152 {
153 auto& timeSignature = ProjectTimeSignature::Get(project);
154
155 const double newTempo = timeSignature.GetTempo();
156 const int newUts = timeSignature.GetUpperTimeSignature();
157 const int newLts = timeSignature.GetLowerTimeSignature();
158
159 if (newTempo == mTempo && newUts == mUpperTimeSignature && newLts == mLowerTimeSignature)
160 return ;
161
162 const bool formatOk = CheckField(1, newUts) && CheckFracField(newLts);
163
164 mTempo = newTempo;
165 mUpperTimeSignature = newUts;
166 mLowerTimeSignature = newLts;
167
168 // 1/4 = BPM is used for now
169 const auto quarterLength = 60.0 / mTempo;
170 const auto beatLength = quarterLength * 4.0 / mLowerTimeSignature;
171 const auto barLength = mUpperTimeSignature * beatLength;
172
173 mFieldLengths[0] = barLength;
174 mFieldLengths[1] = beatLength;
175
176 const auto hasFracPart = mFracPart > mLowerTimeSignature;
177
178 if (hasFracPart)
179 {
180 const auto fracLength = beatLength * mLowerTimeSignature / mFracPart;
181 mFieldLengths[2] = fracLength;
182 }
183
184 if (formatOk)
185 return ;
186
188 }

References ProjectTimeSignature::Get(), and project.

Here is the call graph for this function:

◆ UpdateFormatForValue()

void anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::UpdateFormatForValue ( double  value,
bool  canShrink 
)
inlineoverridevirtual

Potentially updates the format so it can fit the value. Default implementation is empty.

Reimplemented from NumericConverterFormatter.

Definition at line 190 of file BeatsNumericConverterFormatter.cpp.

191 {
192 // Beats formatter does not support negative values
193 value = std::max(0.0, value);
194
195 // ForRange has a preserved weird behavior
196 const auto barsCount =
197 // Range is not inclusive
198 1 +
199 // Bars can start from 1
201 static_cast<int>(std::floor(value / mFieldLengths[0]));
202
203 const auto barsField = NumericField::ForRange(
204 barsCount, true, MIN_DIGITS[0]);
205
206 const auto oldDigits = mFields[0].digits;
207
208 const bool updateNeeded = canShrink ? oldDigits != barsField.digits :
209 oldDigits < barsField.digits;
210
211 if (!updateNeeded)
212 return;
213
214 UpdateFields(barsField.digits);
215 Publish({ value, oldDigits > mFields[0].digits });
216 }

References NumericField::ForRange().

Here is the call graph for this function:

◆ UpdatePrefs()

void anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::UpdatePrefs ( )
inlineoverridevirtual

Implements PrefsListener.

Definition at line 318 of file BeatsNumericConverterFormatter.cpp.

319 {
320 auto project = mContext.GetProject();
321
322 if (!project)
323 return;
324
325 auto barString = BarString.Translation();
326 auto beatString = BeatString.Translation();
327
328 if (barString == mBarString && beatString == mBeatString)
329 return;
330
331 mBarString = barString;
332 mBeatString = beatString;
333
335 }

References anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BarString, anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatString, and project.

◆ UpdateResultString()

void anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::UpdateResultString ( ConversionResult result) const
inline

Definition at line 218 of file BeatsNumericConverterFormatter.cpp.

219 {
220 for (size_t fieldIndex = 0; fieldIndex < mFields.size(); ++fieldIndex)
221 {
222 result.valueString +=
223 result.fieldValueStrings[fieldIndex] + mFields[fieldIndex].label;
224 }
225 }

References NumericConverterFormatter::ConversionResult::fieldValueStrings, and NumericConverterFormatter::ConversionResult::valueString.

◆ ValueToString()

ConversionResult anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::ValueToString ( double  value,
bool  nearest 
) const
inlineoverridevirtual
Postcondition
result: GetFields().size() == result.fieldValueStrings.size()

Implements NumericConverterFormatter.

Definition at line 227 of file BeatsNumericConverterFormatter.cpp.

228 {
229 ConversionResult result;
230 result.fieldValueStrings.resize(mFields.size());
231
232 if (value < 0)
233 {
234 for (size_t fieldIndex = 0; fieldIndex < mFields.size (); ++fieldIndex)
235 {
236 const auto digitsCount = mFields[fieldIndex].digits;
237 auto& fieldValue = result.fieldValueStrings[fieldIndex];
238 for (int digitIndex = 0; digitIndex < digitsCount; ++digitIndex)
239 fieldValue += L"-";
240 }
241
242 UpdateResultString(result);
243
244 return result;
245 }
246
247 // Calculate the epsilon only once, so the total loss of precision is addressed.
248 // This is a "multiplicative" epsilon, so there is no need to calculate 1 + eps every time.
249 const auto eps =
250 1.0 + std::max(1.0, value) * std::numeric_limits<double>::epsilon();
251
252 for (size_t fieldIndex = 0; fieldIndex < mFields.size(); ++fieldIndex)
253 {
254 const auto fieldLength = mFieldLengths[fieldIndex];
255 const auto fieldValue = std::max(
256 0, static_cast<int>(std::floor(value * eps / fieldLength)));
257
258 result.fieldValueStrings[fieldIndex] = wxString::Format(
259 mFields[fieldIndex].formatStr, fieldValue + mFieldValueOffset);
260
261 value = value - fieldValue * fieldLength;
262 }
263
264 UpdateResultString(result);
265 return result;
266 }

References NumericConverterFormatter::ConversionResult::fieldValueStrings.

Member Data Documentation

◆ mBarString

wxString anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mBarString
private

Definition at line 353 of file BeatsNumericConverterFormatter.cpp.

◆ mBeatString

wxString anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mBeatString
private

Definition at line 354 of file BeatsNumericConverterFormatter.cpp.

◆ mContext

const FormatterContext anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mContext
private

Definition at line 338 of file BeatsNumericConverterFormatter.cpp.

◆ mFieldLengths

std::array<double, 3> anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mFieldLengths {}
private

Definition at line 351 of file BeatsNumericConverterFormatter.cpp.

◆ mFieldValueOffset

const int anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mFieldValueOffset
private

Definition at line 349 of file BeatsNumericConverterFormatter.cpp.

◆ mFracPart

const int anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mFracPart
private

Definition at line 347 of file BeatsNumericConverterFormatter.cpp.

◆ MIN_DIGITS

constexpr std::array<size_t, 3> anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::MIN_DIGITS { 3, 2, 2 }
staticconstexpr

Definition at line 45 of file BeatsNumericConverterFormatter.cpp.

◆ mLowerTimeSignature

int anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mLowerTimeSignature { 0 }
private

Definition at line 345 of file BeatsNumericConverterFormatter.cpp.

◆ mTempo

double anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mTempo { 0.0 }
private

Definition at line 342 of file BeatsNumericConverterFormatter.cpp.

◆ mTimeSignatureChangedSubscription

Observer::Subscription anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mTimeSignatureChangedSubscription
private

Definition at line 340 of file BeatsNumericConverterFormatter.cpp.

◆ mUpperTimeSignature

int anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::mUpperTimeSignature { 0 }
private

Definition at line 344 of file BeatsNumericConverterFormatter.cpp.

◆ UPPER_BOUNDS

constexpr std::array<size_t, 3> anonymous_namespace{BeatsNumericConverterFormatter.cpp}::BeatsFormatter::UPPER_BOUNDS
staticconstexpr
Initial value:
{
Get10Pow(MIN_DIGITS[0] - 1) + 1, Get10Pow(MIN_DIGITS[1] - 1) + 1,
Get10Pow(MIN_DIGITS[2] - 1) + 1
}

Definition at line 46 of file BeatsNumericConverterFormatter.cpp.


The documentation for this class was generated from the following file: