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

Public Member Functions

 ParsedNumericConverterFormatter (NumericConverterType type, const TranslatableString &untranslatedFormat, const FormatterContext &context)
 
bool IsTimeRelatedFormat () const
 
void ParseFormatString ()
 
void UpdateFormat ()
 
ConversionResult ValueToString (double rawValue, bool nearest) 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
 

Private Attributes

const FormatterContext mContext
 
const NumericConverterType mType
 
wxString mFormat
 
const TranslatableString mUntranslatedFormat
 
std::vector< FieldConfigmFieldConfigs
 
double mScalingFactor
 
double mSampleRate { 1.0 }
 
Observer::Subscription mProjectRateChangedSubscription
 
bool mScalingFactorIsSamples { false }
 
bool mNtscDrop
 

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...
 
- Static Public Attributes inherited from Observer::Publisher< NumericConverterFormatChangedMessage >
static constexpr bool notifies_all
 
- 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 159 of file ParsedNumericConverterFormatter.cpp.

Constructor & Destructor Documentation

◆ ParsedNumericConverterFormatter()

anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::ParsedNumericConverterFormatter ( NumericConverterType  type,
const TranslatableString untranslatedFormat,
const FormatterContext context 
)
inline

Definition at line 164 of file ParsedNumericConverterFormatter.cpp.

166 : mContext { context }
167 , mType { type }
168 , mFormat { untranslatedFormat.Translation() }
169 , mUntranslatedFormat { untranslatedFormat }
170 {
171 UpdateFormat();
172
174 {
175 auto project = mContext.GetProject();
176
177 if (project != nullptr)
178 {
179 // We need a non const object to subscribe...
181 const_cast<ProjectRate&>(ProjectRate::Get(*project))
182 .Subscribe([this](const auto&) { UpdateFormat(); });
183 }
184 }
185 }
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
Holds project sample rate.
Definition: ProjectRate.h:24
static ProjectRate & Get(AudacityProject &project)
Definition: ProjectRate.cpp:28
wxString Translation() const

References ProjectRate::Get(), and project.

Here is the call graph for this function:

Member Function Documentation

◆ IsTimeRelatedFormat()

bool anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::IsTimeRelatedFormat ( ) const
inline

Definition at line 187 of file ParsedNumericConverterFormatter.cpp.

188 {
189 return mType == NumericConverterType_TIME() ||
191 }
const NumericConverterType & NumericConverterType_DURATION()
const NumericConverterType & NumericConverterType_TIME()

References NumericConverterType_DURATION(), and NumericConverterType_TIME().

Here is the call graph for this function:

◆ ParseFormatString()

void anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::ParseFormatString ( )
inline

Definition at line 194 of file ParsedNumericConverterFormatter.cpp.

195 {
196 mPrefix.clear();
197 mFields.clear();
198 mDigits.clear();
199 mFieldConfigs.clear();
200
201 mScalingFactor = 1.0;
202
203 // We will change inFrac to true when we hit our first decimal point.
204 bool inFrac = false;
205 int fracMult = 1;
206 int numWholeFields = 0;
207 int numFracFields = 0;
208 wxString numStr;
209 wxString delimStr;
210 unsigned int i;
211
212 mNtscDrop = false;
213 for (i = 0; i < mFormat.length(); i++)
214 {
215 bool handleDelim = false;
216 bool handleNum = false;
217
218 if (mFormat[i] == '|')
219 {
220 wxString remainder = mFormat.Right(mFormat.length() - i - 1);
221 // For languages which use , as a separator.
222 remainder.Replace(wxT(","), wxT("."));
223
224 mScalingFactorIsSamples = remainder == wxT("#");
225
227 {
229 }
230 else if (remainder == wxT("N"))
231 {
232 mNtscDrop = true;
233 }
234 else
235 // Use the C locale here for string to number.
236 // Translations are often incomplete.
237 // We can't rely on the correct ',' or '.' in the
238 // translation, so we work based on '.' for decimal point.
239 remainder.ToCDouble(&mScalingFactor);
240 i = mFormat.length() - 1; // force break out of loop
241 if (!delimStr.empty())
242 handleDelim = true;
243 if (!numStr.empty())
244 handleNum = true;
245 }
246 else if (
247 (mFormat[i] >= '0' && mFormat[i] <= '9') ||
248 mFormat[i] == wxT('*') || mFormat[i] == wxT('#'))
249 {
250 numStr += mFormat[i];
251 if (!delimStr.empty())
252 handleDelim = true;
253 }
254 else
255 {
256 delimStr += mFormat[i];
257 if (!numStr.empty())
258 handleNum = true;
259 }
260
261 if (i == mFormat.length() - 1)
262 {
263 if (!numStr.empty())
264 handleNum = true;
265 if (!delimStr.empty())
266 handleDelim = true;
267 }
268
269 if (handleNum)
270 {
271 bool zeropad = false;
272 long range = 0;
273
274 if (numStr.Right(1) == wxT("#"))
275 range = static_cast<long int>(mSampleRate);
276 else if (numStr.Right(1) != wxT("*"))
277 {
278 numStr.ToLong(&range);
279 }
280 if (numStr.GetChar(0) == '0' && numStr.length() > 1)
281 zeropad = true;
282
283 // Hack: always zeropad
284 zeropad = true;
285
286 if (inFrac)
287 {
288 int base = fracMult * range;
289 mFieldConfigs.push_back({ inFrac, base, range });
290 mFields.push_back(NumericField::ForRange(range, zeropad));
291 fracMult *= range;
292 numFracFields++;
293 }
294 else
295 {
296 unsigned int j;
297 for (j = 0; j < mFields.size(); j++)
298 mFieldConfigs[j].base *= range;
299 mFieldConfigs.push_back({ inFrac, 1, range });
300 mFields.push_back(NumericField::ForRange(range, zeropad));
301 numWholeFields++;
302 }
303 numStr = wxT("");
304 }
305
306 if (handleDelim)
307 {
308 bool goToFrac = false;
309
310 if (!inFrac)
311 {
312 wxChar delim = delimStr[delimStr.length() - 1];
313 if (delim == '<' || delim == '>')
314 {
315 goToFrac = true;
316 if (delimStr.length() > 1)
317 delimStr = delimStr.BeforeLast(delim);
318 }
319 }
320
321 if (inFrac)
322 {
323 if (numFracFields == 0)
324 {
325 // Should never happen
326 return;
327 }
328 if (handleNum && numFracFields > 1)
329 mFields[mFields.size() - 2].label = delimStr;
330 else
331 mFields[mFields.size() - 1].label = delimStr;
332 }
333 else
334 {
335 if (numWholeFields == 0)
336 mPrefix = delimStr;
337 else
338 {
339 delimStr.Replace(wxT("<"), wxT(","));
340 delimStr.Replace(wxT(">"), wxT("."));
341 mFields[numWholeFields - 1].label = delimStr;
342 }
343 }
344
345 if (goToFrac)
346 inFrac = true;
347 delimStr = wxT("");
348 }
349 }
350
351 size_t pos = 0;
352
353 pos += mPrefix.length();
354
355 for (i = 0; i < mFields.size(); i++)
356 {
357 mFields[i].pos = pos;
358
359 for (size_t j = 0; j < mFields[i].digits; j++)
360 {
361 mDigits.push_back(DigitInfo { i, j, pos });
362 pos++;
363 }
364
365 pos += mFields[i].label.length();
366 }
367
368 // This Publish will happen from the
369 // constructor as well, despite it is not
370 // possible to catch it there
371 Publish({});
372 }
wxT("CloseDown"))
CallbackReturn Publish(const NumericConverterFormatChangedMessage &message)
Send a message to connected callbacks.
Definition: Observer.h:207
static NumericField ForRange(size_t range, bool zeropad=true, size_t minDigits=0)

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

Here is the call graph for this function:

◆ SingleStep()

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

Implements NumericConverterFormatter.

Definition at line 577 of file ParsedNumericConverterFormatter.cpp.

578 {
579 const auto dir = upwards ? 1 : -1;
580 for (size_t i = 0; i < mFields.size(); i++)
581 {
582 if (
583 (mDigits[digitIndex].pos >= mFields[i].pos) &&
584 (mDigits[digitIndex].pos < mFields[i].pos + mFields[i].digits))
585 { // it's this field
586 if (value < 0)
587 value = 0;
588
589 value *= mScalingFactor;
590
591 const double mult = pow(
592 10., mFields[i].digits -
593 (mDigits[digitIndex].pos - mFields[i].pos) - 1);
594
595 if (mFieldConfigs[i].frac)
596 {
597 value += ((mult / (double)mFieldConfigs[i].base) * dir);
598 }
599 else
600 {
601 value += ((mult * (double)mFieldConfigs[i].base) * dir);
602 }
603
604 if (mNtscDrop)
605 {
606 if ((value - (int)value) * 30 < 2)
607 {
608 if ((((int)value) % 60 == 0) && (((int)value) % 600 != 0))
609 {
610 value = (int)value + (dir > 0 ? 2. : -1.) / 30.;
611 }
612 }
613 }
614
615 if (value < 0.)
616 {
617 value = 0.;
618 }
619
620 value /= mScalingFactor;
621
622 if (mNtscDrop)
623 {
624 mNtscDrop = false;
625 auto result = ValueToString(value, false);
626 mNtscDrop = true;
627 return *StringToValue(result.valueString);
628 }
629
630 return value;
631 }
632 }
633
634 return value;
635 }

◆ StringToValue()

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

Implements NumericConverterFormatter.

Definition at line 511 of file ParsedNumericConverterFormatter.cpp.

513 {
514 unsigned int i;
515 double t = 0.0;
516
517 if (
518 mFields.size() > 0 &&
519 valueString.Mid(mFields[0].pos, 1) == wxChar('-'))
520 return std::nullopt;
521
522 for (i = 0; i < mFields.size(); i++)
523 {
524 const auto pos = mFields[i].pos;
525 const auto digits = mFields[i].digits;
526
527 if (pos >= valueString.size() || pos + digits > valueString.size())
528 return std::nullopt;
529
530 long val;
531
532 const auto fieldStringValue =
533 valueString.Mid(mFields[i].pos, mFields[i].digits);
534
535 if (!fieldStringValue.ToLong(&val))
536 return std::nullopt;
537
538 if (mFieldConfigs[i].frac)
539 t += (val / (double)mFieldConfigs[i].base);
540 else
541 t += (val * (double)mFieldConfigs[i].base);
542 }
543
544 t /= mScalingFactor;
545
546 if (mNtscDrop)
547 {
548 int t_int = (int)(t + .000000001);
549 double t_frac = (t - t_int);
550 int tenMins = t_int / 600;
551 double frames = tenMins * 17982;
552 t_int -= tenMins * 600;
553 int mins = t_int / 60;
554 int addMins = 0;
555 if (mins > 0)
556 {
557 frames += 1800;
558 addMins = mins - 1;
559 }
560 frames += addMins * 1798;
561 t_int -= mins * 60;
562 if (mins == 0) // first min of a block of 10, don't drop frames 0 and 1
563 frames += t_int * 30 + t_frac * 30.;
564 else
565 { // drop frames 0 and 1 of first seconds of these minutes
566 if (t_int > 0)
567 frames += 28 + (t_int - 1) * 30 + t_frac * 30.;
568 else
569 frames += t_frac * 30. - 2.;
570 }
571 t = frames * 1.001 / 30.;
572 }
573
574 return t;
575 }

◆ UpdateFormat()

void anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::UpdateFormat ( )
inline

Definition at line 374 of file ParsedNumericConverterFormatter.cpp.

375 {
376 const auto newSampleRate = mContext.GetSampleRate();
377
378 const bool sampleRateChanged = newSampleRate != mSampleRate;
379
380 mSampleRate = newSampleRate;
381
382 if (mFields.empty() || (sampleRateChanged && mScalingFactorIsSamples))
384 }
double GetSampleRate(double defaultSampleRate=44100.0) const
Returns a sample rate from this context.

◆ UpdatePrefs()

void anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::UpdatePrefs ( )
inlineoverridevirtual

Implements PrefsListener.

Definition at line 637 of file ParsedNumericConverterFormatter.cpp.

638 {
639 auto newFormat = mUntranslatedFormat.Translation();
640
641 if (mFormat == newFormat)
642 return;
643
644 mFormat = newFormat;
646 }

◆ ValueToString()

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

Implements NumericConverterFormatter.

Definition at line 386 of file ParsedNumericConverterFormatter.cpp.

388 {
389 ConversionResult result;
390
392 rawValue = floor(rawValue * mSampleRate + (nearest ? 0.5f : 0.0f)) /
393 mSampleRate; // put on a sample
394 double theValue = rawValue * mScalingFactor
395 // PRL: what WAS this .000001 for? Nobody could explain.
396 // + .000001
397 ;
398
399 sampleCount t_int;
400 bool round = true;
401 // We round on the last field. If we have a fractional field we round
402 // using it. Otherwise we round to nearest integer.
403 for (size_t i = 0; i < mFields.size(); i++)
404 {
405 if (mFieldConfigs[i].frac)
406 round = false;
407 }
408 if (theValue < 0)
409 t_int = -1;
410 else if (round)
411 t_int = sampleCount(theValue + (nearest ? 0.5f : 0.0f));
412 else
413 {
414 wxASSERT(mFieldConfigs.back().frac);
415 theValue += (nearest ? 0.5f : 0.0f) / mFieldConfigs.back().base;
416 t_int = sampleCount(theValue);
417 }
418 double t_frac;
419 if (theValue < 0)
420 t_frac = -1;
421 else
422 t_frac = (theValue - t_int.as_double());
423
424 int tenMins;
425 int mins;
426 int addMins;
427 int secs;
428 int frames;
429
430 result.valueString = mPrefix;
431
432 if (mNtscDrop && theValue >= 0)
433 {
434 frames = (int)(theValue * 30. / 1.001 + (nearest ? 0.5f : 0.0f));
435 tenMins = frames / 17982;
436 frames -= tenMins * 17982;
437 mins = tenMins * 10;
438 if (frames >= 1800)
439 {
440 frames -= 1800;
441 mins++;
442 addMins = frames / 1798;
443 frames -= addMins * 1798;
444 mins += addMins;
445 secs = frames / 30;
446 frames -= secs * 30;
447 frames += 2;
448 if (frames >= 30)
449 {
450 secs++;
451 frames -= 30;
452 }
453 }
454 else
455 {
456 secs = frames / 30;
457 frames -= secs * 30;
458 }
459 t_int = mins * 60 + secs;
460 t_frac = frames / 30.;
461 }
462
463 for (size_t i = 0; i < mFields.size(); i++)
464 {
465 long long value = -1;
466
467 if (mFieldConfigs[i].frac)
468 {
469 // JKC: This old code looks bogus to me.
470 // The rounding is not propagating to earlier fields in the frac
471 // case.
472 // value = (int)(t_frac * mFields[i].base + 0.5); // +0.5 as
473 // rounding required
474 // I did the rounding earlier.
475 if (t_frac >= 0)
476 value = t_frac * mFieldConfigs[i].base;
477 // JKC: TODO: Find out what the range is supposed to do.
478 // It looks bogus too.
479 // if (mFields[i].range > 0)
480 // value = value % mFields[i].range;
481 }
482 else
483 {
484 if (t_int >= 0)
485 {
486 value = t_int.as_long_long() / mFieldConfigs[i].base;
487 if (mFieldConfigs[i].range > 0)
488 value = value % mFieldConfigs[i].range;
489 }
490 }
491
492 wxString field;
493
494 if (value < 0)
495 {
496 for (int ii = 0; ii < mFields[i].digits; ++ii)
497 field += wxT("-");
498 }
499 else
500 field = wxString::Format(mFields[i].formatStr, (int)value);
501
502 result.fieldValueStrings.push_back(field);
503
504 result.valueString += field;
505 result.valueString += mFields[i].label;
506 }
507
508 return result;
509 }
#define field(n, t)
Definition: ImportAUP.cpp:165
bool HasSampleRate() const
Returns true if it is possible to get a sample rate from this context.
Positions or offsets within audio files need a wide type.
Definition: SampleCount.h:19
long long as_long_long() const
Definition: SampleCount.h:48
double as_double() const
Definition: SampleCount.h:46
fastfloat_really_inline void round(adjusted_mantissa &am, callback cb) noexcept
Definition: fast_float.h:2512

References sampleCount::as_double(), sampleCount::as_long_long(), field, NumericConverterFormatter::ConversionResult::fieldValueStrings, fast_float::round(), NumericConverterFormatter::ConversionResult::valueString, and wxT().

Here is the call graph for this function:

Member Data Documentation

◆ mContext

const FormatterContext anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mContext
private

Definition at line 648 of file ParsedNumericConverterFormatter.cpp.

◆ mFieldConfigs

std::vector<FieldConfig> anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mFieldConfigs
private

Definition at line 653 of file ParsedNumericConverterFormatter.cpp.

◆ mFormat

wxString anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mFormat
private

Definition at line 650 of file ParsedNumericConverterFormatter.cpp.

◆ mNtscDrop

bool anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mNtscDrop
mutableprivate

Definition at line 662 of file ParsedNumericConverterFormatter.cpp.

◆ mProjectRateChangedSubscription

Observer::Subscription anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mProjectRateChangedSubscription
private

Definition at line 658 of file ParsedNumericConverterFormatter.cpp.

◆ mSampleRate

double anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mSampleRate { 1.0 }
private

Definition at line 656 of file ParsedNumericConverterFormatter.cpp.

◆ mScalingFactor

double anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mScalingFactor
private

Definition at line 655 of file ParsedNumericConverterFormatter.cpp.

◆ mScalingFactorIsSamples

bool anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mScalingFactorIsSamples { false }
private

Definition at line 660 of file ParsedNumericConverterFormatter.cpp.

◆ mType

const NumericConverterType anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mType
private

Definition at line 649 of file ParsedNumericConverterFormatter.cpp.

◆ mUntranslatedFormat

const TranslatableString anonymous_namespace{ParsedNumericConverterFormatter.cpp}::ParsedNumericConverterFormatter::mUntranslatedFormat
private

Definition at line 651 of file ParsedNumericConverterFormatter.cpp.


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