AudioParamTimeline.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. /*
  2. * Copyright (C) 2011 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
  18. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #if ENABLE(WEB_AUDIO)
  27. #include "AudioParamTimeline.h"
  28. #include "AudioUtilities.h"
  29. #include "FloatConversion.h"
  30. #include <algorithm>
  31. #include <wtf/MathExtras.h>
  32. using namespace std;
  33. namespace WebCore {
  34. void AudioParamTimeline::setValueAtTime(float value, float time)
  35. {
  36. insertEvent(ParamEvent(ParamEvent::SetValue, value, time, 0, 0, 0));
  37. }
  38. void AudioParamTimeline::linearRampToValueAtTime(float value, float time)
  39. {
  40. insertEvent(ParamEvent(ParamEvent::LinearRampToValue, value, time, 0, 0, 0));
  41. }
  42. void AudioParamTimeline::exponentialRampToValueAtTime(float value, float time)
  43. {
  44. insertEvent(ParamEvent(ParamEvent::ExponentialRampToValue, value, time, 0, 0, 0));
  45. }
  46. void AudioParamTimeline::setTargetAtTime(float target, float time, float timeConstant)
  47. {
  48. insertEvent(ParamEvent(ParamEvent::SetTarget, target, time, timeConstant, 0, 0));
  49. }
  50. void AudioParamTimeline::setValueCurveAtTime(Float32Array* curve, float time, float duration)
  51. {
  52. insertEvent(ParamEvent(ParamEvent::SetValueCurve, 0, time, 0, duration, curve));
  53. }
  54. static bool isValidNumber(float x)
  55. {
  56. return !std::isnan(x) && !std::isinf(x);
  57. }
  58. void AudioParamTimeline::insertEvent(const ParamEvent& event)
  59. {
  60. // Sanity check the event. Be super careful we're not getting infected with NaN or Inf.
  61. bool isValid = event.type() < ParamEvent::LastType
  62. && isValidNumber(event.value())
  63. && isValidNumber(event.time())
  64. && isValidNumber(event.timeConstant())
  65. && isValidNumber(event.duration())
  66. && event.duration() >= 0;
  67. ASSERT(isValid);
  68. if (!isValid)
  69. return;
  70. MutexLocker locker(m_eventsLock);
  71. unsigned i = 0;
  72. float insertTime = event.time();
  73. for (i = 0; i < m_events.size(); ++i) {
  74. // Overwrite same event type and time.
  75. if (m_events[i].time() == insertTime && m_events[i].type() == event.type()) {
  76. m_events[i] = event;
  77. return;
  78. }
  79. if (m_events[i].time() > insertTime)
  80. break;
  81. }
  82. m_events.insert(i, event);
  83. }
  84. void AudioParamTimeline::cancelScheduledValues(float startTime)
  85. {
  86. MutexLocker locker(m_eventsLock);
  87. // Remove all events starting at startTime.
  88. for (unsigned i = 0; i < m_events.size(); ++i) {
  89. if (m_events[i].time() >= startTime) {
  90. m_events.remove(i, m_events.size() - i);
  91. break;
  92. }
  93. }
  94. }
  95. float AudioParamTimeline::valueForContextTime(AudioContext* context, float defaultValue, bool& hasValue)
  96. {
  97. ASSERT(context);
  98. {
  99. MutexTryLocker tryLocker(m_eventsLock);
  100. if (!tryLocker.locked() || !context || !m_events.size() || context->currentTime() < m_events[0].time()) {
  101. hasValue = false;
  102. return defaultValue;
  103. }
  104. }
  105. // Ask for just a single value.
  106. float value;
  107. double sampleRate = context->sampleRate();
  108. double startTime = context->currentTime();
  109. double endTime = startTime + 1.1 / sampleRate; // time just beyond one sample-frame
  110. double controlRate = sampleRate / AudioNode::ProcessingSizeInFrames; // one parameter change per render quantum
  111. value = valuesForTimeRange(startTime, endTime, defaultValue, &value, 1, sampleRate, controlRate);
  112. hasValue = true;
  113. return value;
  114. }
  115. float AudioParamTimeline::valuesForTimeRange(
  116. double startTime,
  117. double endTime,
  118. float defaultValue,
  119. float* values,
  120. unsigned numberOfValues,
  121. double sampleRate,
  122. double controlRate)
  123. {
  124. // We can't contend the lock in the realtime audio thread.
  125. MutexTryLocker tryLocker(m_eventsLock);
  126. if (!tryLocker.locked()) {
  127. if (values) {
  128. for (unsigned i = 0; i < numberOfValues; ++i)
  129. values[i] = defaultValue;
  130. }
  131. return defaultValue;
  132. }
  133. float value = valuesForTimeRangeImpl(startTime, endTime, defaultValue, values, numberOfValues, sampleRate, controlRate);
  134. return value;
  135. }
  136. float AudioParamTimeline::valuesForTimeRangeImpl(
  137. double startTime,
  138. double endTime,
  139. float defaultValue,
  140. float* values,
  141. unsigned numberOfValues,
  142. double sampleRate,
  143. double controlRate)
  144. {
  145. ASSERT(values);
  146. if (!values)
  147. return defaultValue;
  148. // Return default value if there are no events matching the desired time range.
  149. if (!m_events.size() || endTime <= m_events[0].time()) {
  150. for (unsigned i = 0; i < numberOfValues; ++i)
  151. values[i] = defaultValue;
  152. return defaultValue;
  153. }
  154. // Maintain a running time and index for writing the values buffer.
  155. double currentTime = startTime;
  156. unsigned writeIndex = 0;
  157. // If first event is after startTime then fill initial part of values buffer with defaultValue
  158. // until we reach the first event time.
  159. double firstEventTime = m_events[0].time();
  160. if (firstEventTime > startTime) {
  161. double fillToTime = min(endTime, firstEventTime);
  162. unsigned fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - startTime, sampleRate);
  163. fillToFrame = min(fillToFrame, numberOfValues);
  164. for (; writeIndex < fillToFrame; ++writeIndex)
  165. values[writeIndex] = defaultValue;
  166. currentTime = fillToTime;
  167. }
  168. float value = defaultValue;
  169. // Go through each event and render the value buffer where the times overlap,
  170. // stopping when we've rendered all the requested values.
  171. // FIXME: could try to optimize by avoiding having to iterate starting from the very first event
  172. // and keeping track of a "current" event index.
  173. int n = m_events.size();
  174. for (int i = 0; i < n && writeIndex < numberOfValues; ++i) {
  175. ParamEvent& event = m_events[i];
  176. ParamEvent* nextEvent = i < n - 1 ? &(m_events[i + 1]) : 0;
  177. // Wait until we get a more recent event.
  178. if (nextEvent && nextEvent->time() < currentTime)
  179. continue;
  180. float value1 = event.value();
  181. double time1 = event.time();
  182. float value2 = nextEvent ? nextEvent->value() : value1;
  183. double time2 = nextEvent ? nextEvent->time() : endTime + 1;
  184. double deltaTime = time2 - time1;
  185. float k = deltaTime > 0 ? 1 / deltaTime : 0;
  186. double sampleFrameTimeIncr = 1 / sampleRate;
  187. double fillToTime = min(endTime, time2);
  188. unsigned fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - startTime, sampleRate);
  189. fillToFrame = min(fillToFrame, numberOfValues);
  190. ParamEvent::Type nextEventType = nextEvent ? static_cast<ParamEvent::Type>(nextEvent->type()) : ParamEvent::LastType /* unknown */;
  191. // First handle linear and exponential ramps which require looking ahead to the next event.
  192. if (nextEventType == ParamEvent::LinearRampToValue) {
  193. for (; writeIndex < fillToFrame; ++writeIndex) {
  194. float x = (currentTime - time1) * k;
  195. value = (1 - x) * value1 + x * value2;
  196. values[writeIndex] = value;
  197. currentTime += sampleFrameTimeIncr;
  198. }
  199. } else if (nextEventType == ParamEvent::ExponentialRampToValue) {
  200. if (value1 <= 0 || value2 <= 0) {
  201. // Handle negative values error case by propagating previous value.
  202. for (; writeIndex < fillToFrame; ++writeIndex)
  203. values[writeIndex] = value;
  204. } else {
  205. float numSampleFrames = deltaTime * sampleRate;
  206. // The value goes exponentially from value1 to value2 in a duration of deltaTime seconds (corresponding to numSampleFrames).
  207. // Compute the per-sample multiplier.
  208. float multiplier = powf(value2 / value1, 1 / numSampleFrames);
  209. // Set the starting value of the exponential ramp. This is the same as multiplier ^
  210. // AudioUtilities::timeToSampleFrame(currentTime - time1, sampleRate), but is more
  211. // accurate, especially if multiplier is close to 1.
  212. value = value1 * powf(value2 / value1,
  213. AudioUtilities::timeToSampleFrame(currentTime - time1, sampleRate) / numSampleFrames);
  214. for (; writeIndex < fillToFrame; ++writeIndex) {
  215. values[writeIndex] = value;
  216. value *= multiplier;
  217. currentTime += sampleFrameTimeIncr;
  218. }
  219. }
  220. } else {
  221. // Handle event types not requiring looking ahead to the next event.
  222. switch (event.type()) {
  223. case ParamEvent::SetValue:
  224. case ParamEvent::LinearRampToValue:
  225. case ParamEvent::ExponentialRampToValue:
  226. {
  227. currentTime = fillToTime;
  228. // Simply stay at a constant value.
  229. value = event.value();
  230. for (; writeIndex < fillToFrame; ++writeIndex)
  231. values[writeIndex] = value;
  232. break;
  233. }
  234. case ParamEvent::SetTarget:
  235. {
  236. currentTime = fillToTime;
  237. // Exponential approach to target value with given time constant.
  238. float target = event.value();
  239. float timeConstant = event.timeConstant();
  240. float discreteTimeConstant = static_cast<float>(AudioUtilities::discreteTimeConstantForSampleRate(timeConstant, controlRate));
  241. for (; writeIndex < fillToFrame; ++writeIndex) {
  242. values[writeIndex] = value;
  243. value += (target - value) * discreteTimeConstant;
  244. }
  245. break;
  246. }
  247. case ParamEvent::SetValueCurve:
  248. {
  249. Float32Array* curve = event.curve();
  250. float* curveData = curve ? curve->data() : 0;
  251. unsigned numberOfCurvePoints = curve ? curve->length() : 0;
  252. // Curve events have duration, so don't just use next event time.
  253. float duration = event.duration();
  254. float durationFrames = duration * sampleRate;
  255. float curvePointsPerFrame = static_cast<float>(numberOfCurvePoints) / durationFrames;
  256. if (!curve || !curveData || !numberOfCurvePoints || duration <= 0 || sampleRate <= 0) {
  257. // Error condition - simply propagate previous value.
  258. currentTime = fillToTime;
  259. for (; writeIndex < fillToFrame; ++writeIndex)
  260. values[writeIndex] = value;
  261. break;
  262. }
  263. // Save old values and recalculate information based on the curve's duration
  264. // instead of the next event time.
  265. unsigned nextEventFillToFrame = fillToFrame;
  266. float nextEventFillToTime = fillToTime;
  267. fillToTime = min(endTime, time1 + duration);
  268. fillToFrame = AudioUtilities::timeToSampleFrame(fillToTime - startTime, sampleRate);
  269. fillToFrame = min(fillToFrame, numberOfValues);
  270. // Index into the curve data using a floating-point value.
  271. // We're scaling the number of curve points by the duration (see curvePointsPerFrame).
  272. float curveVirtualIndex = 0;
  273. if (time1 < currentTime) {
  274. // Index somewhere in the middle of the curve data.
  275. // Don't use timeToSampleFrame() since we want the exact floating-point frame.
  276. float frameOffset = (currentTime - time1) * sampleRate;
  277. curveVirtualIndex = curvePointsPerFrame * frameOffset;
  278. }
  279. // Render the stretched curve data using nearest neighbor sampling.
  280. // Oversampled curve data can be provided if smoothness is desired.
  281. for (; writeIndex < fillToFrame; ++writeIndex) {
  282. // Ideally we'd use round() from MathExtras, but we're in a tight loop here
  283. // and we're trading off precision for extra speed.
  284. unsigned curveIndex = static_cast<unsigned>(0.5 + curveVirtualIndex);
  285. curveVirtualIndex += curvePointsPerFrame;
  286. // Bounds check.
  287. if (curveIndex < numberOfCurvePoints)
  288. value = curveData[curveIndex];
  289. values[writeIndex] = value;
  290. }
  291. // If there's any time left after the duration of this event and the start
  292. // of the next, then just propagate the last value.
  293. for (; writeIndex < nextEventFillToFrame; ++writeIndex)
  294. values[writeIndex] = value;
  295. // Re-adjust current time
  296. currentTime = nextEventFillToTime;
  297. break;
  298. }
  299. }
  300. }
  301. }
  302. // If there's any time left after processing the last event then just propagate the last value
  303. // to the end of the values buffer.
  304. for (; writeIndex < numberOfValues; ++writeIndex)
  305. values[writeIndex] = value;
  306. return value;
  307. }
  308. } // namespace WebCore
  309. #endif // ENABLE(WEB_AUDIO)