#import <AsympenvUG.h>
Public Member Functions | |
(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 AsympenvUG to value. | |
(id) | - setRate: |
Sets the rate at which the AsympenvUG approaches its target, where rate is the percentage of the remaining journey that's stepped off at each sample. | |
(id) | - setT60: |
Computes the AsympUG's rate such that the target is perceptually reached (to within -60dB of the target) in seconds seconds. | |
(id) | - preemptEnvelope |
Causes the AsympenvUG 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 AsympenvUG 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 AsympenvUG is running, its current value isn't reset to the new MKEnvelope's first y value; instead, the new MKEnvelope's first breakpoint is ignored and the Asymp's rate is reset such that it proceeds toward the second breakpoint. | |
(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: |
Has no effect. | |
(id) | - setReleaseXScale: |
Has no effect. | |
(id) | - envelope |
Returns the MKEnvelope that's associated with the AsympenvUG, 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 AsympenvUG receives the finish message. | |
(id) | - abortEnvelope |
Disassociates the AsympenvUG from its MKEnvelope. | |
(id) | - setConstant: |
Aborts any running MKEnvelope and sets the AsympenvUG to produce val as a constant value. | |
(void) | - MKUpdateAsymp |
Apply an Envelope on the DSP. | |
Static Public Member Functions | |
(BOOL) | + shouldOptimize: |
Specifies that all arguments are to be optimized if possible except the state variable. |
AsympenvUG is an MKEnvelope handler that plays a MusicKit MKEnvelope on the DSP. It is very similar to AsympUG and has almost the same Objective C protocol. However, unlike AsympUG, which feeds the MKEnvelope to the DSP one segment at a time, AsympenvUG loads the entire MKEnvelope (actually, tables derived from the MKEnvelope data) into DSP memory. This means AsympenvUG is more well-suited to critical interactive real-time applications, such as playing a MIDI keyboard and hearing sound immediately. It also means that there is a limit to the length of the envelopes it can handle, since there is a limited amount of DSP memory. In practice, envelopes are not usually very long, so this restriction is usually not a problem. In short, it is usually best to use AsympenvUG if critical interactive real-time is a concern, but AsympUG is better for situations with very long MKEnvelopes or where real-time response is not an issue.
AsympenvUG objects are normally used to provide dynamic scaling of a musical attribute. To this end, the output of an AsympenvUG 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 Envelopes, 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, AsympenvUG 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.
MusicKit MKEnvelopes are usually associated with a set of parameters, such as attackTime, releaseTime, etc. The C function MKUpdateAsymp (AsympenvUG) is provided to conveniently manage setting the AsympUG's attributes according to a given MKEnvelope and a set of MKNote parameters. By using MKUpdateAsymp (AsympenvUG), you need only set the AsympenvUG's output patchpoint; all other methods are invoked for you. For more information, see the Class Description for the MKEnvelope class.
As with AsympUG, you should not change the contents of a MusicKit MKEnvelope object while an AsympenvUG is using it. Furthermore, MKEnvelope data is cached on the DSP and referenced using the MKEnvelope object id for speed and efficiency. This has the advantage of allowing several AsympenvUGs to share MKEnvelope data and avoids wasting DSP memory. However, this also implies that if you change the data in an MKEnvelope object, these changes may not take effect, because the MusicKit continues to use the old representation. Therefore, if you do change an MKEnvelope's data, you should send the message +envelopeHasChanged:, passing the MKEnvelope object as the argument. Also, you should not free any MKEnvelope objects that have been used in a MusicKit performance until the MKOrchestra has been closed. Otherwise, a re-used id may cause the AsympenvUG to use an incorrect cached MKEnvelope.
There are a few other differences between AsympUG and AsympenvUG:
AsympenvUGa a output
- (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 AsympenvUG 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 AsympenvUG 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 AsympenvUG 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 AsympUG's rate such that the target is perceptually reached (to within -60dB of the target) in seconds seconds.
seconds | is a double. |
- (id) preemptEnvelope |
Causes the AsympenvUG 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 AsympenvUG objects.
- (id) setEnvelope: | (id) | anEnvelope | ||
yScale: | (double) | yScaleValue | ||
yOffset: | (double) | yOffsetValue | ||
xScale: | (double) | xScaleValue | ||
releaseXScale: | (double) | releaseXScaleValue | ||
Associates the AsympenvUG with the given MKEnvelope and arguments.
When the AsympenvUG 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 AsympenvUG 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 AsympenvUG 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 AsympenvUG'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 AsympenvUG 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 (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 AsympenvUG is running, its current value isn't reset to the new MKEnvelope's first y value; instead, the new MKEnvelope's first breakpoint is ignored and the Asymp's rate is reset such that it proceeds toward the second breakpoint.
This affords are more graceful transition into the new MKEnvelope. transitionTimeis currently 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).
yesOrNo | is a BOOL. |
- (id) setYScale: | (double) | yScaleValue | ||
yOffset: | (double) | yOffsetValue | ||
Has no effect.
Implemented for compatibility with AsympUG.
yScaleValue | is a double. | |
yOffsetValue | is a double. |
- (id) setReleaseXScale: | (double) | releaseXScaleValue |
Has no effect.
Implemented for compatability with AsympUG.
releaseXScaleValue | is a double. |
- (id) envelope |
Returns the MKEnvelope that's associated with the AsympenvUG, or nil if none.
- (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 AsympenvUG receives the finish message.
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 AsympenvUG from its MKEnvelope.
The MKEnvelope sticks on its current value.
- (id) setConstant: | (double) | val |
Aborts any running MKEnvelope and sets the AsympenvUG to produce val as a constant value.
Equivalent to invoking abortEnvelope, followed by setTarget:val, followed by setCurVal:val.
val | is a double. |
- (void) MKUpdateAsymp | (id) | asymp | ||
(id) | envelope | |||
(double) | valueAt0 | |||
(double) | valueAt1 | |||
(double) | attackDur | |||
(double) | releaseDur | |||
(double) | portamentoTime | |||
(MKPhraseStatus) | status | |||
Apply an Envelope on the DSP.
This is a fairly complicated function that, simply put, does the “right thing” in applying an MKEnvelope object to a DSP-synthesized musical attribute during a Music Kit performance. It's designed to be called as part of the implementation of a MKSynthPatch subclass.
The asymp argument is an AsympUG object that will handle the MKEnvelope on the DSP; envelope is the MKEnvelope object itself. The arguments valueAt0, valueAt1, attackDur, and releaseDur scale and stretch the MKEnvelope; their values are expected to be taken from an associated group of MKNote parameters. For example, to apply an MKEnvelope to the frequency of a synthesized MKNote, the values of these arguments would be retrieved as follows:
MKEnvelope *envelope = [aNote parAsEnvelope:MK_freqEnv];
double valueAt0 = [aNote parAsDouble:MK_freq0];
double valueAt1 = [aNote parAsDouble:MK_freq1];
double attackDur = [aNote parAsDouble:MK_freqAtt];
double releaseDur = [aNote parAsDouble:MK_freqRel];
The portamentoTime argument is taken as the MKNote's MK_portamentoTime value. As the name implies, it sets the portamento or “slur” between MKNotes and is only applied if the MKNote to which the MKEnvelope belongs is a noteOn that's interrupting an existing MKNote. If the note is a MKNoteUpdate, the value is changed abruptly.
The final argument, status, is used to distinguish the state of the MKSynthPatch at the time that the envelope is applied. You retrieve the phrase status through MKSynthPatch's phraseStatus method. The use of portamento, for example, is determined by the value of this argument.
The asymp and status arguments are essential; the parameter-valued arguments aren't. The function tries to be intelligent with regard to missing parameter-valued arguments; if, for example, envelope is nil, the value of valueAt1 is applied as a constant. .
MKUpdateAsymp handles all the MKEnvelope breakpoint scheduling - keep in mind that the breakpoint data in an MKEnvelope object isn't transferred to the DSP as a unit but, instead, the breakpoints are fed to the DSP through message requests scheduled with a MKConductor. The function always schedules MKEnvelope breakpoint messages with the clockConductor.
asymp | is a AsympUG instance. | |
envelope | is an MKEnvelope instance. | |
valueAt0 | is a double. | |
valueAt1 | is a double. | |
attackDur | is a double. | |
releaseDur | is a double. | |
portamentoTime | is a double. | |
status | is a MKPhraseStatus. |