pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plonk_BreakPoints.h
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
 All Classes Functions Typedefs Enumerations Enumerator Properties