blob: 1ff9e359ab2beee16c6ec450435320aa8cad22f0 [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 Computer, 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.
*/
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_PARAM_TIMELINE_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_PARAM_TIMELINE_H_
#include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
#include "third_party/blink/renderer/modules/webaudio/audio_destination_node.h"
#include "third_party/blink/renderer/modules/webaudio/base_audio_context.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
#include "third_party/blink/renderer/platform/wtf/threading.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
#include <tuple>
namespace blink {
class AudioParamTimeline {
DISALLOW_NEW();
public:
AudioParamTimeline() = default;
void SetValueAtTime(float value, double time, ExceptionState&);
void LinearRampToValueAtTime(float value,
double time,
float initial_value,
double call_time,
ExceptionState&);
void ExponentialRampToValueAtTime(float value,
double time,
float initial_value,
double call_time,
ExceptionState&);
void SetTargetAtTime(float target,
double time,
double time_constant,
ExceptionState&);
void SetValueCurveAtTime(const Vector<float>& curve,
double time,
double duration,
ExceptionState&);
void CancelScheduledValues(double start_time, ExceptionState&);
void CancelAndHoldAtTime(double cancel_time, ExceptionState&);
// Compute the value from this AudioParamHandler at the current context frame.
// Returns two values:
//
// bool has_value - to indicate if the value could be computed from the
// timeline
// float value - the timeline value if |has_value| is true; otherwise
// |default_value| is returned.
std::tuple<bool, float> ValueForContextTime(AudioDestinationHandler&,
float default_value,
float min_value,
float max_value);
// Given the time range in frames, 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 start_frame,
size_t end_frame,
float default_value,
float* values,
unsigned number_of_values,
double sample_rate,
double control_rate,
float min_value,
float max_value);
// Returns true if the AudioParam timeline needs to run in this
// rendering quantum. This means some automation is already running
// or is scheduled to run in the current rendering quantuym.
bool HasValues(size_t current_frame, double sample_rate) const;
float SmoothedValue() { return smoothed_value_; }
void SetSmoothedValue(float v) { smoothed_value_ = v; }
private:
class ParamEvent {
public:
enum Type {
kSetValue,
kLinearRampToValue,
kExponentialRampToValue,
kSetTarget,
kSetValueCurve,
// For cancelValuesAndHold
kCancelValues,
// Special marker for the end of a |kSetValueCurve| event.
kSetValueCurveEnd,
kLastType
};
static std::unique_ptr<ParamEvent> CreateLinearRampEvent(
float value,
double time,
float initial_value,
double call_time);
static std::unique_ptr<ParamEvent> CreateExponentialRampEvent(
float value,
double time,
float initial_value,
double call_time);
static std::unique_ptr<ParamEvent> CreateSetValueEvent(float value,
double time);
static std::unique_ptr<ParamEvent>
CreateSetTargetEvent(float value, double time, double time_constant);
static std::unique_ptr<ParamEvent> CreateSetValueCurveEvent(
const Vector<float>& curve,
double time,
double duration);
static std::unique_ptr<ParamEvent> CreateSetValueCurveEndEvent(float value,
double time);
static std::unique_ptr<ParamEvent> CreateCancelValuesEvent(
double time,
std::unique_ptr<ParamEvent> saved_event);
// Needed for creating a saved event where we want to supply all
// the possible parameters because we're mostly copying an
// existing event.
static std::unique_ptr<ParamEvent> CreateGeneralEvent(
Type,
float value,
double time,
float initial_value,
double call_time,
double time_constant,
double duration,
Vector<float>& curve,
double curve_points_per_second,
float curve_end_value,
std::unique_ptr<ParamEvent> saved_event);
static bool EventPreceeds(const std::unique_ptr<ParamEvent>& a,
const std::unique_ptr<ParamEvent>& b) {
return a->Time() < b->Time();
}
Type GetType() const { return type_; }
float Value() const { return value_; }
double Time() const { return time_; }
void SetTime(double new_time) { time_ = new_time; }
double TimeConstant() const { return time_constant_; }
double Duration() const { return duration_; }
const Vector<float>& Curve() const { return curve_; }
Vector<float>& Curve() { return curve_; }
float InitialValue() const { return initial_value_; }
double CallTime() const { return call_time_; }
double CurvePointsPerSecond() const { return curve_points_per_second_; }
float CurveEndValue() const { return curve_end_value_; }
// For CancelValues events. Not valid for any other event.
ParamEvent* SavedEvent() const;
bool HasDefaultCancelledValue() const;
void SetCancelledValue(float);
private:
// General event
ParamEvent(Type type,
float value,
double time,
float initial_value,
double call_time,
double time_constant,
double duration,
Vector<float>& curve,
double curve_points_per_second,
float curve_end_value,
std::unique_ptr<ParamEvent> saved_event);
// Create simplest event needing just a value and time, like
// setValueAtTime.
ParamEvent(Type, float value, double time);
// Create a linear or exponential ramp that requires an initial
// value and time in case there is no actual event that preceeds
// this event.
ParamEvent(Type,
float value,
double time,
float initial_value,
double call_time);
// Create an event needing a time constant (setTargetAtTime)
ParamEvent(Type, float value, double time, double time_constant);
// Create a setValueCurve event
ParamEvent(Type,
double time,
double duration,
const Vector<float>& curve,
double curve_points_per_second,
float curve_end_value);
// Create CancelValues event
ParamEvent(Type, double time, std::unique_ptr<ParamEvent> saved_event);
Type type_;
// The value for the event. The interpretation of this depends on
// the event type. Not used for SetValueCurve. For CancelValues,
// it is the end value to use when cancelling a LinearRampToValue
// or ExponentialRampToValue event.
float value_;
// The time for the event. The interpretation of this depends on
// the event type.
double time_;
// Initial value and time to use for linear and exponential ramps that don't
// have a preceding event.
float initial_value_;
double call_time_;
// Only used for SetTarget events
double time_constant_;
// The following items are only used for SetValueCurve events.
//
// The duration of the curve.
double duration_;
// The array of curve points.
Vector<float> curve_;
// The number of curve points per second. it is used to compute
// the curve index step when running the automation.
double curve_points_per_second_;
// 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 curve_end_value_;
// 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::unique_ptr<ParamEvent> saved_event_;
// True if a default value has been assigned to the CancelValues event.
bool has_default_cancelled_value_;
};
// 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 number_of_values;
// Start and end frames for this automation request
const size_t start_frame;
const size_t end_frame;
// Sample rate and control rate for this request
const double sample_rate;
const double control_rate;
// Parameters needed for processing the current event.
const unsigned fill_to_frame;
const size_t fill_to_end_frame;
// Value and time for the current event
const float value1;
const double time1;
// Value and time for the next event, if any.
const float value2;
const double time2;
// The current event, and it's index in the event vector.
const ParamEvent* event;
const int event_index;
};
void InsertEvent(std::unique_ptr<ParamEvent>, ExceptionState&);
float ValuesForFrameRangeImpl(size_t start_frame,
size_t end_frame,
float default_value,
float* values,
unsigned number_of_values,
double sample_rate,
double control_rate);
// Produce a nice string describing the event in human-readable form.
String EventToString(const ParamEvent&) const;
// Automation functions that compute the vlaue of the specified
// automation at the specified time.
float LinearRampAtTime(double t,
float value1,
double time1,
float value2,
double time2);
float ExponentialRampAtTime(double t,
float value1,
double time1,
float value2,
double time2);
float TargetValueAtTime(double t,
float value1,
double time1,
float value2,
float time_constant);
float ValueCurveAtTime(double t,
double time1,
double duration,
const float* curve_data,
unsigned curve_length);
// Handles the special case where the first event in the timeline
// starts after |startFrame|. These initial values are filled using
// |defaultValue|. The updated |currentFrame| and |writeIndex| is
// returned.
std::tuple<size_t, unsigned> HandleFirstEvent(float* values,
float default_value,
unsigned number_of_values,
size_t start_frame,
size_t end_frame,
double sample_rate,
size_t current_frame,
unsigned write_index);
// Return true if |currentEvent| starts after |currentFrame|, but
// also takes into account the |nextEvent| if any.
bool IsEventCurrent(const ParamEvent* current_event,
const ParamEvent* next_event,
size_t current_frame,
double sample_rate) const;
// Clamp times to current time, if needed for any new events. Note,
// this method can mutate |events_|, so do call this only in safe
// places.
void ClampNewEventsToCurrentTime(double current_time);
// Handle the case where the last event in the timeline is in the
// past. Returns false if any event is not in the past. Otherwise,
// return true and also fill in |values| with |defaultValue|.
// |defaultValue| may be updated with a new value.
bool HandleAllEventsInThePast(double current_time,
double sample_rate,
float& default_value,
unsigned number_of_values,
float* values);
// Handle processing of CancelValue event. If cancellation happens, value2,
// time2, and nextEventType will be updated with the new value due to
// cancellation. Note that |next_event| or its member can be null.
std::tuple<float, double, ParamEvent::Type> HandleCancelValues(
const ParamEvent* current_event,
ParamEvent* next_event,
float value2,
double time2);
// Process a SetTarget event and the next event is a
// LinearRampToValue or ExponentialRampToValue event. This requires
// special handling because the ramp should start at whatever value
// the SetTarget event has reached at this time, instead of using
// the value of the SetTarget event.
void ProcessSetTargetFollowedByRamp(int event_index,
ParamEvent*& current_event,
ParamEvent::Type next_event_type,
size_t current_frame,
double sample_rate,
double control_rate,
float& value);
// Handle processing of linearRampEvent, writing the appropriate
// values to |values|. Returns the updated |currentFrame|, last
// computed |value|, and the updated |writeIndex|.
std::tuple<size_t, float, unsigned> ProcessLinearRamp(
const AutomationState& current_state,
float* values,
size_t current_frame,
float value,
unsigned write_index);
// Handle processing of exponentialRampEvent, writing the appropriate
// values to |values|. Returns the updated |currentFrame|, last
// computed |value|, and the updated |writeIndex|.
std::tuple<size_t, float, unsigned> ProcessExponentialRamp(
const AutomationState& current_state,
float* values,
size_t current_frame,
float value,
unsigned write_index);
// Handle processing of SetTargetEvent, writing the appropriate
// values to |values|. Returns the updated |currentFrame|, last
// computed |value|, and the updated |writeIndex|.
std::tuple<size_t, float, unsigned> ProcessSetTarget(
const AutomationState& current_state,
float* values,
size_t current_frame,
float value,
unsigned write_index);
// Handle processing of SetValueCurveEvent, writing the appropriate
// values to |values|. Returns the updated |currentFrame|, last
// computed |value|, and the updated |writeIndex|.
std::tuple<size_t, float, unsigned> ProcessSetValueCurve(
const AutomationState& current_state,
float* values,
size_t current_frame,
float value,
unsigned write_index);
// Handle processing of CancelValuesEvent, writing the appropriate
// values to |values|. Returns the updated |currentFrame|, last
// computed |value|, and the updated |writeIndex|.
std::tuple<size_t, float, unsigned> ProcessCancelValues(
const AutomationState& current_state,
float* values,
size_t current_frame,
float value,
unsigned write_index);
// Fill the output vector |values| with the value |defaultValue|,
// starting at |writeIndex| and continuing up to |endFrame|
// (exclusive). |writeIndex| is updated with the new index.
uint32_t FillWithDefault(float* values,
float default_value,
uint32_t end_frame,
uint32_t write_index);
// When cancelling events, remove the items from |events_| starting
// at the given index. Update |new_events_| too.
void RemoveCancelledEvents(wtf_size_t first_event_to_remove);
// Remove old events, but always leave at least one event in the timeline.
// This is needed in case a new event is added (like linearRamp) that would
// use a previous event to compute the automation.
void RemoveOldEvents(wtf_size_t n_events);
// Vector of all automation events for the AudioParam. Access must
// be locked via m_eventsLock.
Vector<std::unique_ptr<ParamEvent>> events_;
// Vector of raw pointers to the actual ParamEvent that was
// inserted. As new events are added, |new_events_| is updated with
// tne new event. When the timline is processed, these events are
// clamped to current time by |ClampNewEventsToCurrentTime|. Access
// must be locked via |events_lock_|. Must be maintained together
// with |events_|.
HashSet<ParamEvent*> new_events_;
mutable Mutex events_lock_;
// Smoothing (de-zippering)
float smoothed_value_;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_WEBAUDIO_AUDIO_PARAM_TIMELINE_H_