/* * 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 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& 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 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 CreateLinearRampEvent( float value, double time, float initial_value, double call_time); static std::unique_ptr CreateExponentialRampEvent( float value, double time, float initial_value, double call_time); static std::unique_ptr CreateSetValueEvent(float value, double time); static std::unique_ptr CreateSetTargetEvent(float value, double time, double time_constant); static std::unique_ptr CreateSetValueCurveEvent( const Vector& curve, double time, double duration); static std::unique_ptr CreateSetValueCurveEndEvent(float value, double time); static std::unique_ptr CreateCancelValuesEvent( double time, std::unique_ptr 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 CreateGeneralEvent( Type, float value, double time, float initial_value, double call_time, double time_constant, double duration, Vector& curve, double curve_points_per_second, float curve_end_value, std::unique_ptr saved_event); static bool EventPreceeds(const std::unique_ptr& a, const std::unique_ptr& 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& Curve() const { return curve_; } Vector& 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& curve, double curve_points_per_second, float curve_end_value, std::unique_ptr 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& curve, double curve_points_per_second, float curve_end_value); // Create CancelValues event ParamEvent(Type, double time, std::unique_ptr 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 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 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, 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 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 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 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 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 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 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 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> 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 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_