Created
November 19, 2023 07:22
-
-
Save marksweiss/5a0dfffe072d1e1a8f162bce3d4780cd to your computer and use it in GitHub Desktop.
Core APIs, documentation and helper functions for LogicProX MIDI scripting
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Define NeedsTimingInfo as true at the global scope to enable GetTimingInfo() | |
var NeedsTimingInfo = true; | |
/////////////////////// | |
// ProcessMIDI Functions | |
// NOTE: ProcessMIDI() can be used as the main event loop in an application. | |
// It will be called repeatedly and events will be generated according to the TiminInfo | |
/* | |
The ProcessMIDI() function lets you perform periodic (generally | |
timing-related) tasks. This can be used when scripting a sequencer, | |
arpeggiator, or other tempo-driven MIDI effect. ProcessMIDI is generally not | |
required for applications that do not make use of musical timing information | |
from the host. ProcessMIDI is called once per “process block,” which is | |
determined by the host’s audio settings (sample rate and buffer size). | |
ProcessMIDI is called with no arguments. | |
This function will often be used in combination with the "JavaScript | |
TimingInfo object" to make use of timing information from the host | |
application. The use of ProcessMIDI and the TimingInfo object is shown in | |
the example. | |
Note: To enable the GetTimingInfo feature, you need to add | |
var NeedsTimingInfo = true; at the global script level (outside of any | |
functions). | |
*/ | |
/* | |
JavaScript TimingInfo object | |
The TimingInfo object contains timing information that describes the state of | |
the host transport and the current musical tempo and meter. A TimingInfo | |
object can be retrieved by calling GetTimingInfo() | |
TimingInfo properties: | |
TimingInfo.playing //uses boolean logic where "true" means the host | |
//transport is running. | |
TimingInfo.blockStartBeat //a floating point number indicates the beat | |
//position at the start of the process block | |
TimingInfo.blockEndBeat //a floating point number indicates the beat position | |
//at the end of the process block | |
TimingInfo.blockSize //a floating point number indicates the length of the | |
//process block in beats | |
TimingInfo.tempo //a floating point number indicates the host tempo | |
TimingInfo.meterNumerator //an integer indicates the host meter numerator | |
TimingInfo.meterDenominator //an integer number indicates the host meter | |
//denominator | |
TimingInfo.cycling //uses boolean logic where "true" means the host transport | |
//is cycling | |
TimingInfo.leftCycleBeat //a floating point number indicates the beat position | |
//at the start of the cycle range | |
TimingInfo.rightCycleBeat //a floating point number indicates the beat | |
//position at the end of the cycle range | |
*note: The length of a beat is determined by the host application time | |
signature and tempo. | |
*/ | |
/* | |
Prints API TimingInfo attributes and calculates additional derived attributes. | |
Returns an object with the API TimingInfo object and derived attributes, and | |
sets this return value to a global. Each call after the first call in a run | |
simply returns the global already set, no-op. This is valid as long as the | |
event loop doesn't modify meter, sample depth or sampling rate, which the API | |
does not support. | |
@return | |
TimingInfoDump = { | |
blockLengthBeats: float, | |
blockLengthSecs: float, | |
blockLengthMsecs: float, | |
blocksPerBeat: int, | |
beatsPerNote: float, | |
beatsPerMeasure: float, | |
meter: string | |
} | |
*/ | |
// global object holding API TimingInfo and derived attributes, set on first | |
// call to parent event loop | |
var INFO = {}; | |
var SHOULD_DUMP = true; | |
var SECS_PER_MIN = 60; | |
var ONE_NOTE_PER_BEAT = 4; | |
function dumpAndGetTimingInfo(info) { | |
if (SHOULD_DUMP) { | |
Trace("** TRANSPORT"); | |
Trace("info.playing: " + info.playing); | |
Trace("info.cycling: " + info.cycling); | |
Trace("info.leftCycleBeat: " + info.leftCycleBeat); | |
Trace("info.rightCycleBeat: " + info.rightCycleBeat); | |
Trace("** TEMPO / BLOCK INFO"); | |
Trace("info.tempo BPM: " + info.tempo); | |
Trace("info.blockStartBeat: " + info.blockStartBeat); | |
Trace("info.blockEndBeat: " + info.blockEndBeat); | |
Trace("info.blockLength beats: " + info.blockLength); | |
var blocksPerBeat = Math.floor(1.0 / info.blockLength); | |
Trace("blocksPerBeat: " + blocksPerBeat); | |
var secsPerBeat = SECS_PER_MIN / info.tempo; | |
var blockLengthSecs = info.blockLength * secsPerBeat; | |
Trace("info.blockLength secs: " + blockLengthSecs); | |
Trace("info.blockLength msecs: " + 1000 * blockLengthSecs); | |
Trace("** METER / BLOCK INFO"); | |
var meter = info.meterNumerator + "/" + info.meterDenominator; | |
Trace("meter: " + meter); | |
var beatsPerNote = ONE_NOTE_PER_BEAT / info.meterDenominator; | |
var beatsPerMeasure = beatsPerNote * info.meterNumerator; | |
Trace("beats per note: " + beatsPerNote); | |
Trace("beats per measure: " + beatsPerMeasure); | |
INFO = { | |
"timingInfo": info, | |
"blockLengthBeats": info.blockLength, | |
"blockLengthSecs": blockLengthSecs, | |
"blockLengthMsecs": 1000 * blockLengthSecs, | |
"blocksPerBeat": blocksPerBeat, | |
"beatsPerNote": beatsPerNote, | |
"beatsPerMeasure": beatsPerMeasure, | |
"meter": meter | |
}; | |
} | |
SHOULD_DUMP = false; | |
return INFO; | |
} | |
// LogicProX API Event Handler, modify as needed | |
function ProcessMIDI() { | |
dumpAndGetTimingInfo(GetTimingInfo()); | |
} | |
// /ProcessMIDI Functions | |
/////////////////////// | |
/////////////////////// | |
// MIDI Event Functions | |
/* | |
Original documentation for functions 1 and 2 | |
The HandleMIDI() function lets you process MIDI events that the plug-in | |
receives. | |
HandleMIDI is called each time a MIDI event is received by the plug-in and is | |
required to process incoming MIDI events. If you do not implement the | |
HandleMIDI function, events pass through the plug-in unaffected. | |
HandleMIDI is called with one argument which is a JavaScript object that | |
represents the incoming MIDI event. HandleMIDI and JavaScript Event object | |
use is shown in the examples. | |
*/ | |
// Pass MIDI events through the plug-in | |
function send(event) { | |
event.send(); | |
} | |
// Log events to the plug-in console and do not send them anywhere | |
function trace(event) { | |
event.trace(); | |
} | |
// Repeat Note events offset by pitchOffset, pass other event types through | |
function transposeNote(event, pitchOffset) { | |
if (event instanceof Note) { | |
event.pitch += pitchOffset; // transpose | |
} | |
event.send(); // send original event | |
} | |
// Repeat Note events with N delayMs of delay, pass all other event types through | |
function delayNote(event, delayMs) { | |
event.send(); // send original event | |
// if it's a note | |
if (event instanceof Note) { | |
event.sendAfterMilliseconds(100); // send after delay | |
} else { | |
event.send(); // otherwise send original event | |
} | |
} | |
// LogicProX API Event Handler | |
// This event handler modifies an existing event | |
function HandleMIDI(event) { | |
send(event); | |
} | |
// ---- | |
// This is the meat of the API for musical Events | |
/* | |
JavaScript Event Object | |
When the "HandleMIDI function" is called, an Event object represents one MIDI | |
event and implements the following methods you can call in your script: | |
Event.send() //send the event | |
Event.sendAfterMilliseconds(number ms) //send the event after the specified | |
//value has elapsed(can be an integer | |
//or floating point number) | |
Event.sendAtBeat(number beat) //as above, but uses the beat value as a delay | |
//in beats from the current position | |
Event.trace() //print the event to the plug-in console | |
Event.toString() //returns a String representation of the event | |
Event.channel(number) //sets MIDI channel 1 to 16. Note: Event.channel is an | |
//event property, rather than a method | |
Event.beatPos //event property, represents the beat position of the event | |
//Event.send() sends at the beat position set by this property | |
Event.articulationID //property representing the articulation id of the note | |
The Event object is not instantiated directly, but is a prototype for the | |
following event-specific object types. All of the following types inherit the | |
methods described above and the channel property. The event types and their | |
properties are passed to HandleMIDI as follows: | |
Note //prototype for NoteOn and NoteOff | |
NoteOn.pitch(integer number) //pitch from 1-127 | |
NoteOn.velocity(integer number) //velocity from 0-127. A velocity value of 0 | |
//is interpreted as a note off event, not a | |
//note on. | |
NoteOff.pitch(integer number) //pitch from 0-127 | |
NoteOff.velocity(integer number) //velocity from 0-127 | |
PolyPressure.pitch(integer number) //pitch from 1-127. Polyphonic aftertouch | |
//is uncommon on synthesizers | |
PolyPressure.value(integer number) //pressure value from 0-127 | |
ControlChange.number(integer number) //controller number from 0-127 | |
ControlChange.value(integer number) //controller value from 0-127 | |
//tip: use MIDI.controllerName(number) to | |
//look up the name of the controller | |
ProgramChange.number(integer number) //Program change number from 0-127 | |
ChannelPressure.value(integer number) //aftertouch value from 0-127 | |
PitchBend.value(integer number) //14-bit pitch bend value from -8192 to 8191 | |
//a value of 0 is center | |
TargetEvent.target(string) // Name of target menu entry | |
// - Target events need a corresponding menu entry, | |
// see Tutorial script 15 | |
TargetEvent.value(float) // Value of set Target from 0.0 to 1.0 | |
*/ | |
// LogicProX API Event Handler | |
// This no-arg function creates new Events | |
function HandleMIDI() { | |
// Implement as needed | |
} | |
// Example from the Tutorial | |
/* | |
//Replace every MIDI event with a modulation control change message | |
//Tip: you can use the JavaScript "new" keyword to generate a new instance of an | |
//Event object of any type. | |
function HandleMIDI() { | |
var cc = new ControlChange; //make a new control change message | |
cc.number = 1; //set it to controller 1 (modulation) | |
cc.value = 100; //set the value | |
cc.send(); //send the event | |
cc.trace(); //print the event to the console | |
} | |
*/ | |
// Example from loop_event Script, good example of creating and sending Notes | |
/* | |
function playNote(pitch, beatDur) { | |
var on = new NoteOn(); | |
on.pitch = pitch; | |
on.send(on.beatPos); | |
var off = new NoteOff(on); | |
off.beatPos = on.beatPos + beatDur; | |
off.send(); | |
} | |
*/ | |
// ---- | |
// /MIDI Event Functions | |
/////////////////////// | |
/////////////////////// | |
// MIDI Global Functions | |
/* | |
JavaScript MIDI object | |
The MIDI object contains a number of convenient and easy to use functions | |
that can be used when writing your scripts. | |
Note: the MIDI object is a property of the global object, which means that | |
you do not instantiate it, but access it's functions much like you | |
would the JavaScript math object. An example is calling | |
MIDI.allNotesOff() directly. | |
MIDI object properties: | |
noteNumber(string name) //returns the MIDI note number for a given note name. | |
//for example: 'C3' or 'B#2' | |
//note: you cannot use flats in your argument. Use | |
A#3, not Bb3 | |
noteName(number pitch) //returns the name (string) for a given MIDI note | |
//number | |
ccName(number controller) //returns the controller name (string) for a given | |
//controller number | |
allNotesOff() //sends the all notes off message on all MIDI channels | |
normalizeStatus(number status) //normalizes a value to the safe range of | |
//MIDI status bytes (128-239) | |
normalizeChannel(number channel) //normalizes a value to the safe range of | |
//MIDI channels (1-16) | |
normalizeData(number data) //normalizes a value to the safe range of MIDI | |
//data byes (0-127) | |
*/ | |
// Example | |
// MIDI.allNotesOff() | |
// /MIDI Global Functions | |
/////////////////////// | |
/////////////////////// | |
// GUI Parameter Controls | |
/* | |
The GetParameter() function retrieves information from parameters defined | |
with var PluginParameters. | |
The GetParameter name argument must match the defined PluginParameters name | |
value. Calling GetParameter() returns the current value of the control. | |
*/ | |
// Example | |
// create a linear parameter called "Note Velocity" with a range of 1 to 127, and | |
// a default value of 80 | |
// var PluginParameters = [{name:"Note Velocity", type:"lin", minValue:1, | |
// maxValue:127, numberOfSteps:126, defaultValue:80}]; | |
/* | |
Create JavaScriptMIDI controls | |
The JavaScriptMIDI Script Editor lets you use a simple shorthand to add | |
standard controllers such as sliders and menus for automated or real time | |
control of your plug-ins. The only mandatory property to define a new | |
parameter is a name, which will default to a basic slider. In addition, you | |
can add the following properties to change the type and behavior of controls. | |
Optional properties: | |
type: | |
//type one of the following strings as the value: | |
"lin" //creates a linear fader | |
"log" //creates a logarithmic fader | |
"menu" //creates a menu | |
"valueStrings" //the menu type requires an additional property that is | |
//an array of strings to show in the menu | |
defaultValue: //type an integer or floating point number to set a default | |
//value. If not value is typed the default is 0.0 | |
minValue: //type an integer or floating point number to set a minimum value. | |
//if no value is typed, the default is 0.0 | |
maxValue: //type an integer or floating point number to set a maximum value. | |
//if no value is typed, the default is 1.0 | |
*/ | |
var SLIDER_TYPE_LINEAR = "lin"; | |
var SLIDER_TYPE_LOG = "log"; | |
var MENU = "menu"; | |
var PluginParameters = []; | |
// Map of indexes of controls, 'parameters' in LogicProX terminology, in the order they are created, | |
// mapped to a callback to pass the value of the control when ParameterChanged() is fired. This is | |
// a built-in LogicProX API call event handler which fires when controls change, and receives the index | |
// of the control and the current value. This pattern lets our implementation dispatch the value | |
// received to a callback created for each control. | |
var PARAM_CALLBACK_MAP = {}; | |
function noOpParamCallback(value) {} | |
function makeSlider(name, sliderType, minVal, maxVal, numberOfSteps, defaultVal, paramCallback) { | |
var paramIndex = PluginParameters.length(); | |
PluginParameters.push({ | |
"name": name , | |
"type": sliderType, | |
"minValue": minVal, | |
"maxValue": 127, | |
"numberOfSteps": numberOfSteps, | |
"defaultValue": defaultVal | |
}); | |
if (paramCallback === null || paramCallback === undefined) { | |
paramCallback = noOpParamCallback; | |
} | |
PARAM_CALLBACK_MAP[paramIndex] = paramCallback; | |
} | |
function makeMenu(name, minVal, maxVal, numberOfSteps, defaultVal, menuItems, paramCallback) { | |
var paramIndex = PluginParameters.length(); | |
PluginParameters.push({ | |
"name": name , | |
"type": MENU, | |
"minValue": minVal, | |
"maxValue": 127, | |
"numberOfSteps": numberOfSteps, | |
"defaultValue": defaultVal, | |
"valueStrings": valueStrings | |
}); | |
if (paramCallback === null || paramCallback === undefined) { | |
paramCallback = noOpParamCallback; | |
} | |
PARAM_CALLBACK_MAP[paramIndex] = paramCallback; | |
} | |
// Helpers for common event attributes we want to control with controls | |
function velocitySetAndSend(event, name) { | |
if (event instanceof Note) { | |
event.velocity = GetParameter(name); | |
} | |
event.send(); | |
} | |
function pitchSetAndSend(event, name) { | |
if (event instanceof Note) { | |
event.pitch = GetParameter(name); | |
} | |
event.send(); | |
} | |
// LogicProX API Event Handler | |
function ParameterChanged(param, value) { | |
PARAM_CALLBACK_MAP[param](value); | |
} | |
// /GUI Paramter Controls | |
/////////////////////// | |
/////////////////////// | |
// Event Parameters Controlled by External Conrollers | |
/* | |
JavaScript TargetEvent Object | |
With the TargetEvent object you can create user definable MIDI CC messages | |
or control plug-in parameters. | |
The object reads the parameter to be modified from a menu in which the user can select | |
a destination MIDI CC, or use the Learn Plug-in Parameter command to assign any | |
parameter of a plug-in inserted after (below) Scripter in the same channel strip. | |
The chosen destination is saved with the plug-in setting. | |
TargetEvent properties: | |
TargetEvent.target(string) // Name of target menu entry | |
TargetEvent.value(float) // Value of set target from 0.0 to 1.0 | |
Example: | |
- set a Parameter of type "target" addressabe by it's "name" | |
- in HandleMIDI(event) if the event is a ControlChange and it's event.number is the CC # we want to bind | |
to this Parameter, then handle the event | |
var PluginParameters = [ | |
// parameter 0 | |
{ | |
name:"Modwheel Target", | |
type:"target" | |
} | |
]; | |
// HandleMIDI is called every time the Scripter receives a MIDI event. | |
function HandleMIDI(incomingEvent) | |
{ | |
// remap modulation to target selected in menu | |
// check for incoming CC event with number 1 (Modwheel) | |
if ((incomingEvent instanceof ControlChange) && (incomingEvent.number == 1)) | |
{ | |
var newEvent = new TargetEvent(); // create new Target Event | |
newEvent.target = "Modwheel Target"; // set menu entry to be used by this event by its name | |
newEvent.value = incomingEvent.value / 127; // rescale from 0..127 to 0.0..1.0 | |
newEvent.send(); // send the event | |
} else { | |
// send all other events | |
incomingEvent.send(); | |
}; | |
}; | |
*/ | |
// /Event Parameters Controlled by External Conrollers | |
/////////////////////// | |
/////////////////////// | |
// General Utils | |
// Helper to play a single note with a pitch and a duration in beats set by beatDur | |
function playNote(pitch, beatDur) { | |
var on = new NoteOn(); | |
on.pitch = pitch; | |
on.send(on.beatPos); | |
var off = new NoteOff(on); | |
off.beatPos = on.beatPos + beatDur; | |
off.send(); | |
} | |
// ---- | |
// ----- | |
// pitches | |
var P0 = { | |
"C": 24, | |
"Cs": 25, | |
"Df": 25, | |
"D": 26, | |
"Ds": 27, | |
"Ef": 27, | |
"E": 28, | |
"F": 29, | |
"Fs": 30, | |
"Gf": 30, | |
"G": 31, | |
"Gs": 32, | |
"Af": 32, | |
"A": 33, | |
"As": 34, | |
"Bf": 34, | |
"B": 35 | |
} | |
/* | |
Calculates and returns MIDI pitch int value as offset by octave from 0th | |
octave (i.e. C0 .. B0). | |
Valid values for octave are 0 .. 7, in that that range | |
of values will actually create a sound on a MIDI piano (for example).Actual | |
MIDI pitch values are valid from 0 to 127, though values below 24 map to | |
"negative octaves" on a piano keyboard, since 60 maps to C3. No validation | |
is done, to avoid additional computation for every note generation. | |
@return int value of MIDI pitch | |
*/ | |
function P(octave, pitch) { | |
return P0[pitch] + (12 * octave); | |
} | |
// ---- | |
var LOOKUP = [ | |
0, 0.01, 0.02, | |
0.03, 0.04, 0.05, | |
0.060000000000000005, 0.07, 0.08, | |
0.09, 0.09999999999999999, 0.10999999999999999, | |
0.11999999999999998, 0.12999999999999998, 0.13999999999999999, | |
0.15, 0.16, 0.17, | |
0.18000000000000002, 0.19000000000000003, 0.20000000000000004, | |
0.21000000000000005, 0.22000000000000006, 0.23000000000000007, | |
0.24000000000000007, 0.25000000000000006, 0.26000000000000006, | |
0.2700000000000001, 0.2800000000000001, 0.2900000000000001, | |
0.3000000000000001, 0.3100000000000001, 0.3200000000000001, | |
0.3300000000000001, 0.34000000000000014, 0.35000000000000014, | |
0.36000000000000015, 0.37000000000000016, 0.38000000000000017, | |
0.3900000000000002, 0.4000000000000002, 0.4100000000000002, | |
0.4200000000000002, 0.4300000000000002, 0.4400000000000002, | |
0.45000000000000023, 0.46000000000000024, 0.47000000000000025, | |
0.48000000000000026, 0.49000000000000027, 0.5000000000000002, | |
0.5100000000000002, 0.5200000000000002, 0.5300000000000002, | |
0.5400000000000003, 0.5500000000000003, 0.5600000000000003, | |
0.5700000000000003, 0.5800000000000003, 0.5900000000000003, | |
0.6000000000000003, 0.6100000000000003, 0.6200000000000003, | |
0.6300000000000003, 0.6400000000000003, 0.6500000000000004, | |
0.6600000000000004, 0.6700000000000004, 0.6800000000000004, | |
0.6900000000000004, 0.7000000000000004, 0.7100000000000004, | |
0.7200000000000004, 0.7300000000000004, 0.7400000000000004, | |
0.7500000000000004, 0.7600000000000005, 0.7700000000000005, | |
0.7800000000000005, 0.7900000000000005, 0.8000000000000005, | |
0.8100000000000005, 0.8200000000000005, 0.8300000000000005, | |
0.8400000000000005, 0.8500000000000005, 0.8600000000000005, | |
0.8700000000000006, 0.8800000000000006, 0.8900000000000006, | |
0.9000000000000006, 0.9100000000000006, 0.9200000000000006, | |
0.9300000000000006, 0.9400000000000006, 0.9500000000000006, | |
0.9600000000000006, 0.9700000000000006, 0.9800000000000006, | |
0.9900000000000007, 1.0000000000000007, 1.0100000000000007, | |
1.0200000000000007, 1.0300000000000007, 1.0400000000000007, | |
1.0500000000000007, 1.0600000000000007, 1.0700000000000007, | |
1.0800000000000007, 1.0900000000000007, 1.1000000000000008, | |
1.1100000000000008, 1.1200000000000008, 1.1300000000000008, | |
1.1400000000000008, 1.1500000000000008, 1.1600000000000008, | |
1.1700000000000008, 1.1800000000000008, 1.1900000000000008, | |
1.2000000000000008, 1.2100000000000009, 1.2200000000000009, | |
1.2300000000000009, 1.2400000000000009, 1.2500000000000009, | |
1.260000000000001, 1.270000000000001, 1.280000000000001, | |
1.290000000000001, 1.300000000000001, 1.310000000000001, | |
1.320000000000001, 1.330000000000001, 1.340000000000001, | |
1.350000000000001, 1.360000000000001, 1.370000000000001, | |
1.380000000000001, 1.390000000000001, 1.400000000000001, | |
1.410000000000001, 1.420000000000001, 1.430000000000001, | |
1.440000000000001, 1.450000000000001, 1.460000000000001, | |
1.470000000000001, 1.480000000000001, 1.490000000000001, | |
1.500000000000001, 1.5100000000000011, 1.5200000000000011, | |
1.5300000000000011, 1.5400000000000011, 1.5500000000000012, | |
1.5600000000000012, 1.5700000000000012, 1.5800000000000012, | |
1.5900000000000012, 1.6000000000000012, 1.6100000000000012, | |
1.6200000000000012, 1.6300000000000012, 1.6400000000000012, | |
1.6500000000000012, 1.6600000000000013, 1.6700000000000013, | |
1.6800000000000013, 1.6900000000000013, 1.7000000000000013, | |
1.7100000000000013, 1.7200000000000013, 1.7300000000000013, | |
1.7400000000000013, 1.7500000000000013, 1.7600000000000013, | |
1.7700000000000014, 1.7800000000000014, 1.7900000000000014, | |
1.8000000000000014, 1.8100000000000014, 1.8200000000000014, | |
1.8300000000000014, 1.8400000000000014, 1.8500000000000014, | |
1.8600000000000014, 1.8700000000000014, 1.8800000000000014, | |
1.8900000000000015, 1.9000000000000015, 1.9100000000000015, | |
1.9200000000000015, 1.9300000000000015, 1.9400000000000015, | |
1.9500000000000015, 1.9600000000000015, 1.9700000000000015, | |
1.9800000000000015, 1.9900000000000015, 2.0000000000000013, | |
2.010000000000001, 2.020000000000001, 2.0300000000000007, | |
2.0400000000000005, 2.0500000000000003, 2.06, | |
2.07, 2.0799999999999996, 2.0899999999999994, | |
2.099999999999999, 2.109999999999999, 2.1199999999999988, | |
2.1299999999999986, 2.1399999999999983, 2.149999999999998, | |
2.159999999999998, 2.1699999999999977, 2.1799999999999975, | |
2.1899999999999973, 2.199999999999997, 2.209999999999997, | |
2.2199999999999966, 2.2299999999999964, 2.239999999999996, | |
2.249999999999996, 2.259999999999996, 2.2699999999999956, | |
2.2799999999999954, 2.289999999999995, 2.299999999999995, | |
2.3099999999999947, 2.3199999999999945, 2.3299999999999943, | |
2.339999999999994, 2.349999999999994, 2.3599999999999937, | |
2.3699999999999934, 2.3799999999999932, 2.389999999999993, | |
2.399999999999993, 2.4099999999999926, 2.4199999999999924, | |
2.429999999999992, 2.439999999999992, 2.4499999999999917, | |
2.4599999999999915, 2.4699999999999913, 2.479999999999991, | |
2.489999999999991, 2.4999999999999907, 2.5099999999999905, | |
2.5199999999999902, 2.52999999999999, 2.53999999999999, | |
2.5499999999999896, 2.5599999999999894, 2.569999999999989, | |
2.579999999999989, 2.5899999999999888, 2.5999999999999885, | |
2.6099999999999883, 2.619999999999988, 2.629999999999988, | |
2.6399999999999877, 2.6499999999999875, 2.6599999999999873, | |
2.669999999999987, 2.679999999999987, 2.6899999999999866, | |
2.6999999999999864, 2.709999999999986, 2.719999999999986, | |
2.7299999999999858, 2.7399999999999856, 2.7499999999999853, | |
2.759999999999985, 2.769999999999985, 2.7799999999999847, | |
2.7899999999999845, 2.7999999999999843, 2.809999999999984, | |
2.819999999999984, 2.8299999999999836, 2.8399999999999834, | |
2.849999999999983, 2.859999999999983, 2.869999999999983, | |
2.8799999999999826, 2.8899999999999824, 2.899999999999982, | |
2.909999999999982, 2.9199999999999817, 2.9299999999999815, | |
2.9399999999999813, 2.949999999999981, 2.959999999999981, | |
2.9699999999999807, 2.9799999999999804, 2.9899999999999802, | |
2.99999999999998, 3.00999999999998, 3.0199999999999796, | |
3.0299999999999794, 3.039999999999979, 3.049999999999979, | |
3.0599999999999787, 3.0699999999999785, 3.0799999999999783, | |
3.089999999999978, 3.099999999999978, 3.1099999999999777, | |
3.1199999999999775, 3.1299999999999772, 3.139999999999977, | |
3.149999999999977 | |
]; | |
var INDEX = 0; | |
var MAX_INDEX = LOOKUP.length; | |
function getSineNext() { | |
if (INDEX == MAX_INDEX) { | |
INDEX = 0; | |
} | |
sineNext = Math.sin(LOOKUP[INDEX]); | |
INDEX++; | |
return sineNext; | |
} | |
// /General Utils | |
/////////////////////// |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment