================= Rates and Domains ================= .. highlight:: stride ``AudioRate`` is the sampling rate value of the ``AudioDomain`` domain. ``ControlRate`` is the sampling rate value of the ``ControlDomain`` domain. ``AudioDomain`` abstracts the audioCallback () and ``ControlDomain`` abstracts the controlCallbacK (). For the following examples ``ControlIn`` is a single block and not a block bundle. The following is the declaration of the ``SinOsc ()`` module, which will be used in the following sections. The C++ code shown is informal, simply used to convey the concepts in the examples. :: module SinOsc { input: none output: Output propertyName: 'frequency' propertyDirection: in propertyBlock: signal Frequency { default: 440. rate: none domain: GetDomain ( port: 'frequency' ) } internalBlock: [ signal Output { default: 0. rate: streamRate domain: streamDomain }, signal Phase { default: 0. rate: none domain: streamDomain }, signal PhaseIncrement { default: 0. rate: none domain: GetDomain ( port: 'frequency' ) } ] streams: [ 2.0 * M_PI * Frequency / streamRate >> PhaseIncremet; Phase >> Sin() >> Output; Phase + PhaseIncremet >> Phase; ] } ---- A beginner user would type the following code and it would produce the desired effect. However, this code is far from optimized since all computations are being performed at ``AudioRate``. :: ControlIn >> Map ( minimum: 55. maximum: 880. ) >> FrequencyValue; SinOsc ( frequency: FrequencyValue ) >> AudioOut; Since ``FrequencyValue`` was not explicityly declared, it gets declared by the backend as a ``signal`` block with default values. :: signal FrequencyValue { default: 0.0 rate: AudioRate domain: AudioDomain } .. highlight:: cpp Code produced by a backend could be:: AtomicFloat ControlValue = 0.0; void controlCallbacK ( float input ) { ControlValue = input; } void audioCallbacK ( float &output ) { static float Phase = 0.0; static float FrequencyValue = 0.0; static float PhaseIncrement = 0.0; FrequencyValue = Map ( ControlValue, 0., 1., 55., 880. ); PhaseIncrement = 2 * M_PI * FrequencyValue / AudioRate; output = Sin ( Phase ); Phase += PhaseIncrement; } ---- .. highlight:: stride The first improvement the user could do is to explicitly declare ``FrequencyValue`` and change its ``rate``. This will reduce the number of computatiosn performed to calculate the phase incremet of the sine oscillator. If the chosen rate is less than ``ControlRate``, which is the rate of ``ControlIn``, then ``ControlIn`` will be downsampled (The signal will be aliased). :: signal FrequencyValue { default: 0.0 rate: 1024. domain: AudioDomain } ControlIn >> Map ( minimum: 55. maximum: 880. ) >> FrequencyValue; SinOsc ( frequency: FrequencyValue ) >> AudioOut; .. highlight:: cpp Code produced by a backend could be:: AtomicFloat ControlValue = 0.0; Timer timer ( 1024. / AudioRate ); void controlCallbacK ( float input ) { ControlValue = input; } void audioCallbacK ( float &output ) { static float Phase = 0.0; static float FrequencyValue = 0.0; static float PhaseIncrement = 0.0; if ( timer () ) { FrequencyValue = Map ( ControlValue, 0., 1., 55., 880. ); PhaseIncrement = 2 * M_PI * FrequencyValue / AudioRate; } output = Sin ( Phase ); Phase += PhaseIncrement; } ---- .. highlight:: stride The first change one needs to do to improve performace is to add an ``OnChange ()`` module after ``ControlIn``. However, this change alone is not sufficient since it actually adds computation. :: signal FrequencyValue { default: 0.0 rate: 1024. domain: AudioDomain } ControlIn >> OnChange () >> Map ( minimum: 55. maximum: 880. ) >> FrequencyValue; SinOsc ( frequency: FrequencyValue ) >> AudioOut; .. highlight:: cpp Code produced by a backend could be:: AtomicFloat ControlValue = 0.0; Timer timer ( 1024. / AudioRate ); void controlCallbacK ( float input ) { ControlValue = input; } void audioCallbacK ( float &output ) { static float Phase = 0.0; static float FrequencyValue = 0.0; static float PhaseIncrement = 0.0; static float PreviousValue = 0.0; if (ControlValue != PreviousValue) { PreviousValue = ControlValue; } if ( timer () ) { FrequencyValue = Map ( PreviousValue, 0., 1., 55., 880. ); PhaseIncrement = 2 * M_PI * FrequencyValue / AudioRate; } output = Sin ( Phase ); Phase += PhaseIncrement; } ---- .. highlight:: stride To achieve the desired improvement ``FrequencyValue`` should be set to run in asynchronous mode by changing its ``rate`` to ``none``. :: signal FrequencyValue { default: 0.0 rate: none domain: AudioDomain } ControlIn >> OnChange () >> Map ( minimum: 55. maximum: 880. ) >> FrequencyValue; SinOsc ( frequency: FrequencyValue ) >> AudioOut; .. highlight:: cpp Code produced by a backend could be:: AtomicFloat ControlValue = 0.0; void controlCallbacK ( float input ) { ControlValue = input; } void audioCallbacK ( float &output ) { static float Phase = 0.0; static float FrequencyValue = 0.0; static float PhaseIncrement = 0.0; static float PreviousValue = 0.0; if ( ControlValue != PreviousValue ) { FrequencyValue = Map ( ControlValue, 0., 1., 55., 880. ); PhaseIncrement = 2 * M_PI * FrequencyValue / AudioRate; PreviousValue = ControlValue; } output = Sin ( Phase ); Phase += PhaseIncrement; } ---- .. highlight:: stride The user also has a choice of moving computations from one domain to the other. That is, computations can be moved from one thread to another. By changing the ``domain`` of ``FrequencyValue`` from ``AudioDomain`` to ``ControlDomain``, the phase increment computation will be moved from audioCallback () to controlCallback (). :: signal FrequencyValue { default: 0.0 rate: none domain: ControlDomain } ControlIn >> OnChange () >> Map ( minimum: 55. maximum: 880. ) >> FrequencyValue; SinOsc ( frequency: FrequencyValue ) >> AudioOut; .. highlight:: cpp Code produced by a backend could be:: AtomicFloat ControlValue = 0.0; void controlCallbacK ( float input ) { static float FrequencyValue = 0.0; static float PhaseIncrement = 0.0; static float PreviousValue = 0.0; if ( input != PreviousValue ) { FrequencyValue = Map ( input, 0., 1., 55., 880. ); ControlValue = 2 * M_PI * FrequencyValue / AudioRate; PreviousValue = input; } } void audioCallbacK ( float &output ) { static float Phase = 0.0; output = Sin ( Phase ); Phase += ControlValue; }