summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/modules/webaudio/audio_param_timeline.h
blob: e0cf3cd4825723b89d340382b2db24908925fe91 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
/*
 * 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&);

  // hasValue is set to true if a valid timeline value is returned.
  // otherwise defaultValue is returned.
  float ValueForContextTime(AudioDestinationHandler&,
                            float default_value,
                            bool& has_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 size_t 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.  The
  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.
  unsigned FillWithDefault(float* values,
                           float default_value,
                           size_t end_frame,
                           unsigned write_index);

  // When cancelling events, remove the items from |events_| starting
  // at the given index.  Update |new_events_| too.
  void RemoveCancelledEvents(size_t first_event_to_remove);

  // 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_