blob: e054b0c816aacc68145e23c4fb67bdbfcc55778a [file] [log] [blame]
// Copyright 2019 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_AUDIO_CORE_VOLUME_CURVE_H_
#define SRC_MEDIA_AUDIO_AUDIO_CORE_VOLUME_CURVE_H_
#include <lib/fit/result.h>
#include <optional>
#include <vector>
namespace media::audio {
// A gain curve is a continuous increasing piecewise linear function that maps from volume over the
// domain [0.0, 1.0] to gain in dbfs.
class VolumeCurve {
public:
enum Error {
kLessThanTwoMappingsCannotMakeCurve = 1,
kDomain0to1NotCovered = 2,
kNonIncreasingDomainIllegal = 3,
kNonIncreasingRangeIllegal = 4,
kRange0NotCovered = 5,
};
// A mapping from volume domain to gain in dbfs.
struct VolumeMapping {
VolumeMapping(float volume_in, float gain_dbfs_in)
: volume(volume_in), gain_dbfs(gain_dbfs_in) {}
float volume;
float gain_dbfs;
};
static constexpr float kDefaultGainForMinVolume = -60.0;
// A default gain curve to use when the curve of the device is unknown, but its minimum gain is
// known.
static VolumeCurve DefaultForMinGain(float min_gain_db);
// Attempts to construct a curve from a mapping from volume domain to gain in dbfs. Mappings must
// represent a continuous increasing function from volume to gain in dbfs over the volume domain
// [0.0, 1.0]. The gain range must start with a negative value and end exactly at 0.0.
static fit::result<VolumeCurve, Error> FromMappings(std::vector<VolumeMapping> mappings);
// Samples the gain curve for the dbfs value at `volume`. Outside of [0.0, 1.0], the volume is
// clamped before sampling.
float VolumeToDb(float volume) const;
// Samples the gain curve for the volume value at `gain_dbfs`. Outside of [-160.0, 0.0], the gain
// is clamped before sampling.
float DbToVolume(float gain_dbfs) const;
// Returns the set of underlying mappings for this curve.
const std::vector<VolumeMapping>& mappings() const { return mappings_; }
private:
explicit VolumeCurve(std::vector<VolumeMapping> mappings);
enum class Attribute {
kVolume,
kGain,
};
// Returns the bounds, the neighboring mappings to attribute x (either gain or volume). If x is
// 0.5, and we have mappings at [0.0, 0.25, 0.75, 1.0] the mappings at 0.25 and 0.75 will be
// returned as bounds. If two bounds do not exist, std::nullopt is returned. Mappings may be
// equal to x on one side.
std::optional<std::pair<VolumeMapping, VolumeMapping>> Bounds(float x, Attribute attribute) const;
// Mappings stored with the assumptions that 1) the map is sorted by volume, 2) there are
// at least two mappings, 3) the volume domain includes [0.0, 1.0], and 4) the final mapping is
// 1.0 => 0.0 dbfs.
std::vector<VolumeMapping> mappings_ = {};
};
} // namespace media::audio
#endif // SRC_MEDIA_AUDIO_AUDIO_CORE_VOLUME_CURVE_H_