![]() |
pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
|
00001 /* 00002 ------------------------------------------------------------------------------- 00003 This file is part of the Plink, Plonk, Plank libraries 00004 by Martin Robinson 00005 00006 http://code.google.com/p/pl-nk/ 00007 00008 Copyright University of the West of England, Bristol 2011-14 00009 All rights reserved. 00010 00011 Redistribution and use in source and binary forms, with or without 00012 modification, are permitted provided that the following conditions are met: 00013 00014 * Redistributions of source code must retain the above copyright 00015 notice, this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright 00017 notice, this list of conditions and the following disclaimer in the 00018 documentation and/or other materials provided with the distribution. 00019 * Neither the name of University of the West of England, Bristol nor 00020 the names of its contributors may be used to endorse or promote products 00021 derived from this software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00026 DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF THE WEST OF ENGLAND, BRISTOL BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 This software makes use of third party libraries. For more information see: 00035 doc/license.txt included in the distribution. 00036 ------------------------------------------------------------------------------- 00037 */ 00038 00039 #ifndef PLONK_BREAKPOINTS_H 00040 #define PLONK_BREAKPOINTS_H 00041 00042 #include "../core/plonk_CoreForwardDeclarations.h" 00043 #include "plonk_ContainerForwardDeclarations.h" 00044 #include "plonk_DynamicContainer.h" 00045 00046 #include "../core/plonk_SmartPointer.h" 00047 #include "../core/plonk_WeakPointer.h" 00048 #include "plonk_ObjectArray.h" 00049 #include "plonk_SimpleArray.h" 00050 00051 // allow some shapes to use double calculations 00052 template<class ValueType> 00053 struct ShapeCalcType 00054 { 00055 union Elem 00056 { 00057 ValueType norm; 00058 double dbl; 00059 } u; 00060 }; 00061 00062 template<class ValueType> 00063 struct ShapeState 00064 { 00065 LongLong stepsToTarget; 00066 ValueType currentLevel; 00067 ValueType targetLevel; 00068 ShapeCalcType<ValueType> grow; 00069 ShapeCalcType<ValueType> a2; 00070 ShapeCalcType<ValueType> b1; 00071 ShapeCalcType<ValueType> y1; 00072 ShapeCalcType<ValueType> y2; 00073 int shapeType; 00074 float curve; 00075 }; 00076 00077 class Shape 00078 { 00079 public: 00080 enum ShapeType 00081 { 00082 Linear, 00083 Numerical, 00084 Sine, 00085 NumShapeTypes 00086 }; 00087 00088 Shape() throw() 00089 : type (Linear), 00090 curve (0.f) 00091 { 00092 } 00093 00094 Shape (const float curveToUse) throw() 00095 : type (Numerical), 00096 curve (curveToUse) 00097 { 00098 } 00099 00100 Shape (ShapeType const& typeToUse) throw() 00101 : type (typeToUse), 00102 curve (0.f) 00103 { 00104 } 00105 00106 ShapeType getType() const throw() { return type; } 00107 float getCurve() const throw() { return curve; } 00108 void setType (ShapeType const& newType) throw() { type = newType; } 00109 void setCurve (const float newCurve) throw() { type = Numerical; curve = newCurve; } 00110 00111 template<class ValueType> 00112 static inline void sustain (ShapeState<ValueType>& shapeState) 00113 { 00114 shapeState.stepsToTarget = TypeUtility<LongLong>::getTypePeak(); 00115 shapeState.currentLevel = shapeState.targetLevel; 00116 shapeState.shapeType = Shape::Linear; 00117 shapeState.curve = 0.f; 00118 shapeState.grow.u.norm = Math<ValueType>::get0(); 00119 } 00120 00121 template<class ValueType> 00122 static inline void initShape (ShapeState<ValueType>& shapeState) 00123 { 00124 if (shapeState.shapeType == Shape::Linear) 00125 initLinear (shapeState); 00126 else if (shapeState.shapeType == Shape::Numerical) 00127 initNumerical (shapeState); 00128 else if (shapeState.shapeType == Shape::Sine) 00129 initSine (shapeState); 00130 else 00131 initLinear (shapeState); 00132 } 00133 00134 template<class ValueType> 00135 static inline ValueType next (ShapeState<ValueType>& shapeState) 00136 { 00137 if (shapeState.stepsToTarget == 1) 00138 { 00139 const ValueType result = shapeState.currentLevel; 00140 sustain (shapeState); 00141 return result; 00142 } 00143 else 00144 { 00145 --shapeState.stepsToTarget; 00146 00147 if (shapeState.shapeType == Shape::Linear) 00148 return nextLinear (shapeState); 00149 else if (shapeState.shapeType == Shape::Numerical) 00150 return nextNumerical (shapeState); 00151 else if (shapeState.shapeType == Shape::Sine) 00152 return nextSine (shapeState); 00153 else 00154 return nextLinear (shapeState); 00155 } 00156 } 00157 00158 template<class ValueType> 00159 static inline void processShape (ShapeState<ValueType>& shapeState, ValueType* outputSamples, const int numSamples) 00160 { 00161 plonk_assert (outputSamples != &shapeState.currentLevel); 00162 00163 int numSamplesRemaining = numSamples; 00164 00165 while (numSamplesRemaining > 0) 00166 { 00167 const int numSamplesThisTime = int (plonk::min (LongLong (numSamples), shapeState.stepsToTarget)); 00168 00169 if (shapeState.shapeType == Shape::Linear) 00170 processLinear (shapeState, outputSamples, numSamplesThisTime); 00171 else if (shapeState.shapeType == Shape::Numerical) 00172 processNumerical (shapeState, outputSamples, numSamplesThisTime); 00173 else if (shapeState.shapeType == Shape::Sine) 00174 processSine (shapeState, outputSamples, numSamplesThisTime); 00175 else 00176 processLinear (shapeState, outputSamples, numSamplesThisTime); 00177 00178 numSamplesRemaining -= numSamplesThisTime; 00179 outputSamples += numSamplesThisTime; 00180 00181 if (numSamplesRemaining > 0) 00182 { 00183 shapeState.stepsToTarget = TypeUtility<LongLong>::getTypePeak(); 00184 shapeState.currentLevel = shapeState.targetLevel; 00185 shapeState.shapeType = Shape::Linear; 00186 shapeState.grow.u.norm = 0; 00187 } 00188 } 00189 } 00190 00191 private: 00192 template<class ValueType> 00193 static inline void initLinear (ShapeState<ValueType>& shapeState) throw() 00194 { 00195 const ValueType diff = shapeState.targetLevel - shapeState.currentLevel; 00196 shapeState.grow.u.norm = diff / ValueType (shapeState.stepsToTarget); 00197 } 00198 00199 template<class ValueType> 00200 static inline void initNumerical (ShapeState<ValueType>& shapeState) throw() 00201 { 00202 const ValueType& zero = Math<ValueType>::get0(); 00203 const ValueType diff = shapeState.targetLevel - shapeState.currentLevel; 00204 00205 if ((plonk::abs (shapeState.curve) < 0.001f) || (diff == zero)) 00206 { 00207 shapeState.shapeType = Shape::Linear; 00208 shapeState.curve = 0.f; 00209 initLinear (shapeState); 00210 } 00211 else 00212 { 00213 const ValueType& one = Math<ValueType>::get1(); 00214 const ValueType a1 = diff / (one - plonk::exp (shapeState.curve)); 00215 shapeState.a2.u.norm = shapeState.currentLevel + a1; 00216 shapeState.b1.u.norm = a1; 00217 shapeState.grow.u.norm = plonk::exp (shapeState.curve / ValueType (shapeState.stepsToTarget)); 00218 } 00219 } 00220 00221 template<class ValueType> 00222 static inline void initSine (ShapeState<ValueType>& shapeState) throw() 00223 { 00224 const double pi = Math<double>::getPi(); 00225 const double piOverTwo = Math<double>::getPi_2(); 00226 const double half = Math<double>::get0_5(); 00227 const double two = Math<double>::get2(); 00228 const double sum = shapeState.targetLevel + shapeState.currentLevel; 00229 const double diff = shapeState.targetLevel - shapeState.currentLevel; 00230 const double w = pi / double (shapeState.stepsToTarget); 00231 00232 shapeState.a2.u.dbl = sum * half; 00233 shapeState.b1.u.dbl = two * plonk::cos (w); 00234 shapeState.y1.u.dbl = diff * half; 00235 shapeState.y2.u.dbl = shapeState.y1.u.dbl * plonk::sin (piOverTwo - w); 00236 shapeState.currentLevel = ValueType (shapeState.a2.u.dbl - shapeState.y1.u.dbl); 00237 } 00238 00239 template<class ValueType> 00240 static inline ValueType nextLinear (ShapeState<ValueType>& shapeState) throw() 00241 { 00242 const ValueType result = shapeState.currentLevel; 00243 shapeState.currentLevel += shapeState.grow.u.norm; 00244 return result; 00245 } 00246 00247 template<class ValueType> 00248 static inline ValueType nextNumerical (ShapeState<ValueType>& shapeState) throw() 00249 { 00250 const ValueType result = shapeState.currentLevel; 00251 shapeState.b1.u.norm *= shapeState.grow.u.norm; 00252 shapeState.currentLevel = shapeState.a2.u.norm - shapeState.b1.u.norm; 00253 return result; 00254 } 00255 00256 template<class ValueType> 00257 static inline ValueType nextSine (ShapeState<ValueType>& shapeState) throw() 00258 { 00259 const ValueType result = shapeState.currentLevel; 00260 const double y0 = shapeState.b1.u.dbl * shapeState.y1.u.dbl - shapeState.y2.u.dbl; 00261 shapeState.currentLevel = ValueType (shapeState.a2.u.dbl - y0); 00262 shapeState.y2.u.dbl = shapeState.y1.u.dbl; 00263 shapeState.y1.u.dbl = y0; 00264 return result; 00265 } 00266 00267 template<class ValueType> 00268 static inline void processLinear (ShapeState<ValueType>& shapeState, ValueType* const outputSamples, const int numSamples) throw() 00269 { 00270 const ValueType& zero = Math<ValueType>::get0(); 00271 00272 if (shapeState.grow.u.norm == zero) 00273 { 00274 for (int i = 0; i < numSamples; ++i) 00275 outputSamples[i] = shapeState.currentLevel; 00276 } 00277 else if (numSamples == shapeState.stepsToTarget) 00278 { 00279 const int lastIndex = numSamples - 1; 00280 00281 for (int i = 0; i < lastIndex; ++i) 00282 outputSamples[i] = nextLinear (shapeState); 00283 00284 outputSamples[lastIndex] = shapeState.currentLevel = shapeState.targetLevel; 00285 } 00286 else 00287 { 00288 for (int i = 0; i < numSamples; ++i) 00289 outputSamples[i] = nextLinear (shapeState); 00290 } 00291 00292 shapeState.stepsToTarget -= numSamples; 00293 } 00294 00295 template<class ValueType> 00296 static inline void processNumerical (ShapeState<ValueType>& shapeState, ValueType* const outputSamples, const int numSamples) throw() 00297 { 00298 if (numSamples == shapeState.stepsToTarget) 00299 { 00300 const int lastIndex = numSamples - 1; 00301 00302 for (int i = 0; i < lastIndex; ++i) 00303 outputSamples[i] = nextNumerical (shapeState); 00304 00305 outputSamples[lastIndex] = shapeState.currentLevel = shapeState.targetLevel; 00306 } 00307 else 00308 { 00309 for (int i = 0; i < numSamples; ++i) 00310 outputSamples[i] = nextNumerical (shapeState); 00311 } 00312 00313 shapeState.stepsToTarget -= numSamples; 00314 } 00315 00316 template<class ValueType> 00317 static inline void processSine (ShapeState<ValueType>& shapeState, ValueType* const outputSamples, const int numSamples) throw() 00318 { 00319 // const ValueType& zero = Math<ValueType>::get0(); 00320 00321 if (numSamples == shapeState.stepsToTarget) 00322 { 00323 const int lastIndex = numSamples - 1; 00324 00325 for (int i = 0; i < lastIndex; ++i) 00326 outputSamples[i] = nextSine (shapeState); 00327 00328 outputSamples[lastIndex] = shapeState.currentLevel = shapeState.targetLevel; 00329 } 00330 else 00331 { 00332 for (int i = 0; i < numSamples; ++i) 00333 outputSamples[i] = nextSine (shapeState); 00334 } 00335 00336 shapeState.stepsToTarget -= numSamples; 00337 } 00338 00339 private: 00340 ShapeType type; 00341 float curve; 00342 }; 00343 00344 00345 template<class SampleType> 00346 class BreakpointInternal : public SenderInternal< BreakpointBase<SampleType> > 00347 { 00348 public: 00349 typedef BreakpointBase<SampleType> Container; 00350 00351 BreakpointInternal (const SampleType targetLevel, 00352 const double targetTime, 00353 Shape const& shapeToUse, 00354 const int nextGateOn, 00355 const int nextGateOff) throw() 00356 : level (targetLevel), 00357 time (targetTime), 00358 shape (shapeToUse), 00359 nextOn (nextGateOn), 00360 nextOff (nextGateOff) 00361 { 00362 } 00363 00364 SampleType getTargetLevel() const throw() { return this->level; } 00365 double getTargetTime() const throw() { return this->time; } 00366 const Shape& getShape() const throw() { return this->shape; } 00367 int getNextGateOn() const throw() { return this->nextOn; } 00368 int getNextGateOff() const throw() { return this->nextOff; } 00369 00370 private: 00371 SampleType level; 00372 double time; 00373 Shape shape; 00374 int nextOn; 00375 int nextOff; 00376 }; 00377 00378 //------------------------------------------------------------------------------ 00379 00381 template<class SampleType> 00382 class BreakpointBase : public SenderContainer< BreakpointInternal<SampleType> > 00383 { 00384 public: 00385 typedef BreakpointInternal<SampleType> Internal; 00386 typedef SenderContainer<Internal> Base; 00387 typedef WeakPointerContainer<BreakpointBase> Weak; 00388 00389 enum NextPoint 00390 { 00391 This = -2, 00392 Next = -1, 00393 End = INT_MAX 00394 }; 00395 00396 BreakpointBase(const SampleType targetLevel = SampleType (0), 00397 const double targetTime = 0.0, 00398 Shape const& shape = Shape::Linear, 00399 const int nextGateOn = BreakpointBase::Next, 00400 const int nextGateOff = BreakpointBase::Next) throw() 00401 : Base (new Internal (targetLevel, 00402 targetTime, 00403 shape, 00404 nextGateOn, 00405 nextGateOff)) 00406 { 00407 plonk_assert (nextGateOn >= -2); // must be a special code or a real index, >=0 00408 plonk_assert (nextGateOff >= -1); // not the only infinite loop but one of them! 00409 } 00410 00411 explicit BreakpointBase (Internal* internalToUse) throw() 00412 : Base (internalToUse) 00413 { 00414 } 00415 00416 BreakpointBase (BreakpointBase const& copy) throw() 00417 : Base (static_cast<Base const&> (copy)) 00418 { 00419 } 00420 00421 BreakpointBase (Dynamic const& other) throw() 00422 : Base (other.as<BreakpointBase>().getInternal()) 00423 { 00424 } 00425 00427 BreakpointBase& operator= (BreakpointBase const& other) throw() 00428 { 00429 if (this != &other) 00430 this->setInternal (other.getInternal()); 00431 00432 return *this; 00433 } 00434 00438 static BreakpointBase fromWeak (Weak const& weak) throw() 00439 { 00440 return weak.fromWeak(); 00441 } 00442 00443 static const BreakpointBase& getNull() throw() 00444 { 00445 static BreakpointBase null; 00446 return null; 00447 } 00448 00449 inline SampleType getTargetLevel() const throw() { return this->getInternal()->getTargetLevel(); } 00450 inline double getTargetTime() const throw() { return this->getInternal()->getTargetTime(); } 00451 inline const Shape& getShape() const throw() { return this->getInternal()->getShape(); } 00452 inline bool isSustainPoint() const throw() { return this->getInternal()->getNextGateOn() == BreakpointBase::This; } 00453 inline int getNextGateOn() const throw() { return this->getInternal()->getNextGateOn(); } 00454 inline int getNextGateOff() const throw() { return this->getInternal()->getNextGateOff(); } 00455 00456 inline int getNext (const bool gate) const throw() 00457 { 00458 return gate ? this->getNextGateOn() : this->getNextGateOff(); 00459 } 00460 00461 PLONK_OBJECTARROWOPERATOR(BreakpointBase); 00462 00463 }; 00464 00465 00466 //------------------------------------------------------------------------------ 00467 00468 00469 template<class SampleType> 00470 class BreakpointsInternal : public SenderInternal< BreakpointsBase<SampleType> > 00471 { 00472 public: 00473 typedef BreakpointsBase<SampleType> Container; 00474 typedef BreakpointBase<SampleType> BreakpointType; 00475 typedef ObjectArray<BreakpointType> BreakpointArrayType; 00476 00477 typedef NumericalArray<SampleType> LevelsArray; 00478 typedef NumericalArray<double> TimesArray; 00479 typedef ObjectArray<Shape> ShapeArray; 00480 typedef NumericalArray<int> NextArray; 00481 00482 BreakpointsInternal(LevelsArray const& levels, 00483 TimesArray const& times, 00484 ShapeArray const& shapes, 00485 NextArray const& nextGateOns, 00486 NextArray const& nextGateOffs) throw() 00487 : breakpoints (BreakpointArrayType::withSize (times.length())) 00488 { 00489 plonk_assert (levels.length() >= 2); 00490 plonk_assert (times.length() == (levels.length() - 1)); 00491 plonk_assert (((nextGateOns.length() == 0) && (nextGateOffs.length() == 0)) || 00492 ((nextGateOns.length() == (levels.length() - 1))) && ((nextGateOffs.length() == (levels.length() - 1)))); 00493 00494 const SampleType* levelsArray = levels.getArray(); 00495 const double* timesArray = times.getArray(); 00496 const int* nextOnsArray = nextGateOns.getArray(); 00497 const int* nextOffsArray = nextGateOffs.getArray(); 00498 00499 this->startLevel = *levelsArray++; 00500 00501 const int numBreakpoints = times.length(); 00502 00503 if (nextGateOns.length() != 0) 00504 { 00505 for (int i = 0; i < numBreakpoints; ++i) 00506 { 00507 this->breakpoints.put (i, BreakpointType (levelsArray[i], 00508 timesArray[i], 00509 shapes.wrapAt (i), 00510 nextOnsArray[i], 00511 nextOffsArray[i])); 00512 } 00513 } 00514 else 00515 { 00516 for (int i = 0; i < numBreakpoints; ++i) 00517 { 00518 this->breakpoints.put (i, BreakpointType (levelsArray[i], 00519 timesArray[i], 00520 shapes.wrapAt (i))); 00521 } 00522 } 00523 } 00524 00525 ~BreakpointsInternal() 00526 { 00527 } 00528 00529 inline int getNumBreakpoints() const throw() 00530 { 00531 return breakpoints.length(); 00532 } 00533 00534 inline SampleType getStartLevel() const throw() 00535 { 00536 return startLevel; 00537 } 00538 00539 inline const BreakpointArrayType& getBreakpoints() const throw() 00540 { 00541 return breakpoints; 00542 } 00543 00544 inline const Container levelScale (const SampleType amount) const throw() 00545 { 00546 BreakpointsInternal* internal = new BreakpointsInternal(); 00547 00548 internal->startLevel = startLevel * amount; 00549 00550 for (int i = 0; i < breakpoints.length(); ++i) 00551 { 00552 const BreakpointType& point = breakpoints.atUnchecked (i); 00553 internal->breakpoints.add (BreakpointType (point.getTargetLevel() * amount, 00554 point.getTargetTime(), 00555 point.getShape(), 00556 point.getNextGateOn(), 00557 point.getNextGateOff())); 00558 } 00559 00560 return Container (internal); 00561 } 00562 00563 inline const Container timeScale (const SampleType amount) const throw() 00564 { 00565 BreakpointsInternal* internal = new BreakpointsInternal(); 00566 00567 internal->startLevel = startLevel; 00568 00569 for (int i = 0; i < breakpoints.length(); ++i) 00570 { 00571 const BreakpointType& point = breakpoints.atUnchecked (i); 00572 internal->breakpoints.add (BreakpointType (point.getTargetLevel(), 00573 point.getTargetTime() * amount, 00574 point.getShape(), 00575 point.getNextGateOn(), 00576 point.getNextGateOff())); 00577 } 00578 00579 return Container (internal); 00580 } 00581 00582 private: 00583 BreakpointsInternal() throw() 00584 { 00585 } 00586 00587 SampleType startLevel; 00588 BreakpointArrayType breakpoints; 00589 }; 00590 00591 00592 //------------------------------------------------------------------------------ 00593 00595 template<class SampleType> 00596 class BreakpointsBase : public SenderContainer< BreakpointsInternal<SampleType> > 00597 { 00598 public: 00599 typedef BreakpointsInternal<SampleType> Internal; 00600 typedef SenderContainer<Internal> Base; 00601 typedef WeakPointerContainer<BreakpointsBase> Weak; 00602 00603 typedef NumericalArray<SampleType> LevelsArray; 00604 typedef NumericalArray<double> TimesArray; 00605 typedef ObjectArray<Shape> ShapeArray; 00606 typedef NumericalArray<int> NextArray; 00607 00608 typedef SignalBase<SampleType> SignalType; 00609 typedef BreakpointBase<SampleType> BreakpointType; 00610 typedef TypeUtility<SampleType> SampleTypeUtility; 00611 00612 00613 BreakpointsBase (LevelsArray const& levels = LevelsArray (SampleType (0), SampleType (0)), 00614 TimesArray const& times = TimesArray (0.0), 00615 ShapeArray const& shapes = ShapeArray (Shape::Linear), 00616 NextArray const& nextGateOns = NextArray::getNull(), 00617 NextArray const& nextGateOffs = NextArray::getNull()) throw() 00618 : Base (new Internal(levels, times, shapes, nextGateOns, nextGateOffs)) 00619 { 00620 } 00621 00622 explicit BreakpointsBase (Internal* internalToUse) throw() 00623 : Base (internalToUse) 00624 { 00625 } 00626 00627 BreakpointsBase (BreakpointsBase const& copy) throw() 00628 : Base (static_cast<Base const&> (copy)) 00629 { 00630 } 00631 00632 BreakpointsBase (Dynamic const& other) throw() 00633 : Base (other.as<BreakpointsBase>().getInternal()) 00634 { 00635 } 00636 00638 BreakpointsBase& operator= (BreakpointsBase const& other) throw() 00639 { 00640 if (this != &other) 00641 this->setInternal (other.getInternal()); 00642 00643 return *this; 00644 } 00645 00649 static BreakpointsBase fromWeak (Weak const& weak) throw() 00650 { 00651 return weak.fromWeak(); 00652 } 00653 00654 static const BreakpointsBase& getNull() throw() 00655 { 00656 static BreakpointsBase null; 00657 return null; 00658 } 00659 00660 static BreakpointsBase value (const double value, 00661 const double sustainTime) throw() 00662 { 00663 return BreakpointsBase (LevelsArray (value, value), 00664 TimesArray (sustainTime), 00665 ShapeArray (Shape::Linear)); 00666 } 00667 00668 static BreakpointsBase line (const double startLevel, 00669 const double endLevel, 00670 const double duration, 00671 Shape const& shape = Shape::Linear) throw() 00672 { 00673 return BreakpointsBase (LevelsArray (startLevel, endLevel), 00674 TimesArray (duration), 00675 ShapeArray (shape)); 00676 } 00677 00678 static BreakpointsBase lineSustain (const double startLevel, 00679 const double startTime, 00680 const double sustainLevel, 00681 const double endTime, 00682 const double endLevel, 00683 Shape const& shape = Shape::Linear) throw() 00684 { 00685 const int lastPoint = 1; 00686 return BreakpointsBase (LevelsArray (startLevel, sustainLevel, endLevel), 00687 TimesArray (startTime, endTime), 00688 ShapeArray (shape), 00689 NextArray (BreakpointType::This, BreakpointType::End), 00690 NextArray (lastPoint, BreakpointType::End)); 00691 } 00692 00693 static BreakpointsBase linen (const double attackTime, 00694 const double sustainTime, 00695 const double releaseTime, 00696 Shape const& shape = Shape::Linear) throw() 00697 { 00698 const SampleType peak = SampleTypeUtility::getTypePeak(); 00699 return BreakpointsBase (LevelsArray (SampleType (0), peak, peak, SampleType (0)), 00700 TimesArray (attackTime, sustainTime, releaseTime), 00701 ShapeArray (shape)); 00702 } 00703 00704 static BreakpointsBase ahdsr (const double attackTime, 00705 const double holdTime, 00706 const double decayTime, 00707 const SampleType sustainLevel, 00708 const double releaseTime, 00709 Shape const& shape = Shape::Linear) throw() 00710 { 00711 const int lastPoint = 3; 00712 const SampleType peak = SampleTypeUtility::getTypePeak(); 00713 return BreakpointsBase (LevelsArray (SampleType (0), peak, peak, sustainLevel, SampleType (0)), 00714 TimesArray (attackTime, holdTime, decayTime, releaseTime), 00715 ShapeArray (shape), 00716 NextArray (BreakpointType::Next, BreakpointType::Next, BreakpointType::This, BreakpointType::End), 00717 NextArray (lastPoint, lastPoint, lastPoint, BreakpointType::End)); 00718 } 00719 00720 static BreakpointsBase adsr (const double attackTime, 00721 const double decayTime, 00722 const SampleType sustainLevel, 00723 const double releaseTime, 00724 Shape const& shape = Shape::Linear) throw() 00725 { 00726 const int lastPoint = 2; 00727 const SampleType peak = SampleTypeUtility::getTypePeak(); 00728 return BreakpointsBase (LevelsArray (SampleType (0), peak, sustainLevel, SampleType (0)), 00729 TimesArray (attackTime, decayTime, releaseTime), 00730 ShapeArray (shape), 00731 NextArray (BreakpointType::Next, BreakpointType::This, BreakpointType::End), 00732 NextArray (lastPoint, lastPoint, BreakpointType::End)); 00733 } 00734 00735 static BreakpointsBase asr (const double attackTime, 00736 const SampleType sustainLevel, 00737 const double releaseTime, 00738 Shape const& shape = Shape::Linear) throw() 00739 { 00740 const int lastPoint = 1; 00741 return BreakpointsBase (LevelsArray (SampleType (0), sustainLevel, SampleType (0)), 00742 TimesArray (attackTime, releaseTime), 00743 ShapeArray (shape), 00744 NextArray (BreakpointType::This, BreakpointType::End), 00745 NextArray (lastPoint, BreakpointType::End)); 00746 } 00747 00748 // static BreakpointsBase asr (const double attackTime, 00749 // const SampleType sustainLevel, 00750 // const double releaseTime, 00751 // Shape const& shape = Shape::Linear) throw() 00752 // { 00753 // return BreakpointsBase::lineSustain (0.0, attackTime, sustainLevel, releaseTime, 0.0, shape); 00754 // } 00755 00756 static BreakpointsBase steal (const double releaseTime, 00757 Shape const& shape = Shape::Linear) throw() 00758 { 00759 const int lastPoint = 1; 00760 return BreakpointsBase (LevelsArray (SampleType (1), SampleType (1), SampleType (0)), 00761 TimesArray (0.0, releaseTime), 00762 ShapeArray (shape), 00763 NextArray (BreakpointType::This, BreakpointType::End), 00764 NextArray (lastPoint, BreakpointType::End)); 00765 } 00766 00767 inline int getNumBreakpoints() const throw() 00768 { 00769 return this->getInternal()->getNumBreakpoints(); 00770 } 00771 00772 inline SampleType getStartLevel() const throw() 00773 { 00774 return this->getInternal()->getStartLevel(); 00775 } 00776 00777 inline const BreakpointType& atUnchecked (const int index) const throw() 00778 { 00779 return this->getInternal()->getBreakpoints().atUnchecked (index); 00780 } 00781 00782 inline const BreakpointsBase levelScale (const SampleType amount) const throw() 00783 { 00784 return this->getInternal()->levelScale (amount); 00785 } 00786 00787 inline const BreakpointsBase timeScale (const SampleType amount) const throw() 00788 { 00789 return this->getInternal()->timeScale (amount); 00790 } 00791 00792 SampleType lookup (const double time) const throw() 00793 { 00794 (void)time; 00795 plonk_assertfalse; // todo 00796 } 00797 00798 void toSignal (SignalType& signal) throw() 00799 { 00800 (void)signal; 00801 plonk_assertfalse; // todo 00802 } 00803 00804 PLONK_OBJECTARROWOPERATOR(BreakpointsBase); 00805 }; 00806 00807 00808 #endif // PLONK_BREAKPOINTS_H