1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/media/webaudio/compiledtest/TestAudioEventTimeline.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,451 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim:set ts=2 sw=2 sts=2 et cindent: */ 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "AudioEventTimeline.h" 1.11 +#include "TestHarness.h" 1.12 +#include <sstream> 1.13 +#include <limits> 1.14 + 1.15 +using namespace mozilla; 1.16 +using namespace mozilla::dom; 1.17 +using std::numeric_limits; 1.18 + 1.19 +// Some simple testing primitives 1.20 +void ok(bool val, const char* msg) 1.21 +{ 1.22 + if (val) { 1.23 + passed(msg); 1.24 + } else { 1.25 + fail(msg); 1.26 + } 1.27 +} 1.28 + 1.29 +namespace std { 1.30 + 1.31 +template <class T> 1.32 +basic_ostream<T, char_traits<T> >& 1.33 +operator<<(basic_ostream<T, char_traits<T> >& os, nsresult rv) 1.34 +{ 1.35 + os << static_cast<uint32_t>(rv); 1.36 + return os; 1.37 +} 1.38 + 1.39 +} 1.40 + 1.41 +template <class T, class U> 1.42 +void is(const T& a, const U& b, const char* msg) 1.43 +{ 1.44 + std::stringstream ss; 1.45 + ss << msg << ", Got: " << a << ", expected: " << b; 1.46 + ok(a == b, ss.str().c_str()); 1.47 +} 1.48 + 1.49 +template <> 1.50 +void is(const float& a, const float& b, const char* msg) 1.51 +{ 1.52 + // stupidly high, since we mostly care about the correctness of the algorithm 1.53 + const float kEpsilon = 0.00001f; 1.54 + 1.55 + std::stringstream ss; 1.56 + ss << msg << ", Got: " << a << ", expected: " << b; 1.57 + ok(fabsf(a - b) < kEpsilon, ss.str().c_str()); 1.58 +} 1.59 + 1.60 +class ErrorResultMock 1.61 +{ 1.62 +public: 1.63 + ErrorResultMock() 1.64 + : mRv(NS_OK) 1.65 + { 1.66 + } 1.67 + void Throw(nsresult aRv) 1.68 + { 1.69 + mRv = aRv; 1.70 + } 1.71 + 1.72 + operator nsresult() const 1.73 + { 1.74 + return mRv; 1.75 + } 1.76 + 1.77 + ErrorResultMock& operator=(nsresult aRv) 1.78 + { 1.79 + mRv = aRv; 1.80 + return *this; 1.81 + } 1.82 + 1.83 +private: 1.84 + nsresult mRv; 1.85 +}; 1.86 + 1.87 +typedef AudioEventTimeline<ErrorResultMock> Timeline; 1.88 + 1.89 +void TestSpecExample() 1.90 +{ 1.91 + // First, run the basic tests 1.92 + Timeline timeline(10.0f); 1.93 + is(timeline.Value(), 10.0f, "Correct default value returned"); 1.94 + 1.95 + ErrorResultMock rv; 1.96 + 1.97 + float curve[] = { -1.0f, 0.0f, 1.0f }; 1.98 + 1.99 + // This test is copied from the example in the Web Audio spec 1.100 + const double t0 = 0.0, 1.101 + t1 = 0.1, 1.102 + t2 = 0.2, 1.103 + t3 = 0.3, 1.104 + t4 = 0.4, 1.105 + t5 = 0.6, 1.106 + t6 = 0.7, 1.107 + t7 = 1.0; 1.108 + timeline.SetValueAtTime(0.2f, t0, rv); 1.109 + is(rv, NS_OK, "SetValueAtTime succeeded"); 1.110 + timeline.SetValueAtTime(0.3f, t1, rv); 1.111 + is(rv, NS_OK, "SetValueAtTime succeeded"); 1.112 + timeline.SetValueAtTime(0.4f, t2, rv); 1.113 + is(rv, NS_OK, "SetValueAtTime succeeded"); 1.114 + timeline.LinearRampToValueAtTime(1.0f, t3, rv); 1.115 + is(rv, NS_OK, "LinearRampToValueAtTime succeeded"); 1.116 + timeline.LinearRampToValueAtTime(0.15f, t4, rv); 1.117 + is(rv, NS_OK, "LinearRampToValueAtTime succeeded"); 1.118 + timeline.ExponentialRampToValueAtTime(0.75f, t5, rv); 1.119 + is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded"); 1.120 + timeline.ExponentialRampToValueAtTime(0.05f, t6, rv); 1.121 + is(rv, NS_OK, "ExponentialRampToValueAtTime succeeded"); 1.122 + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), t6, t7 - t6, rv); 1.123 + is(rv, NS_OK, "SetValueCurveAtTime succeeded"); 1.124 + 1.125 + is(timeline.GetValueAtTime(0.0), 0.2f, "Correct value"); 1.126 + is(timeline.GetValueAtTime(0.05), 0.2f, "Correct value"); 1.127 + is(timeline.GetValueAtTime(0.1), 0.3f, "Correct value"); 1.128 + is(timeline.GetValueAtTime(0.15), 0.3f, "Correct value"); 1.129 + is(timeline.GetValueAtTime(0.2), 0.4f, "Correct value"); 1.130 + is(timeline.GetValueAtTime(0.25), (0.4f + 1.0f) / 2, "Correct value"); 1.131 + is(timeline.GetValueAtTime(0.3), 1.0f, "Correct value"); 1.132 + is(timeline.GetValueAtTime(0.35), (1.0f + 0.15f) / 2, "Correct value"); 1.133 + is(timeline.GetValueAtTime(0.4), 0.15f, "Correct value"); 1.134 + is(timeline.GetValueAtTime(0.45), (0.15f * powf(0.75f / 0.15f, 0.05f / 0.2f)), "Correct value"); 1.135 + is(timeline.GetValueAtTime(0.5), (0.15f * powf(0.75f / 0.15f, 0.5f)), "Correct value"); 1.136 + is(timeline.GetValueAtTime(0.55), (0.15f * powf(0.75f / 0.15f, 0.15f / 0.2f)), "Correct value"); 1.137 + is(timeline.GetValueAtTime(0.6), 0.75f, "Correct value"); 1.138 + is(timeline.GetValueAtTime(0.65), (0.75f * powf(0.05f / 0.75f, 0.5f)), "Correct value"); 1.139 + is(timeline.GetValueAtTime(0.7), -1.0f, "Correct value"); 1.140 + is(timeline.GetValueAtTime(0.9), 0.0f, "Correct value"); 1.141 + is(timeline.GetValueAtTime(1.0), 1.0f, "Correct value"); 1.142 +} 1.143 + 1.144 +void TestInvalidEvents() 1.145 +{ 1.146 + static_assert(numeric_limits<float>::has_quiet_NaN, "Platform must have a quiet NaN"); 1.147 + const float NaN = numeric_limits<float>::quiet_NaN(); 1.148 + const float Infinity = numeric_limits<float>::infinity(); 1.149 + Timeline timeline(10.0f); 1.150 + 1.151 + float curve[] = { -1.0f, 0.0f, 1.0f }; 1.152 + float badCurve1[] = { -1.0f, NaN, 1.0f }; 1.153 + float badCurve2[] = { -1.0f, Infinity, 1.0f }; 1.154 + float badCurve3[] = { -1.0f, -Infinity, 1.0f }; 1.155 + 1.156 + ErrorResultMock rv; 1.157 + 1.158 + timeline.SetValueAtTime(NaN, 0.1, rv); 1.159 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.160 + timeline.SetValueAtTime(Infinity, 0.1, rv); 1.161 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.162 + timeline.SetValueAtTime(-Infinity, 0.1, rv); 1.163 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.164 + timeline.LinearRampToValueAtTime(NaN, 0.2, rv); 1.165 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.166 + timeline.LinearRampToValueAtTime(Infinity, 0.2, rv); 1.167 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.168 + timeline.LinearRampToValueAtTime(-Infinity, 0.2, rv); 1.169 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.170 + timeline.ExponentialRampToValueAtTime(NaN, 0.3, rv); 1.171 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.172 + timeline.ExponentialRampToValueAtTime(Infinity, 0.3, rv); 1.173 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.174 + timeline.ExponentialRampToValueAtTime(-Infinity, 0.4, rv); 1.175 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.176 + timeline.ExponentialRampToValueAtTime(0, 0.5, rv); 1.177 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.178 + timeline.SetTargetAtTime(NaN, 0.4, 1.0, rv); 1.179 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.180 + timeline.SetTargetAtTime(Infinity, 0.4, 1.0, rv); 1.181 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.182 + timeline.SetTargetAtTime(-Infinity, 0.4, 1.0, rv); 1.183 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.184 + timeline.SetTargetAtTime(0.4f, NaN, 1.0, rv); 1.185 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.186 + timeline.SetTargetAtTime(0.4f, Infinity, 1.0, rv); 1.187 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.188 + timeline.SetTargetAtTime(0.4f, -Infinity, 1.0, rv); 1.189 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.190 + timeline.SetValueCurveAtTime(nullptr, 0, 1.0, 1.0, rv); 1.191 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.192 + timeline.SetValueCurveAtTime(badCurve1, ArrayLength(badCurve1), 1.0, 1.0, rv); 1.193 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.194 + timeline.SetValueCurveAtTime(badCurve2, ArrayLength(badCurve2), 1.0, 1.0, rv); 1.195 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.196 + timeline.SetValueCurveAtTime(badCurve3, ArrayLength(badCurve3), 1.0, 1.0, rv); 1.197 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.198 + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), NaN, 1.0, rv); 1.199 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.200 + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), Infinity, 1.0, rv); 1.201 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.202 + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), -Infinity, 1.0, rv); 1.203 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.204 + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, NaN, rv); 1.205 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.206 + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, Infinity, rv); 1.207 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.208 + timeline.SetValueCurveAtTime(curve, ArrayLength(curve), 1.0, -Infinity, rv); 1.209 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.210 +} 1.211 + 1.212 +void TestEventReplacement() 1.213 +{ 1.214 + Timeline timeline(10.0f); 1.215 + 1.216 + ErrorResultMock rv; 1.217 + 1.218 + is(timeline.GetEventCount(), 0u, "No events yet"); 1.219 + timeline.SetValueAtTime(10.0f, 0.1, rv); 1.220 + is(timeline.GetEventCount(), 1u, "One event scheduled now"); 1.221 + timeline.SetValueAtTime(20.0f, 0.1, rv); 1.222 + is(rv, NS_OK, "Event scheduling should be successful"); 1.223 + is(timeline.GetEventCount(), 1u, "Event should be replaced"); 1.224 + is(timeline.GetValueAtTime(0.1), 20.0f, "The first event should be overwritten"); 1.225 + timeline.LinearRampToValueAtTime(30.0f, 0.1, rv); 1.226 + is(rv, NS_OK, "Event scheduling should be successful"); 1.227 + is(timeline.GetEventCount(), 2u, "Different event type should be appended"); 1.228 + is(timeline.GetValueAtTime(0.1), 30.0f, "The first event should be overwritten"); 1.229 +} 1.230 + 1.231 +void TestEventRemoval() 1.232 +{ 1.233 + Timeline timeline(10.0f); 1.234 + 1.235 + ErrorResultMock rv; 1.236 + 1.237 + timeline.SetValueAtTime(10.0f, 0.1, rv); 1.238 + timeline.SetValueAtTime(15.0f, 0.15, rv); 1.239 + timeline.SetValueAtTime(20.0f, 0.2, rv); 1.240 + timeline.LinearRampToValueAtTime(30.0f, 0.3, rv); 1.241 + is(timeline.GetEventCount(), 4u, "Should have three events initially"); 1.242 + timeline.CancelScheduledValues(0.4); 1.243 + is(timeline.GetEventCount(), 4u, "Trying to delete past the end of the array should have no effect"); 1.244 + timeline.CancelScheduledValues(0.3); 1.245 + is(timeline.GetEventCount(), 3u, "Should successfully delete one event"); 1.246 + timeline.CancelScheduledValues(0.12); 1.247 + is(timeline.GetEventCount(), 1u, "Should successfully delete two events"); 1.248 + timeline.CancelAllEvents(); 1.249 + ok(timeline.HasSimpleValue(), "No event should remain scheduled"); 1.250 +} 1.251 + 1.252 +void TestBeforeFirstEventSetValue() 1.253 +{ 1.254 + Timeline timeline(10.0f); 1.255 + 1.256 + ErrorResultMock rv; 1.257 + 1.258 + timeline.SetValueAtTime(20.0f, 1.0, rv); 1.259 + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); 1.260 +} 1.261 + 1.262 +void TestBeforeFirstEventSetTarget() 1.263 +{ 1.264 + Timeline timeline(10.0f); 1.265 + 1.266 + ErrorResultMock rv; 1.267 + 1.268 + timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); 1.269 + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); 1.270 +} 1.271 + 1.272 +void TestBeforeFirstEventLinearRamp() 1.273 +{ 1.274 + Timeline timeline(10.0f); 1.275 + 1.276 + ErrorResultMock rv; 1.277 + 1.278 + timeline.LinearRampToValueAtTime(20.0f, 1.0, rv); 1.279 + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); 1.280 +} 1.281 + 1.282 +void TestBeforeFirstEventExponentialRamp() 1.283 +{ 1.284 + Timeline timeline(10.0f); 1.285 + 1.286 + ErrorResultMock rv; 1.287 + 1.288 + timeline.ExponentialRampToValueAtTime(20.0f, 1.0, rv); 1.289 + is(timeline.GetValueAtTime(0.5), 10.0f, "Retrun the default value before the first event"); 1.290 +} 1.291 + 1.292 +void TestAfterLastValueEvent() 1.293 +{ 1.294 + Timeline timeline(10.0f); 1.295 + 1.296 + ErrorResultMock rv; 1.297 + 1.298 + timeline.SetValueAtTime(20.0f, 1.0, rv); 1.299 + is(timeline.GetValueAtTime(1.5), 20.0f, "Return the last value after the last SetValue event"); 1.300 +} 1.301 + 1.302 +void TestAfterLastTargetValueEvent() 1.303 +{ 1.304 + Timeline timeline(10.0f); 1.305 + 1.306 + ErrorResultMock rv; 1.307 + 1.308 + timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); 1.309 + is(timeline.GetValueAtTime(10.), (20.f + (10.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after the last SetTarget event based on the curve"); 1.310 +} 1.311 + 1.312 +void TestAfterLastTargetValueEventWithValueSet() 1.313 +{ 1.314 + Timeline timeline(10.0f); 1.315 + 1.316 + ErrorResultMock rv; 1.317 + 1.318 + timeline.SetValue(50.f); 1.319 + timeline.SetTargetAtTime(20.0f, 1.0, 5.0, rv); 1.320 + 1.321 + // When using SetTargetValueAtTime, Timeline become stateful: the value for 1.322 + // time t may depend on the time t-1, so we can't just query the value at a 1.323 + // time and get the right value. We have to call GetValueAtTime for the 1.324 + // previous times. 1.325 + for (double i = 0.0; i < 9.99; i+=0.01) { 1.326 + timeline.GetValueAtTime(i); 1.327 + } 1.328 + 1.329 + is(timeline.GetValueAtTime(10.), (20.f + (50.f - 20.f) * expf(-9.0f / 5.0f)), "Return the value after SetValue and the last SetTarget event based on the curve"); 1.330 +} 1.331 + 1.332 +void TestValue() 1.333 +{ 1.334 + Timeline timeline(10.0f); 1.335 + 1.336 + ErrorResultMock rv; 1.337 + 1.338 + is(timeline.Value(), 10.0f, "value should initially match the default value"); 1.339 + timeline.SetValue(20.0f); 1.340 + is(timeline.Value(), 20.0f, "Should be able to set the value"); 1.341 + timeline.SetValueAtTime(20.0f, 1.0, rv); 1.342 + // TODO: The following check needs to change when we compute the value based on the current time of the context 1.343 + is(timeline.Value(), 20.0f, "TODO..."); 1.344 + timeline.SetValue(30.0f); 1.345 + is(timeline.Value(), 20.0f, "Should not be able to set the value"); 1.346 +} 1.347 + 1.348 +void TestLinearRampAtZero() 1.349 +{ 1.350 + Timeline timeline(10.0f); 1.351 + 1.352 + ErrorResultMock rv; 1.353 + 1.354 + timeline.LinearRampToValueAtTime(20.0f, 0.0, rv); 1.355 + is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0"); 1.356 +} 1.357 + 1.358 +void TestExponentialRampAtZero() 1.359 +{ 1.360 + Timeline timeline(10.0f); 1.361 + 1.362 + ErrorResultMock rv; 1.363 + 1.364 + timeline.ExponentialRampToValueAtTime(20.0f, 0.0, rv); 1.365 + is(timeline.GetValueAtTime(0.0), 20.0f, "Should get the correct value when t0 == t1 == 0"); 1.366 +} 1.367 + 1.368 +void TestLinearRampAtSameTime() 1.369 +{ 1.370 + Timeline timeline(10.0f); 1.371 + 1.372 + ErrorResultMock rv; 1.373 + 1.374 + timeline.SetValueAtTime(5.0f, 1.0, rv); 1.375 + timeline.LinearRampToValueAtTime(20.0f, 1.0, rv); 1.376 + is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); 1.377 +} 1.378 + 1.379 +void TestExponentialRampAtSameTime() 1.380 +{ 1.381 + Timeline timeline(10.0f); 1.382 + 1.383 + ErrorResultMock rv; 1.384 + 1.385 + timeline.SetValueAtTime(5.0f, 1.0, rv); 1.386 + timeline.ExponentialRampToValueAtTime(20.0f, 1.0, rv); 1.387 + is(timeline.GetValueAtTime(1.0), 20.0f, "Should get the correct value when t0 == t1"); 1.388 +} 1.389 + 1.390 +void TestSetTargetZeroTimeConstant() 1.391 +{ 1.392 + Timeline timeline(10.0f); 1.393 + 1.394 + ErrorResultMock rv; 1.395 + 1.396 + timeline.SetTargetAtTime(20.0f, 1.0, 0.0, rv); 1.397 + is(timeline.GetValueAtTime(10.), 20.f, "Should get the correct value with timeConstant == 0"); 1.398 +} 1.399 + 1.400 +void TestExponentialInvalidPreviousZeroValue() 1.401 +{ 1.402 + Timeline timeline(0.f); 1.403 + 1.404 + ErrorResultMock rv; 1.405 + 1.406 + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); 1.407 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.408 + timeline.SetValue(1.f); 1.409 + rv = NS_OK; 1.410 + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); 1.411 + is(rv, NS_OK, "Should succeed this time"); 1.412 + timeline.CancelScheduledValues(0.0); 1.413 + is(timeline.GetEventCount(), 0u, "Should have no events scheduled"); 1.414 + rv = NS_OK; 1.415 + timeline.SetValueAtTime(0.f, 0.5, rv); 1.416 + is(rv, NS_OK, "Should succeed"); 1.417 + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); 1.418 + is(rv, NS_ERROR_DOM_SYNTAX_ERR, "Correct error code returned"); 1.419 + timeline.CancelScheduledValues(0.0); 1.420 + is(timeline.GetEventCount(), 0u, "Should have no events scheduled"); 1.421 + rv = NS_OK; 1.422 + timeline.ExponentialRampToValueAtTime(1.f, 1.0, rv); 1.423 + is(rv, NS_OK, "Should succeed this time"); 1.424 +} 1.425 + 1.426 +int main() 1.427 +{ 1.428 + ScopedXPCOM xpcom("TestAudioEventTimeline"); 1.429 + if (xpcom.failed()) { 1.430 + return 1; 1.431 + } 1.432 + 1.433 + TestSpecExample(); 1.434 + TestInvalidEvents(); 1.435 + TestEventReplacement(); 1.436 + TestEventRemoval(); 1.437 + TestBeforeFirstEventSetValue(); 1.438 + TestBeforeFirstEventSetTarget(); 1.439 + TestBeforeFirstEventLinearRamp(); 1.440 + TestBeforeFirstEventExponentialRamp(); 1.441 + TestAfterLastValueEvent(); 1.442 + TestAfterLastTargetValueEvent(); 1.443 + TestAfterLastTargetValueEventWithValueSet(); 1.444 + TestValue(); 1.445 + TestLinearRampAtZero(); 1.446 + TestExponentialRampAtZero(); 1.447 + TestLinearRampAtSameTime(); 1.448 + TestExponentialRampAtSameTime(); 1.449 + TestSetTargetZeroTimeConstant(); 1.450 + TestExponentialInvalidPreviousZeroValue(); 1.451 + 1.452 + return gFailCount > 0; 1.453 +} 1.454 +