blob: 282ba03e7aab2c2cd10bfce5f3d1160208d291bd [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_MEDIA_AUDIO_LIB_TIMELINE_TIMELINE_RATE_H_
#define SRC_MEDIA_AUDIO_LIB_TIMELINE_TIMELINE_RATE_H_
#include <stdint.h>
#include <zircon/assert.h>
#include <limits>
namespace media {
// TimelineRate expresses the relative rate of a timeline as the ratio between two uint64_t values
// subject_delta / reference_delta. "subject" refers to the timeline whose rate is being
// represented, and "reference" refers to the timeline relative to which the rate is expressed.
class TimelineRate final {
public:
// Used to indicate overflow of scaling operations.
static constexpr int64_t kOverflow = std::numeric_limits<int64_t>::max();
// Zero as a TimelineRate.
static const TimelineRate Zero;
// Nanoseconds (subject) per second (reference) as a TimelineRate.
static const TimelineRate NsPerSecond;
// Returns the product of the rates. If exact is true, crash on precision loss.
static TimelineRate Product(TimelineRate a, TimelineRate b, bool exact = true);
TimelineRate() : subject_delta_(0), reference_delta_(1) {}
// Creates a TimelineRate from a numerator and denominator.
TimelineRate(uint64_t subject_delta, uint64_t reference_delta);
// Creates a TimelineRate based on a floating-point value. ASSERTs on negative values.
explicit TimelineRate(float rate_as_float) : TimelineRate(static_cast<double>(rate_as_float)) {}
explicit TimelineRate(double rate_as_double)
: TimelineRate(rate_as_double > 1.0 ? kDoubleFactor
: static_cast<uint64_t>(kDoubleFactor * rate_as_double),
rate_as_double > 1.0 ? static_cast<uint64_t>(kDoubleFactor / rate_as_double)
: kDoubleFactor) {
ZX_DEBUG_ASSERT(rate_as_double >= 0.0);
}
// Determines whether this |TimelineRate| is invertible.
bool invertible() const { return subject_delta_ != 0; }
// Returns the inverse of the rate. DCHECKs if the subject_delta of this rate is zero.
TimelineRate Inverse() const {
ZX_DEBUG_ASSERT(subject_delta_ != 0);
// Note: TimelineRates should always be in reduced form. Because of this, we need not invoke the
// subject/reference constructor (which attempts to reduce the ratio). Instead, use the default
// constructor and just swap subject/reference.
TimelineRate ret;
ret.subject_delta_ = reference_delta_;
ret.reference_delta_ = subject_delta_;
return ret;
}
// Rounding mode for Scale operations.
enum class RoundingMode {
Truncate, // round towards zero
Floor, // round down
Ceiling, // round up
};
// Scales the value by this rate. Returns kOverflow on overflow or underflow.
int64_t Scale(int64_t value, RoundingMode mode = RoundingMode::Truncate) const;
uint64_t subject_delta() const { return subject_delta_; }
uint64_t reference_delta() const { return reference_delta_; }
private:
// Multiplier for double-to-TimelineRate conversion (doubles have fixed bit-width mantissas).
static constexpr uint64_t kDoubleFactor = 1ul << 52;
uint64_t subject_delta_;
uint64_t reference_delta_;
};
// Tests two rates for equality.
inline bool operator==(TimelineRate a, TimelineRate b) {
return a.subject_delta() == b.subject_delta() && a.reference_delta() == b.reference_delta();
}
// Tests two rates for inequality.
inline bool operator!=(TimelineRate a, TimelineRate b) { return !(a == b); }
} // namespace media
#endif // SRC_MEDIA_AUDIO_LIB_TIMELINE_TIMELINE_RATE_H_