#import <AsympUG.h>
Public Member Functions | |
(MKEnvStatus) | - envelopeStatus |
Returns the status of the most recently accessed MKEnvelope breakpoint. | |
(id) | - setOutput: |
Sets the output patchpoint to aPatchPoint. | |
(id) | - setTargetVal: |
Sets the target to target, which should be between 0.0 and 1.0. | |
(id) | - setCurVal: |
Sets the current value of the AsympUG to value. | |
(id) | - setRate: |
Sets the rate at which the AsympUG approaches its target, where rate is the percentage of the remaining journey that's stepped off at each sample. | |
(id) | - setT60: |
Computes the AsynpUG's rate such that the target is perceptually reached (to within -60dB of the target) in seconds seconds. | |
(id) | - setT48: |
Computes the AsympUG's rate such that the target is perceptually reached (to within -48dB of the target) in seconds seconds. | |
(id) | - preemptEnvelope |
Causes the AsympUG to head for the last breakpoint in its MKEnvelope, using a rate that's computed from the value set through the MKSetPreemptDuration() function (the default preempt duration is 0.006 seconds). | |
(id) | - setEnvelope:yScale:yOffset:xScale:releaseXScale:funcPtr: |
Associates the AsympUG with the given MKEnvelope and arguments. | |
(id) | - resetEnvelope:yScale:yOffset:xScale:releaseXScale:funcPtr:transitionTime: |
This method is similar to the setEnvelope:... method but for this difference: If the AsympUG is running, its current value isn't reset to the new Envelope's first y value; instead, the new Envelope's first breakpoint is ignored and the Asymp's rate is reset such that the second breakpoint of the new MKEnvelope is (virtually) reached within transitionTime seconds. | |
(id) | - useInitialValue: |
Controls how the MKEnvelope is handled when it is "retriggered" (i.e. run is invoked before the preceeding MKEnvelope has finished). | |
(id) | - setYScale:yOffset: |
Resets the values by which the AsympUG scales and offsets its MKEnvelope's y values. | |
(id) | - setReleaseXScale: |
Resets the value by which the release time of the AsympUG's MKEnvelope is scaled. | |
(id) | - envelope |
Returns the MKEnvelope that's associated with the AsympUG, or nil if none. | |
(id) | - runSelf |
You never send this message. | |
(id) | - idleSelf |
You never send this message. | |
(double) | - finishSelf |
You never invoke this method; it's invoked automatically when the AsympUG receives the finish message. | |
(id) | - abortEnvelope |
Disassociates the AsympUG from its MKEnvelope. | |
(id) | - setConstant: |
Aborts any running MKEnvelope and sets the AsympUG to produce val as a constant value. | |
Static Public Member Functions | |
(BOOL) | + shouldOptimize: |
Specifies that all arguments are to be optimized if possible except the state variable. |
AsympUG is an exponential (asymptotic) MKEnvelope handler that plays a MusicKit MKEnvelope on the DSP. It is very similar to AsympenvUG and has almost the same Objective C protocol. However, unlike AsympenvUG, which loads the entire MKEnvelope into DSP memory, AsympUG feeds the MKEnvelope to the DSP one segment at a time. This means AsympUG is more well-suited to very long Envelopes that would not fit in DSP memory. For example, an entire piece may be specified as one long MKEnvelope. AsympUG also uses less DSP code than AsympenvUG. However, AsympUG is not well-suited to handling MKEnvelopes in interactive real-time applications, such as playing a MIDI keyboard and hearing sound immediately. For such applications, it is better to use AsympenvUG.
AsympUG objects are normally used to provide dynamic scaling of a musical attribute. To this end, the output of an AsympUG is typically connected to the frequency or amplitude input of an OscgafiUG object or used as input to an InterpUG, Mul2UG, ScaleUG, etc. Although typically used to convey MKEnvelopes, AsympUG may also be used as a simple exponential ramper, without an explicit MKEnvelope object. Methods are provided that let you set the rate directly, or as a time limit (referred to as “T60”) that defines when the target will have been perceptually reached.
For each MKEnvelope segment, AsympUG creates an exponential signal that approaches a limit (the “target”) at a particular rate, where the rate expresses the precentage of the remaining journey that's taken with each step:
output = previousOutput + (rate * (target - previousOutput)) previousOutput = output
For example, if the rate is 0.1 and the target is 1.0, the samples generated by the AsympUG are
0.1, 0.19, 0.271, 0.343, 0.409, 0.4685, ...
Exponential envelopes have the advantage of being "self-limiting". That is, they seek their targets from any starting point. This allows for efficient implementation of long connected MKEnvelope "phrases", one of the primary advantages of the MusicKit's MKNote representation. In addition, if, for some reason, the host processor gets a little bit behind, due to time-sharing, the envelope will not continue unbounded toward disaster.
MKEnvelope data is mapped onto the exponential representation as follows:
The MKEnvelope's yArray[n] is the target, considered to be in the infinite future.The MKEnvelope's xArray[n] is the time of the right-hand side of the segment (i.e. the time to interrupt the trajectory toward yArray[n]). The MKEnvelope's smoothingArra[n] is the smoothing constant to get to yArray[n]. If smoothingArra[n] is 0, the point is reached immediately. If smoothingArra[n] is 1.0, the point is reached, within about -48dB at the time of the next update. If smoothingArra[n] is larger, the point is not reached within -48dB by the time of the next update. A value of smoothingArra[n] of infinity will cause the envelope to never change value. The first point, xArray[0], is assumed to be the right-hand side of the non-existant first segment. yArray[0] is the initial point (which may or may not be used, depending on the value of the instance variable useInitialvalue (see below)). smoothingArra[0] is ignored.
The envelope has a "stick point". When the envelope handler reaches the stick point, it does not proceed to the next point until it receives the -finish message. If there is no stick point, the -finish message is ignored. If the envelope handler has not yet reached the stick point when the -finish message is received, the envelope handler proceeds to the first point after the stick point and continues from there. Keep in mind that while AsympUG uses the clockConductor (see Conductor Class Description) for timing of envelope breakpoint values, -finish is sent based on the arrival of a noteOff to the MKSynthPatch, which is (usually) managed by another MKConductor.
MusicKit MKEnvelopes are usually associated with a set of parameters, such as attackTime, releaseTime, etc. The C function MKUpdateAsymp() is provided to conveniently manage setting the AsympUG's attributes according to a given MKEnvelope and a set of Note parameters. By using MKUpdateAsymp(), you need only set the AsympUG's output patchpoint; all other methods are invoked for you. For more information, see the Class Description for the MKEnvelope class.
A few other points to keep in mind:
AsympUGa
a output
- (MKEnvStatus) envelopeStatus |
Returns the status of the most recently accessed MKEnvelope breakpoint.
Note that the DSP may not yet have reached that point. For example, if the stickpoint's target was just set, envelopeStatus is MK_stickPoint, even though the DSP is just beginning its exponential approach to the stickpoint. The value returned by envelopeStatus is either MK_stickPoint, MK_lastPoint, or MK_noEnvError. If the AsympUG's MKEnvelope hasn't been set, MK_noMorePoints is returned.
- (id) setOutput: | (id) | aPatchPoint |
Sets the output patchpoint to aPatchPoint.
aPatchPoint | is an id. |
- (id) setTargetVal: | (double) | target |
Sets the target to target, which should be between 0.0 and 1.0.
The new target is simply inserted, overriding the current target. If the object is already processing an envelope, that envelope is not interrupted.
target | is a double. |
- (id) setCurVal: | (double) | value |
Sets the current value of the AsympUG to value.
The new value overrides the previous sample as shown in the computation in the class description above. If the object is already processing an envelope, that envelope is not interrupted.
value | is a double. |
- (id) setRate: | (double) | rate |
Sets the rate at which the AsympUG approaches its target, where rate is the percentage of the remaining journey that's stepped off at each sample.
The value of rate, which should be between 0.0 and 0.125. (It should be between 0.0 and 1.0, but for historical reasons the outer limit stands at 0.125. In any case, a rate of 0.125 means that the target is virtually reached in less than two ticks, which is quite fast). More precisely, this method sets the rate of the exponential. (1-e^T/tau), where T is sampling period and tau is the time constant.If the AsympUG is already processing an MKEnvelope, the new rate is simply inserted, overriding the current value, and the MKEnvelope proceeds otherwise unaffected.
rate | is a double. |
- (id) setT60: | (double) | seconds |
Computes the AsynpUG's rate such that the target is perceptually reached (to within -60dB of the target) in seconds seconds.
seconds | is a double. |
- (id) setT48: | (double) | seconds |
Computes the AsympUG's rate such that the target is perceptually reached (to within -48dB of the target) in seconds seconds.
Same as [self setRate: 5.52 / (seconds * srate)].
seconds | is a double. |
- (id) preemptEnvelope |
Causes the AsympUG to head for the last breakpoint in its MKEnvelope, using a rate that's computed from the value set through the MKSetPreemptDuration() function (the default preempt duration is 0.006 seconds).
This method is invoked automatically by a MKSynthInstrument object when it preempts a MKSynthPatch that contains AsympUG objects.
- (id) setEnvelope: | (id) | anEnvelope | ||
yScale: | (double) | yScaleValue | ||
yOffset: | (double) | yOffsetValue | ||
xScale: | (double) | xScaleValue | ||
releaseXScale: | (double) | releaseXScaleValue | ||
Associates the AsympUG with the given MKEnvelope and arguments.
When the AsympUG is run, it automatically schedules the breakpoints from its MKEnvelope to be fed to itself through message requests with the clockConductor. If this method is invoked while the AsympUG is running, the object's current value is immediately set to the (scaled and offset) y value of the first breakpoint in the new MKEnvelope. When continuity is desired with the previous invocation, use the resetEnvelope:... method instead.
The yScaleValue and yOffsetValue arguments scale and offset the AsympUG target values as each breakpoint is reached; xScaleValue and releaseXScaleValue modify the rate before and after the MKEnvelope's stickpoint is reached, respectively.
The yScaleFunction argument is a pointer to an optional function that performs additional, possibly dynamic, target scaling. The fuction takes two arguments, a double that gives the AsympUG's current value, and the object's id. The function is called once for each breakpoint.
Typically, you call the MKUpdateAsymp() function rather than invoking this method. The function provides a slightly easier interface to AsympUG management in the context of a MKSynthPatch.
anEnvelope | is an id. | |
yScaleValue | is a double. | |
yOffsetValue | is a double. | |
xScaleValue | is a double. | |
releaseXScaleValue | is a double. | |
yScaleFunction | is a pointer to a function returning a double. |
- (id) resetEnvelope: | (id) | anEnvelope | ||
yScale: | (double) | yScaleValue | ||
yOffset: | (double) | yOffsetValue | ||
xScale: | (double) | xScaleValue | ||
releaseXScale: | (double) | releaseXScaleValue | ||
This method is similar to the setEnvelope:... method but for this difference: If the AsympUG is running, its current value isn't reset to the new Envelope's first y value; instead, the new Envelope's first breakpoint is ignored and the Asymp's rate is reset such that the second breakpoint of the new MKEnvelope is (virtually) reached within transitionTime seconds.
This affords are more graceful transition into the new MKEnvelope. If transitionTime (as with any of the other double values) is MK_NODVAL, it is ignored. As with the setEnvelope:... method, you typically call the MKUpdateAsymp() function rather than invoke this method.
anEnvelope | is an id. | |
yScaleValue | is a double. | |
yOffsetValue | is a double. | |
xScaleValue | is a double. | |
releaseXScaleValue | is a double. | |
yScaleFunction | is a pointer to a function returning a double. | |
transitionTime | is a double. |
- (id) useInitialValue: | (BOOL) | yesOrNo |
Controls how the MKEnvelope is handled when it is "retriggered" (i.e. run is invoked before the preceeding MKEnvelope has finished).
If yesOrNo, the first value of the MKEnvelope is set as the AsympUG's first output. Otherwise, the AsympUG continues from whatever its current value happens to be to the second point of the MKEnvelope. This method is rarely needed, since the same functionality is provided by resetEnvelope:yScale:yOffset:xScale:releaseXScale:funcPtr:transitionTime:. It is included as an optimization, when it is known that all parameters are the same.
yesOrNo | is a BOOL. |
- (id) setYScale: | (double) | yScaleValue | ||
yOffset: | (double) | yOffsetValue | ||
Resets the values by which the AsympUG scales and offsets its MKEnvelope's y values.
If the object is running, its current value is appropriately modified.
yScaleValue | is a double. | |
yOffsetValue | is a double. |
- (id) setReleaseXScale: | (double) | releaseXScaleValue |
Resets the value by which the release time of the AsympUG's MKEnvelope is scaled.
This only has an affect on subsequent breakpoints - you can't, for example, extend the life of an AsympUG by increasing its release scale after the object has read (and is heading for) its last breakpoint.
releaseXScaleValue | is a double. |
- (id) envelope |
- (id) runSelf |
You never send this message.
It's invoked by sending the run message to the object. Starts the MKEnvelope, if any, on its way.
Reimplemented from MKUnitGenerator.
- (id) idleSelf |
You never send this message.
It's invoked by sending the idlemessage to the object. Sets the output patchpoint to sink, thus ensuring that the object does not produce any output. Note that you must send setOutput: and run again to use the MKUnitGenerator after sending idle.
Reimplemented from MKUnitGenerator.
- (double) finishSelf |
You never invoke this method; it's invoked automatically when the AsympUG receives the finish message.
If the object has yet to see or is waiting at its MKEnvelope's stickpoint, this causes it to head for the first breakpoint after the stickpoint, and then on the end of the MKEnvelope. If the AsympUG's MKEnvelope contains no stickpoint, this method has no effect. Returns the time in seconds until the MKEnvelope is expected to finish, plus a small grace time given by MKGetPreemptDuration(). This time may be changed by calling MKSetPreemptDuration().
Reimplemented from MKUnitGenerator.
+ (BOOL) shouldOptimize: | (unsigned) | arg |
Specifies that all arguments are to be optimized if possible except the state variable.
arg | is an unsigned. |
Reimplemented from MKUnitGenerator.
- (id) abortEnvelope |
Disassociates the AsympUG from its MKEnvelope.
If the AsympUG is running, it stops reading breakpoints. It continues heading for its current target.
- (id) setConstant: | (double) | aVal |
Aborts any running MKEnvelope and sets the AsympUG to produce val as a constant value.
Equivalent to invoking abortEnvelope, followed by setTarget: val, followed by setCurVal: val.
aVal | is a double. |