blob: a5ea6c057a668cf00a000c347dd37750154980a3 [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "AudioContext.h"
#include <JavaScriptCore/Forward.h>
#include <wtf/Lock.h>
#include <wtf/Vector.h>
namespace WebCore {
class AudioParamTimeline {
WTF_MAKE_NONCOPYABLE(AudioParamTimeline);
WTF_MAKE_FAST_ALLOCATED;
public:
AudioParamTimeline() = default;
ExceptionOr<void> setValueAtTime(float value, Seconds time);
ExceptionOr<void> linearRampToValueAtTime(float targetValue, Seconds endTime, float currentValue, Seconds currentTime);
ExceptionOr<void> exponentialRampToValueAtTime(float targetValue, Seconds endTime, float currentValue, Seconds currentTime);
ExceptionOr<void> setTargetAtTime(float target, Seconds time, float timeConstant);
ExceptionOr<void> setValueCurveAtTime(Vector<float>&& curve, Seconds time, Seconds duration);
void cancelScheduledValues(Seconds cancelTime);
ExceptionOr<void> cancelAndHoldAtTime(Seconds cancelTime);
// hasValue is set to true if a valid timeline value is returned.
// otherwise defaultValue is returned.
std::optional<float> valueForContextTime(BaseAudioContext&, float defaultValue, float minValue, float maxValue);
// Given the time range, calculates parameter values into the values buffer
// and returns the last parameter value calculated for "values" or the defaultValue if none were calculated.
// controlRate is the rate (number per second) at which parameter values will be calculated.
// It should equal sampleRate for sample-accurate parameter changes, and otherwise will usually match
// the render quantum size such that the parameter value changes once per render quantum.
float valuesForFrameRange(size_t startFrame, size_t endFrame, float defaultValue, float minValue, float maxValue, float* values, unsigned numberOfValues, double sampleRate, double controlRate);
bool hasValues(size_t startFrame, double sampleRate) const;
private:
class ParamEvent {
WTF_MAKE_FAST_ALLOCATED;
public:
enum Type {
SetValue,
LinearRampToValue,
ExponentialRampToValue,
SetTarget,
SetValueCurve,
CancelValues,
LastType
};
struct SavedEvent {
Type type;
float value;
Seconds time;
};
static ParamEvent createSetValueEvent(float value, Seconds time);
static ParamEvent createLinearRampEvent(float value, Seconds time);
static ParamEvent createExponentialRampEvent(float value, Seconds time);
static ParamEvent createSetTargetEvent(float target, Seconds time, float timeConstant);
static ParamEvent createSetValueCurveEvent(Vector<float>&& curve, Seconds time, Seconds duration);
static ParamEvent createCancelValuesEvent(Seconds cancelTime, std::optional<SavedEvent>&&);
ParamEvent(Type type, float value, Seconds time, float timeConstant, Seconds duration, Vector<float>&& curve, double curvePointsPerSecond, float curveEndValue, std::optional<SavedEvent>&& savedEvent)
: m_type(type)
, m_value(value)
, m_time(time)
, m_timeConstant(timeConstant)
, m_duration(duration)
, m_curve(WTFMove(curve))
, m_curvePointsPerSecond(curvePointsPerSecond)
, m_curveEndValue(curveEndValue)
, m_savedEvent(WTFMove(savedEvent))
{
}
Type type() const { return m_type; }
float value() const { return m_value; }
Seconds time() const { return m_time; }
float timeConstant() const { return m_timeConstant; }
Seconds duration() const { return m_duration; }
const Vector<float>& curve() const { return m_curve; }
SavedEvent* savedEvent() { return m_savedEvent ? &m_savedEvent.value() : nullptr; }
void setCancelledValue(float cancelledValue)
{
ASSERT(m_type == Type::CancelValues);
m_value = cancelledValue;
m_hasDefaultCancelledValue = true;
}
bool hasDefaultCancelledValue() const
{
ASSERT(m_type == Type::CancelValues);
return m_hasDefaultCancelledValue;
}
double curvePointsPerSecond() const { return m_curvePointsPerSecond; }
float curveEndValue() const { return m_curveEndValue; }
private:
Type m_type;
float m_value { 0 };
Seconds m_time;
// Only used for SetTarget events.
float m_timeConstant { 0 };
// The duration of the curve.
Seconds m_duration;
// The array of curve points.
Vector<float> m_curve;
// The number of curve points per second. it is used to compute
// the curve index step when running the automation.
double m_curvePointsPerSecond { 0 };
// The default value to use at the end of the curve. Normally
// it's the last entry in m_curve, but cancelling a SetValueCurve
// will set this to a new value.
float m_curveEndValue { 0 };
// True if a default value has been assigned to the CancelValues event.
bool m_hasDefaultCancelledValue { false };
// For CancelValues. If CancelValues is in the middle of an event, this
// holds the event that is being cancelled, so that processing can
// continue as if the event still existed up until we reach the actual
// scheduled cancel time.
std::optional<SavedEvent> m_savedEvent;
};
// State of the timeline for the current event.
struct AutomationState {
// Parameters for the current automation request. Number of
// values to be computed for the automation request
const unsigned numberOfValues;
// Start and end frames for this automation request
const size_t startFrame;
const size_t endFrame;
// Sample rate and control rate for this request
const double sampleRate;
const double controlRate;
const double samplingPeriod;
// Parameters needed for processing the current event.
const unsigned fillToFrame;
const size_t fillToEndFrame;
// Value and time for the current event
const float value1;
const Seconds time1;
// Value and time for the next event, if any.
const float value2;
const Seconds time2;
// The current event, and it's index in the event vector.
const ParamEvent* event;
const int eventIndex;
};
void removeCancelledEvents(size_t firstEventToRemove) WTF_REQUIRES_LOCK(m_eventsLock);
void removeOldEvents(size_t eventCount) WTF_REQUIRES_LOCK(m_eventsLock);
ExceptionOr<void> insertEvent(ParamEvent&&) WTF_REQUIRES_LOCK(m_eventsLock);
float valuesForFrameRangeImpl(size_t startFrame, size_t endFrame, float defaultValue, float* values, unsigned numberOfValues, double sampleRate, double controlRate) WTF_REQUIRES_LOCK(m_eventsLock);
float linearRampAtTime(Seconds t, float value1, Seconds time1, float value2, Seconds time2);
float exponentialRampAtTime(Seconds t, float value1, Seconds time1, float value2, Seconds time2);
float valueCurveAtTime(Seconds t, Seconds time1, Seconds duration, const float* curveData, size_t curveLength);
void handleCancelValues(ParamEvent&, ParamEvent* nextEvent, float& value2, Seconds& time2, ParamEvent::Type& nextEventType);
bool isEventCurrent(const ParamEvent&, const ParamEvent* nextEvent, size_t currentFrame, double sampleRate) const;
void processLinearRamp(const AutomationState&, float* values, size_t& currentFrame, float& value, unsigned& writeIndex);
void processExponentialRamp(const AutomationState&, float* values, size_t& currentFrame, float& value, unsigned& writeIndex);
void processCancelValues(const AutomationState&, float* values, size_t& currentFrame, float& value, unsigned& writeIndex) WTF_REQUIRES_LOCK(m_eventsLock);
void processSetTarget(const AutomationState&, float* values, size_t& currentFrame, float& value, unsigned& writeIndex);
void processSetValueCurve(const AutomationState&, float* values, size_t& currentFrame, float& value, unsigned& writeIndex);
void processSetTargetFollowedByRamp(int eventIndex, ParamEvent*&, ParamEvent::Type nextEventType, size_t currentFrame, double samplingPeriod, double controlRate, float& value) WTF_REQUIRES_LOCK(m_eventsLock);
Vector<ParamEvent> m_events WTF_GUARDED_BY_LOCK(m_eventsLock);
mutable Lock m_eventsLock;
};
} // namespace WebCore