Data AcQuisition And Real-Time AnalysisScope - Spectrum - Spectrogram - Signal Generator
Software for Windows
Science with your Sound Card!
Contact us about
MIDI Changes Script Oscillators
Changes: $n=Sf, $n(min,max)
MIDI Changes scripts support up to 24 oscillators, whose outputs can be used in place of most values. (Exceptions are Voice number, Buffer number, and the Oscillator number itself, which must have explicit constant values or letters.)
Oscillators are typically used for slowly changing variables. In the days of classical hardware synthesizers, these would have been called "LFOs" (Low Frequency Oscillators). Changes script oscillators can go from less than 0.0001 Hz to 8000 Hz.
Oscillators can have different waveforms: Sine, Triangle, Ramp Up, Ramp Down, Square, or Pulse. The Pulse duty cycle is adjustable.
Oscillators can also have a specified phase, allowing two oscillators to track at the same frequency while maintaining a fixed phase relationship, such as sine and cosine.
Oscillators are always used with limits in parentheses. For example, assuming you have previously set the operating frequency and waveform of Oscillator 1, you can use it to set Tempo to vary between 200 and 300 BPM like this:
The order of the limits does not matter. In general, either or both may be signed. The output of the oscillator will be further limited by the command it is used with, in this case to 30 to 6000 BPM.
You can use the same oscillator in different places, with different limits. This is analogous to having a master oscillator that has multiple outputs with independent level controls.
The above reads the current value of the specified oscillator. See Reading Oscillator Settings, below, to read the oscillator frequency and other parameters.
Note that Oscillator variables described below (frequency, phase, and Pulse On percent) can accept unsigned fixed-point fractions. All other Changes script variables are integers, except lowercase User Variables Ua-Uz.
Oscillators are identified by numbers 1-8, letters A-H, and letters a-h. These three groups correspond to modes of operation: 1-8 are "normal" oscillators whose values appear to change continuously in real time. Oscillators A-H operate on "beat time", and a-h operate on "uses".
Real-time oscillators 1-8 are the easiest to understand: Whenever one is used in an executing Changes script, the returned value is just what one would expect if it was a stand-alone benchtop device... it keeps running at its own rate even when it is not being used.
Real-time oscillators are set with the desired frequency in hertz (cycles per second). For example, to set Oscillator 1 to a Sine wave at 1.2345 Hz, use $1=S1.2345. (See below for more about setting waveform types.)
Beat-time oscillators A-H are set in units of cycles per 1000 beats instead of cycles per second. This makes them dependent upon the Tempo setting. To find the value to set for an equivalent cycles per second, multiply by the Tempo in msec. For example, to set Oscillator A to an effective 1 cycle per second Sine when Tempo msec is 200, use $A=200. Sine is assumed by default here; an explicit assignment would be $A=S200... see below.
(Note that you can use the Tempo controls to convert between BPM and msec, by entering one and reading the other.)
Beat-time oscillators allow you to maintain a specified internal cycle in a song, even when the Tempo is changing. For example, you may want to gradually increase and decrease the Note Range, so that it goes through exactly one cycle during a particular Velocity Pattern. If you use a beat-time oscillator for this, it will maintain the same alignment with the pattern even if the Tempo is changed, either statically via the Tempo controls or dynamically via the TB or T commands.
Use-based oscillators a-h are set in units of cycles per 1000 uses. This oscillator type advances only when read via some Changes command.
Use-based oscillators are ideal for Buffer Fill operations using the Bf command, or Buffer Add Value using the Ba command. For example, the command Bf21.0=($a(48,72),8) would fill Voice 2, buffer 1 starting from the 0th position, with 8 points from the oscillator $a output.
If a real-time or beat-based oscillator had been used here, its output would only change on the beat and would thus be constant during the fill process, so all buffer positions would be filled with the same value.
Normally, the oscillator number is given as an immediate value after the $, such as the 1 in $1=2.345 or in TB=$1(200,300). But if you want to select the oscillator under Changes script control, you can replace the number with an expression enclosed in carets, such as $<UA+UB>=2.345 or TB=$<UA*2-UC>(200,300).
In such cases, the expression must result in a value in the range of 1-8 for real-time oscillators, 9-16 (instead of A-H) for beat-time, or 17-24 (instead of a-h) for use-based.
In the simplest case, oscillators are set via $n=Sf, where n is the Oscillator number, S is the waveform (S = Sine here), and f is the frequency.
S = Sine (default) T = Triangle R = Ramp Up r = Ramp Down Q = sQuare P = Pulse
Sine is the default, which means you can omit the S. This can be convenient if you only use Sine, but if you use other waveforms as well you can include the explicit S to make it clear.
The default Pulse duty cycle is 25% On. You can specify another On percentage by putting it in parentheses right after the P. For example $1=P(10.5)1.234 sets a Pulse with 10.5% On time and 1.234 Hz frequency.
The On portion of the Pulse is assumed to start at the beginning of the cycle. You can adjust that via the oscillator phase.
By default, all oscillators start at 0 degrees. For a Sine oscillator, this corresponds to midway between the limits given in parentheses when you use it.
But suppose you want to use the oscillator to control a variable that should start at one limit or the other. For example, if Tempo is set to 200 BPM and you use TB=$1(200,300) right after setting the oscillator, Tempo will jump to 250 BPM.
To get it to start at the minimum, you must set the phase to 270 degrees, the bottom of the negative peak of a Sine. For all waveforms except Pulse, phase is given right after the waveform letter as a lowercase p followed by the phase in parentheses, then the frequency. For example, to set Oscillator 2 to a 0.5 Hz Sine at 270 degrees, you would use $2=Sp(270)0.5.
For Pulse waveforms, the phase must come after the On percentage, if any. For example, $2=P(10)p(180)0.5 would set Oscillator 2 to a 0.5 Hz Pulse with a 10% On time, at 180 degrees. That means the On phase will start halfway through the cycle.
You can set two (or more) oscillators to have the same frequency but different phases. This can allow synchronized complementary actions, such as increasing the +/-Note value for one voice while decreasing it for another.
(Alternatively, you could also produce the effect of 180 degree phase difference by using a single oscillator, with subtraction to invert the polarity. For example, you could use n1=$1(0,12) and n2=12-$1(0,12).)
Once an oscillator has been set, you may subsequently change its frequency without changing the phase. This allows frequency modulation or sweeps, but note that for smooth operation you must update the oscillator often, typically once per beat.
You can also change the phase without changing the frequency. You must always set a frequency value, but if you set the same frequency with a new phase, only the phase will change. Note that this will usually cause a discontinuity in the oscillator output, unless the output at the new phase happens to be near the old value.
For example, if the output is at the positive peak of a Sine and you change the phase by 180 degrees, it will jump to the negative peak. On the other hand, if the output is initially at zero, it will still be at zero after a 180 degree change (though it will be moving in the opposite direction).
Besides obtaining the current value of an oscillator as in the TB=$1(200,300) example given earlier, you can also read other parameters like the oscillator frequency, starting phase, Pulse duty cycle, or waveform.
oLf=$1 displays the frequency of real-time oscillator 1. (oLf shows this with the full fixed-point fraction.) You might want to know the frequency if you set it with an expression that used random variables, Mouse Position, or current MIDI control values that are not known ahead of time.
Similarly, oLf=$1p shows the starting phase of oscillator 1.
oLf=$1P shows the Pulse duty cycle of oscillator 1, in percent, if it a Pulse waveform type. Otherwise, it shows zero.
oL=$1t shows the oscillator waveform as an integer between 0 and 5:
0 = S = Sine (default) 1 = T = Triangle 2 = R = Ramp Up 3 = r = Ramp Down 4 = Q = sQuare 5 = P = Pulse
The above examples used the Output Display command, but you can use oscillator values in expressions just as you would any variable. For example, $2=$1*2/3 sets oscillator 2 to 2/3 of the frequency of oscillator 1.
You need to set an oscillator before you use it. All oscillators that the script will use would typically be set at the start of the script. The remainder of the script would then be placed in an infinite loop. Without that loop, the entire script would be repeated over and over, including resetting all the oscillators at the start of each pass.
That's not necessarily a problem if none of the oscillators have an explicit phase set, and if all use constant frequencies; setting the same frequency without setting the phase has no effect. However, if there is a phase setting it would mean that each pass through the script would start at that phase. If the prior pass through the script ended at a different phase, there could be a discontinuity when the phase is reset. That may be what you want, but if not you should use the infinite loop trick.
You can use an oscillator, or a sum of oscillators, to produce a "semi-random" sequence of values. Consider that if you set a real-time oscillator frequency to a value that is near (but not equal to) a multiple of the Tempo frequency, it will produce a slowly varying series of values at the difference rate. But as you set the frequency farther from an integer multiple of the Tempo, the sequence will jump around more since the oscillator output travels farther between beats. This can often seem random at first, but it actually repeats at the lowest common divisor.
Questions? Comments? Contact us!We respond to ALL inquiries, typically within 24 hrs.
Over 35 Years of Innovative Instrumentation
© Copyright 2007 - 2021 by Interstellar Research
All rights reserved