56 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, gender identity and expression, level of experience,
9 | education, socio-economic status, nationality, personal appearance, race,
10 | religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team via [email](mailto:kabirajitnagral@gmail.com). All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
--------------------------------------------------------------------------------
/Library/sequencer.js:
--------------------------------------------------------------------------------
1 | // Constructs a sequence of notes triggered relative to the base note
2 |
3 | var NeedsTimingInfo = true;
4 | var activeNotes = [];
5 | var sequence = [2, 2, 1, 2, 2, 2, 1]; // Choose your sequence here. Enter integers for ups or downs
6 | /* needed to make beatPos work */
7 | function HandleMIDI(event) {
8 | if (event instanceof NoteOn) {
9 | constructSequence(event);
10 | // activeNotes.push(event);
11 | // for (var i = 0; i < sequence.length; i++) {
12 | // var on = new NoteOn (activeNotes[i]);
13 | // var previous = new NoteOn (activeNotes[i])
14 | // on.pitch = MIDI.normalizeData(previous.pitch + sequence[i]);
15 | // activeNotes.push (on);
16 | // on.sendAtBeat(previous.beatPos + 2);
17 | // }
18 | }
19 |
20 | else if (event instanceof NoteOff) {
21 | // remove note from array
22 | Reset();
23 | for (i = 0; i < activeNotes.length; i++) {
24 | if (activeNotes[i].pitch == event.pitch) {
25 | activeNotes.splice(i, 1);
26 | break;
27 | }
28 | }
29 | }
30 |
31 | else {
32 | event.send();
33 | }
34 | }
35 |
36 | function Reset() {
37 | activeNotes = [];
38 | }
39 |
40 | // function ProcessMIDI() {
41 | // for (var i = 0; i < activeNotes.length; i++) {
42 | // var currentNote = new NoteOn (sequence[i]);
43 | // currentNote.send();
44 | // }
45 | // }
46 |
47 | function constructSequence(event) {
48 | activeNotes.push (event);
49 | for (var i = 0; i < sequence.length; i++) {
50 | var on = new NoteOn;
51 | on.pitch = MIDI.normalizeData(activeNotes[i].pitch + sequence[i]);
52 | activeNotes.push (on);
53 | }
54 | }
55 |
56 | var wasPlaying = false;
57 |
58 | function ProcessMIDI() {
59 | // Get timing information from the host application
60 | var musicInfo = GetTimingInfo();
61 |
62 | // clear activeNotes[] when the transport stops and send any remaining note off events
63 | if (wasPlaying && !musicInfo.playing){
64 | for(i=0;i= musicInfo.rightCycleBeat) {
89 | if (lookAheadEnd >= musicInfo.rightCycleBeat) {
90 | var cycleBeats = musicInfo.rightCycleBeat - musicInfo.leftCycleBeat;
91 | var cycleEnd = lookAheadEnd - cycleBeats;
92 | }
93 | }
94 |
95 | // var state = GetParameter("Reset");
96 | // if (state == 1) {
97 | // Reset();
98 | // }
99 |
100 | // loop through the beats that fall within this buffer
101 | while ((nextBeat >= musicInfo.blockStartBeat && nextBeat < lookAheadEnd)
102 | // including beats that wrap around the cycle point
103 | || (musicInfo.cycling && nextBeat < cycleEnd)) {
104 | // adjust for cycle
105 | if (musicInfo.cycling && nextBeat >= musicInfo.rightCycleBeat)
106 | nextBeat -= cycleBeats;
107 |
108 | // calculate step
109 | var step = Math.floor(nextBeat / (1 / division) - division);
110 | var chosenNote = chooseNote(noteOrder, step);
111 |
112 | // send events
113 | var noteOn = new NoteOn(chosenNote);
114 | // noteOn.pitch = MIDI.normalizeData(noteOn.pitch + randomOctave);
115 | noteOn.pitch = (noteOn.pitch + randomOctave);
116 | noteOn.sendAtBeat(nextBeat + randomDelay);
117 | var noteOff = new NoteOff(noteOn);
118 | noteOff.sendAtBeat(nextBeat + randomDelay + noteLength + randomLength)
119 |
120 | // advance to next beat
121 | nextBeat += 0.001;
122 | nextBeat = Math.ceil(nextBeat * division) / division;
123 | }
124 | }
125 | }
126 |
127 | var noteOrders = ["up", "down", "random"];
128 |
129 | function chooseNote(noteOrder, step) {
130 | var order = noteOrders[noteOrder];
131 | var length = activeNotes.length
132 | if (order == "up") return activeNotes[step % length];
133 | if (order == "down") return activeNotes[Math.abs(step % length - (length - 1))];
134 | if (order == "random") return activeNotes[Math.floor(Math.random() * length)];
135 | else return 0;
136 | }
137 |
138 | // function constructSequence(event) {
139 | // activeNotes.push (event);
140 | // for (var i = 0; i < sequence.length; i++) {
141 | // var on = new NoteOn;
142 | // on.pitch = MIDI.normalizeData(activeNotes[i].pitch + sequence[i]);
143 | // on.beatPos = activeNotes[i].beatPos + 1;
144 | // activeNotes.push (on);
145 | // }
146 | // }
147 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Do you enjoy Logic Pro, Javascript, the Logic Pro Scripter plugin or all three? Here's how we can help each other.
4 |
5 | We love pull requests from everyone. By participating in this project, you agree
6 | to abide by the LPXscripts [code of conduct](https://github.com/kabirnagral/LPXscripts/blob/master/CODE_OF_CONDUCT.md).
7 |
8 | ## Contents
9 |
10 | [Git and GitHub](#git-and-github)
11 |
12 | [Contributing Basics](#contributing-basics)
13 | * [Contributing to the Library](#contributing-to-the-library)
14 | * [Contributing to the Guide](#contributing-to-the-guide)
15 | * [Submitting Changes](#submitting-changes)
16 | * [Commit Messages](#commit-messages)
17 | * [Making Changes Locally](#making-changes-locally)
18 |
19 | [Coding Conventions](#coding-conventions)
20 |
21 | [Reporting Issues](#reporting-issues)
22 |
23 | [Resources](#resources)
24 |
25 | ## Git and Github
26 |
27 | LPXscripts is an Open Source project. It uses [Git](https://git-scm.com/) and [GitHub](http://github.com/) to handle coordinating maintenance of the site and the publishing of new content and features.
28 |
29 | Check out our [resources](#resources) for assistance.
30 |
31 | ## Contributing Basics
32 |
33 | Fork this repository (Don't know how? Refer to the [resources](#resources)).
34 |
35 | Clone your fork of this repository (Don't know how? Refer to the [resources](#resources)).
36 |
37 | Make your changes locally on your system (more about that [here](#making-changes-locally)), while making sure that you follow our [coding conventions](#coding-conventions).
38 |
39 | Test your changes to see if they work.
40 |
41 | ### Contributing to the Library
42 |
43 | To contribute to the Library, you need to have Logic Pro X installed on your system (the system should run OS X, although there may be people who know workarounds). You need to access the Logic Pro Scripter plugin on a MIDI/software instrument through the MIDI FX options (see [here](https://kabirnagral.github.io/LPXscripts/#how-to-use-library) on how to get there). Once you are there, you can use regular JavaScript, the basic Apple tutorials and this [quick reference guide] (https://kabirnagral.github.io/LPXscripts/#reference-guide) to start developing your own plugins.
44 |
45 | ### Contributing to the Guide
46 |
47 | The website is contained in the docs folder. To contribute to the website, you do not need to have Logic Pro (although that definitely helps). All you need is basic HTML/CSS experience. In fact, you don't even need any coding experience. You could raise issues you have with the website [here](https://github.com/kabirnagral/LPXscripts/issues/new), or even provide language translations for the website (raise an issue for the same).
48 |
49 | ### Submitting Changes
50 |
51 | Add your changes and commit them, while keeping in mind our [policy on commit messages](#commit-messages).
52 |
53 | Push your local repository to your remote repository.
54 |
55 | Submit a pull request.
56 |
57 | Please send a [GitHub Pull Request to LPXscripts](https://github.com/kabirnagral/LPXscripts/pull/new/master) with a clear list of what you've done. Please follow our [coding conventions](#coding-conventions).
58 |
59 | Wait for us.
60 | We try to at least comment on pull requests within one business day.
61 | We may suggest changes.
62 |
63 | ### Commit Messages
64 |
65 | Always write a clear log message for your commits. One-line messages are fine for small changes, but bigger changes should look like this:
66 |
67 | $ git commit -m "A brief summary of the commit
68 | >
69 | > A paragraph describing what changed and its impact."
70 |
71 | ### Making Changes Locally
72 |
73 | We suggest that you always make changes to your fork on a local repository on your system. This makes the testing process for both the script functions and the guide website much simpler. If you are only making documentation changes, then it is fine to make changes using GitHub's online editor.
74 |
75 | ## Coding conventions
76 |
77 | Start reading our code and you'll get the hang of it. We optimize for readability:
78 |
79 | * We indent using two spaces (soft tabs)
80 | * We always put spaces after list items (`[1, 2, 3]`, not `[1,2,3]`) and method parameters (`[1, 2, 3]`, not `[1,2,3]`), around operators (`x += 1`, not `x+=1`), and around hash arrows.
81 | * This is open source software. Consider the people who will read your code, and make it look nice for them.
82 | * Our code must be accessible to all. Check out our [resources](#resources) for assistance.
83 |
84 | ## Reporting Issues
85 |
86 | Raising and reporting issues is an incredible way to contribute to this project. If you find something you think you can improve or you want improved, please [raise an issue](https://github.com/kabirnagral/LPXscripts/issues/new). Read through [existing issues](https://github.com/kabirnagral/LPXscripts/issues) to make sure that you are not raising a new issue that is similar to an issue that already exists. If you have something that is related to an existent issue, you can comment on its thread.
87 |
88 | ## Resources
89 |
90 | You can use and contribute to resources [here](https://github.com/kabirnagral/LPXscripts/blob/master/RESOURCES.md).
91 |
--------------------------------------------------------------------------------
/docs/style.js:
--------------------------------------------------------------------------------
1 | function w3_open() {
2 | document.getElementById("mySidebar").style.display = "block";
3 | document.getElementById("myOverlay").style.display = "block";
4 | }
5 |
6 | function w3_close() {
7 | document.getElementById("mySidebar").style.display = "none";
8 | document.getElementById("myOverlay").style.display = "none";
9 | }
10 |
11 | // Modal Image Gallery
12 | function onClick(element) {
13 | document.getElementById("img01").src = element.src;
14 | document.getElementById("modal01").style.display = "block";
15 | var captionText = document.getElementById("caption");
16 | captionText.innerHTML = element.alt;
17 | }
18 |
19 | function myAccFunc(element) {
20 | var x = document.getElementById(element);
21 | if (x.className.indexOf("w3-show") == -1) {
22 | x.className += " w3-show";
23 | x.previousElementSibling.className += " w3-green";
24 | } else {
25 | x.className = x.className.replace(" w3-show", "");
26 | x.previousElementSibling.className =
27 | x.previousElementSibling.className.replace(" w3-green", "");
28 | }
29 | }
30 |
31 | function sortTableMetrics(n) {
32 | var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
33 | table = document.getElementById("resultsTable");
34 | switching = true;
35 | // Set the sorting direction to ascending:
36 | dir = "asc";
37 | /* Make a loop that will continue until
38 | no switching has been done: */
39 | while (switching) {
40 | // Start by saying: no switching is done:
41 | switching = false;
42 | rows = table.getElementsByTagName("TR");
43 | /* Loop through all table rows (except the
44 | first, which contains table headers): */
45 | for (i = 1; i < (rows.length - 1); i++) {
46 | // Start by saying there should be no switching:
47 | shouldSwitch = false;
48 | /* Get the two elements you want to compare,
49 | one from current row and one from the next: */
50 | x = rows[i].getElementsByTagName("TD")[n];
51 | y = rows[i + 1].getElementsByTagName("TD")[n];
52 | /* Check if the two rows should switch place,
53 | based on the direction, asc or desc: */
54 | if (dir == "asc") {
55 | if (+(x.innerHTML) > +(y.innerHTML)) {
56 | // If so, mark as a switch and break the loop:
57 | shouldSwitch= true;
58 | break;
59 | }
60 | } else if (dir == "desc") {
61 | if (+(x.innerHTML) < +(y.innerHTML)) {
62 | // If so, mark as a switch and break the loop:
63 | shouldSwitch= true;
64 | break;
65 | }
66 | }
67 | }
68 | if (shouldSwitch) {
69 | /* If a switch has been marked, make the switch
70 | and mark that a switch has been done: */
71 | rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
72 | switching = true;
73 | // Each time a switch is done, increase this count by 1:
74 | switchcount ++;
75 | } else {
76 | /* If no switching has been done AND the direction is "asc",
77 | set the direction to "desc" and run the while loop again. */
78 | if (switchcount == 0 && dir == "asc") {
79 | dir = "desc";
80 | switching = true;
81 | }
82 | }
83 | }
84 | }
85 |
86 | function sortTable(n) {
87 | var table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
88 | table = document.getElementById("resultsTable");
89 | switching = true;
90 | // Set the sorting direction to ascending:
91 | dir = "asc";
92 | /* Make a loop that will continue until
93 | no switching has been done: */
94 | while (switching) {
95 | // Start by saying: no switching is done:
96 | switching = false;
97 | rows = table.getElementsByTagName("TR");
98 | /* Loop through all table rows (except the
99 | first, which contains table headers): */
100 | for (i = 1; i < (rows.length - 1); i++) {
101 | // Start by saying there should be no switching:
102 | shouldSwitch = false;
103 | /* Get the two elements you want to compare,
104 | one from current row and one from the next: */
105 | x = rows[i].getElementsByTagName("TD")[n];
106 | y = rows[i + 1].getElementsByTagName("TD")[n];
107 | /* Check if the two rows should switch place,
108 | based on the direction, asc or desc: */
109 | if (dir == "asc") {
110 | if ((x.innerHTML) > (y.innerHTML)) {
111 | // If so, mark as a switch and break the loop:
112 | shouldSwitch= true;
113 | break;
114 | }
115 | } else if (dir == "desc") {
116 | if ((x.innerHTML) < (y.innerHTML)) {
117 | // If so, mark as a switch and break the loop:
118 | shouldSwitch= true;
119 | break;
120 | }
121 | }
122 | }
123 | if (shouldSwitch) {
124 | /* If a switch has been marked, make the switch
125 | and mark that a switch has been done: */
126 | rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
127 | switching = true;
128 | // Each time a switch is done, increase this count by 1:
129 | switchcount ++;
130 | } else {
131 | /* If no switching has been done AND the direction is "asc",
132 | set the direction to "desc" and run the while loop again. */
133 | if (switchcount == 0 && dir == "asc") {
134 | dir = "desc";
135 | switching = true;
136 | }
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/Library/arpeggiator.js:
--------------------------------------------------------------------------------
1 | // Allows users to create a sequence that keeps repeating. Example use case: to test out melodies.
2 |
3 | var NeedsTimingInfo = true;
4 | var activeNotes = [];
5 |
6 | function HandleMIDI(event) {
7 | if (event instanceof NoteOn) {
8 | // add note to array
9 | activeNotes.push(event);
10 | }
11 | // else if (event instanceof NoteOff) {
12 | // // remove note from array
13 | // for (i = 0; i < activeNotes.length; i++) {
14 | // if (activeNotes[i].pitch == event.pitch) {
15 | // activeNotes.splice (i, 1);
16 | // break;
17 | // }
18 | // }
19 | // }
20 | // pass non-note events through
21 | else event.send();
22 |
23 | // sort array of active notes
24 | // activeNotes.sort(sortByPitchAscending);
25 | // Remove the '//' above to force the note to be in order by pitch
26 | }
27 |
28 | //-----------------------------------------------------------------------------
29 | function sortByPitchAscending(a,b) {
30 | if (a.pitch < b.pitch) return -1;
31 | if (a.pitch > b.pitch) return 1;
32 | return 0;
33 | }
34 |
35 | //-----------------------------------------------------------------------------
36 | var wasPlaying = false;
37 |
38 | function ProcessMIDI() {
39 | // Get timing information from the host application
40 | var musicInfo = GetTimingInfo();
41 |
42 | // clear activeNotes[] when the transport stops and send any remaining note off events
43 | if (wasPlaying && !musicInfo.playing){
44 | for(i=0;i= musicInfo.rightCycleBeat) {
68 | if (lookAheadEnd >= musicInfo.rightCycleBeat) {
69 | var cycleBeats = musicInfo.rightCycleBeat - musicInfo.leftCycleBeat;
70 | var cycleEnd = lookAheadEnd - cycleBeats;
71 | }
72 | }
73 |
74 | var state = GetParameter("Reset");
75 | if (state == 1) {
76 | Reset();
77 | }
78 |
79 | // loop through the beats that fall within this buffer
80 | while ((nextBeat >= musicInfo.blockStartBeat && nextBeat < lookAheadEnd && state == 0)
81 | // including beats that wrap around the cycle point
82 | || (musicInfo.cycling && nextBeat < cycleEnd)) {
83 | // adjust for cycle
84 | if (musicInfo.cycling && nextBeat >= musicInfo.rightCycleBeat)
85 | nextBeat -= cycleBeats;
86 |
87 | // calculate step
88 | var step = Math.floor(nextBeat / (1 / division) - division);
89 | var chosenNote = chooseNote(noteOrder, step);
90 |
91 | // send events
92 | var noteOn = new NoteOn(chosenNote);
93 | noteOn.pitch = MIDI.normalizeData(noteOn.pitch + randomOctave);
94 | noteOn.sendAtBeat(nextBeat + randomDelay);
95 | var noteOff = new NoteOff(noteOn);
96 | noteOff.sendAtBeat(nextBeat + randomDelay + noteLength + randomLength)
97 |
98 | // advance to next beat
99 | nextBeat += 0.001;
100 | nextBeat = Math.ceil(nextBeat * division) / division;
101 | }
102 | }
103 | }
104 |
105 | function Reset() {
106 | NeedsTimingInfo = true;
107 | activeNotes = [];
108 | SetParameter ("Reset", 0);
109 | }
110 |
111 | //-----------------------------------------------------------------------------
112 | var noteOrders = ["up", "down", "random"];
113 |
114 | function chooseNote(noteOrder, step) {
115 | var order = noteOrders[noteOrder];
116 | var length = activeNotes.length
117 | if (order == "up") return activeNotes[step % length];
118 | if (order == "down") return activeNotes[Math.abs(step % length - (length - 1))];
119 | if (order == "random") return activeNotes[Math.floor(Math.random() * length)];
120 | else return 0;
121 | }
122 |
123 | //-----------------------------------------------------------------------------
124 | var PluginParameters =
125 | [
126 | {name:"Reset", type:"menu", valueStrings:["Off", "On"],
127 | minValue:0, maxValue:1, numberOfSteps: 2, defaultValue:0},
128 |
129 | {name:"Beat Division", type:"linear",
130 | minValue:1, maxValue:16, numberOfSteps:15, defaultValue:1},
131 |
132 | {name:"Note Order", type:"menu", valueStrings:noteOrders,
133 | minValue:0, maxValue:2, numberOfSteps: 3, defaultValue:0},
134 |
135 | {name:"Note Length", unit:"%", type:"linear",
136 | minValue:1, maxValue:200, defaultValue:100.0, numberOfSteps:199},
137 |
138 | {name:"Random Length", unit:"%", type:"linear",
139 | minValue:0, maxValue:200, numberOfSteps: 200, defaultValue:0},
140 |
141 | {name:"Random Delay", unit:"%", type:"linear",
142 | minValue:0, maxValue:200, numberOfSteps:200, defaultValue:0},
143 |
144 | {name:"Random Octave", type:"linear",
145 | minValue:1, maxValue:4, defaultValue:1, numberOfSteps:3}
146 | ];
147 |
148 | // ----------------------------------------------------------------------------
149 | // Code from plugin.js
150 |
151 | // Copy and paste this chunk of code into your script editor to create controls in your plugin
152 |
153 | // var PluginParameters = [];
154 |
155 | // Types of Plugin Parameters
156 | const LINEAR_FADER = "lin";
157 | const LOGARITHMIC_FADER = "log";
158 | const MOMENTARY_BUTTON = "momentary";
159 | const MENU = "menu";
160 | const NOT_NEEDED = "";
161 |
162 | /*
163 | To create a plugin parameter (a fader or knob that changes something is a basic way of desribing it), call the createPluginParameter function as follows:
164 | createPluginParameter("Enter a name in quotes", Enter a type from above in quotes (for example: LINEAR_FADER), Enter a minimum value, Enter a maximum value, Enter a default value, enter the number of steps, "Enter a unit in quotes", "Enter text to create a divider/header in the plug-in", Enter a list of value strings if you are creating a menu as follows: ["something", "something", "something"]);
165 | */
166 |
167 | function createPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) {
168 | if (type == MENU) {
169 | PluginParameters.push (createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings));
170 | }
171 | else {
172 | PluginParameters.push (createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text));
173 | }
174 | }
175 |
176 | function createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text) {
177 | return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text};
178 | }
179 |
180 | function createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) {
181 | return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text, valueStrings: valueStrings};
182 | }
183 |
184 | //Parameters for the plugin
185 |
--------------------------------------------------------------------------------
/Library/repeater.js:
--------------------------------------------------------------------------------
1 | // Repeats note that is played with specified beat divisions
2 |
3 | var NeedsTimingInfo = true;
4 | var activeNotes = [];
5 |
6 | function HandleMIDI(event) {
7 | if (event instanceof NoteOn) {
8 | // add note to array
9 | activeNotes.push(event);
10 | }
11 | else if (event instanceof NoteOff) {
12 | // remove note from array
13 | for (i = 0; i < activeNotes.length; i++) {
14 | if (activeNotes[i].pitch == event.pitch) {
15 | activeNotes.splice (i, 1);
16 | break;
17 | }
18 | }
19 | }
20 | // pass non-note events through
21 | else event.send();
22 |
23 | // sort array of active notes
24 | activeNotes.sort(sortByPitchAscending);
25 | }
26 |
27 | //-----------------------------------------------------------------------------
28 | function sortByPitchAscending (a, b) {
29 | if (a.pitch < b.pitch) {
30 | return -1;
31 | }
32 | if (a.pitch > b.pitch) {
33 | return 1;
34 | }
35 | return 0;
36 | }
37 |
38 | //-----------------------------------------------------------------------------
39 | var wasPlaying = false;
40 |
41 | function ProcessMIDI() {
42 | // Get timing information from the host application
43 | var musicInfo = GetTimingInfo();
44 |
45 | // clear activeNotes[] when the transport stops and send any remaining note off events
46 | if (wasPlaying && !musicInfo.playing) {
47 | for(i = 0;i < activeNotes.length; i++) {
48 | var off = new NoteOff(activeNotes[i]);
49 | off.send();
50 | }
51 | }
52 |
53 | wasPlaying = musicInfo.playing;
54 |
55 | if (activeNotes.length != 0) {
56 |
57 | // get parameters
58 | var division = GetParameter("Beat Division");
59 | var noteOrder = GetParameter("Note Order");
60 | var noteLength = (GetParameter("Note Length") / 100) * (1 / division);
61 | // var randomLength = Math.random() * ((GetParameter("Random Length") / 100) * (1 / division));
62 | // var randomDelay = Math.random() * ((GetParameter("Random Delay") / 100) * (1 / division));
63 | // var randomOctave = Math.floor(Math.random() * GetParameter("Random Octave")) * 12;
64 |
65 | // calculate beat to schedule
66 | var lookAheadEnd = musicInfo.blockEndBeat;
67 | var nextBeat = Math.ceil(musicInfo.blockStartBeat * division) / division;
68 | // var nextBeat = musicInfo.blockStartBeat;
69 |
70 | // when cycling, find the beats that wrap around the last buffer
71 | if (musicInfo.cycling && lookAheadEnd >= musicInfo.rightCycleBeat && lookAheadEnd >= musicInfo.rightCycleBeat) {
72 | var cycleBeats = musicInfo.rightCycleBeat - musicInfo.leftCycleBeat;
73 | var cycleEnd = lookAheadEnd - cycleBeats;
74 | }
75 |
76 | var state = GetParameter("Reset");
77 | if (state == 1) {
78 | Reset();
79 | }
80 |
81 | // loop through the beats that fall within this buffer
82 | while ((nextBeat >= musicInfo.blockStartBeat && nextBeat < lookAheadEnd && state == 0)
83 | // including beats that wrap around the cycle point
84 | || (musicInfo.cycling && nextBeat < cycleEnd)) {
85 |
86 | // adjust for cycle
87 | if (musicInfo.cycling && nextBeat >= musicInfo.rightCycleBeat)
88 | nextBeat -= cycleBeats;
89 |
90 | // calculate step
91 | var step = Math.floor(nextBeat / (1 / division) - division);
92 | var chosenNote = chooseNote(noteOrder, step);
93 |
94 | // send events
95 | var noteOn = new NoteOn(chosenNote);
96 | // noteOn.pitch = MIDI.normalizeData(noteOn.pitch + randomOctave);
97 | noteOn.pitch = MIDI.normalizeData(noteOn.pitch);
98 | // noteOn.sendAtBeat(nextBeat + randomDelay);
99 | noteOn.sendAtBeat(nextBeat);
100 | var noteOff = new NoteOff(noteOn);
101 | // noteOff.sendAtBeat(nextBeat + randomDelay + noteLength + randomLength);
102 | noteOff.sendAtBeat(nextBeat + noteLength);
103 |
104 | // advance to next beat
105 | nextBeat += 0.001;
106 | nextBeat = Math.ceil(nextBeat * division) / division;
107 | }
108 | }
109 | }
110 |
111 | function Reset() {
112 | NeedsTimingInfo = true;
113 | activeNotes = [];
114 | SetParameter ("Reset", 0);
115 | }
116 |
117 | //-----------------------------------------------------------------------------
118 | var noteOrders = ["up", "down", "random"];
119 |
120 | function chooseNote(noteOrder, step) {
121 | var order = noteOrders[noteOrder];
122 | var length = activeNotes.length
123 | if (order == "up") return activeNotes[step % length];
124 | if (order == "down") return activeNotes[Math.abs(step % length - (length - 1))];
125 | if (order == "random") return activeNotes[Math.floor(Math.random() * length)];
126 | else return 0;
127 | }
128 |
129 | //-----------------------------------------------------------------------------
130 | // var PluginParameters =
131 | // [
132 | // {name:"Beat Division", type:"linear",
133 | // minValue:1, maxValue:16, numberOfSteps:15, defaultValue:1},
134 | //
135 | // {name:"Note Order", type:"menu", valueStrings:noteOrders,
136 | // minValue:0, maxValue:2, numberOfSteps: 3, defaultValue:0},
137 | //
138 | // {name:"Note Length", unit:"%", type:"linear",
139 | // minValue:1, maxValue:200, defaultValue:100.0, numberOfSteps:199},
140 | //
141 | // {name:"Random Length", unit:"%", type:"linear",
142 | // minValue:0, maxValue:200, numberOfSteps: 200, defaultValue:0},
143 | //
144 | // {name:"Random Delay", unit:"%", type:"linear",
145 | // minValue:0, maxValue:200, numberOfSteps:200, defaultValue:0},
146 | //
147 | // {name:"Random Octave", type:"linear",
148 | // minValue:1, maxValue:4, defaultValue:1, numberOfSteps:3}
149 | // ];
150 | var PluginParameters =
151 | [
152 | {name:"Beat Division", type:"linear",
153 | minValue:1, maxValue:16, numberOfSteps:15, defaultValue:1},
154 |
155 | {name:"Note Order", type:"menu", valueStrings:noteOrders,
156 | minValue:0, maxValue:2, numberOfSteps: 3, defaultValue:0},
157 |
158 | {name:"Reset", type:"menu", valueStrings:["Off", "On"],
159 | minValue:0, maxValue:1, numberOfSteps: 2, defaultValue:0},
160 |
161 | {name:"Note Length", unit:"%", type:"linear",
162 | minValue:1, maxValue:200, defaultValue:100.0, numberOfSteps:199}
163 | ];
164 |
165 | // ----------------------------------------------------------------------------
166 | // Code from plugin.js
167 |
168 | // Copy and paste this chunk of code into your script editor to create controls in your plugin
169 |
170 | // var PluginParameters = [];
171 |
172 | // Types of Plugin Parameters
173 | const LINEAR_FADER = "lin";
174 | const LOGARITHMIC_FADER = "log";
175 | const MOMENTARY_BUTTON = "momentary";
176 | const MENU = "menu";
177 | const NOT_NEEDED = "";
178 |
179 | /*
180 | To create a plugin parameter (a fader or knob that changes something is a basic way of desribing it), call the createPluginParameter function as follows:
181 | createPluginParameter("Enter a name in quotes", Enter a type from above in quotes (for example: LINEAR_FADER), Enter a minimum value, Enter a maximum value, Enter a default value, enter the number of steps, "Enter a unit in quotes", "Enter text to create a divider/header in the plug-in", Enter a list of value strings if you are creating a menu as follows: ["something", "something", "something"]);
182 | */
183 |
184 | function createPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) {
185 | if (type == MENU) {
186 | PluginParameters.push (createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings));
187 | }
188 | else {
189 | PluginParameters.push (createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text));
190 | }
191 | }
192 |
193 | function createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text) {
194 | return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text};
195 | }
196 |
197 | function createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) {
198 | return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text, valueStrings: valueStrings};
199 | }
200 |
201 | //Parameters for the plugin
202 |
--------------------------------------------------------------------------------
/Library/chords.js:
--------------------------------------------------------------------------------
1 | // Triggers chords derived from played note
2 |
3 | // Chordtypes
4 | var maj_Chord = [4, 7];
5 | var min_Chord = [3, 7];
6 | var dim_Chord = [3, 6];
7 | var maj7th_Chord = [4, 7, 11];
8 | var min7th_Chord = [3, 7, 10];
9 | var dom7th_Chord = [4, 7, 10];
10 | var dim7th_Chord = [3, 6, 10];
11 |
12 | var activeNotes = [];
13 |
14 | function HandleMIDI(event) {
15 | if (GetParameter("Flavour") == 0) {
16 | if (GetParameter("Mode") == 0) {
17 | // MAJOR
18 | switch (event.pitch % 12) {
19 | // I
20 | case (GetParameter("Root") % 12):
21 | buildChord(event, maj_Chord);
22 | break;
23 | // ii
24 | case ((GetParameter("Root") + 2) % 12):
25 | buildChord(event, min_Chord);
26 | break;
27 | // iii
28 | case ((GetParameter("Root") + 4) % 12):
29 | buildChord(event, min_Chord);
30 | break;
31 | // IV
32 | case ((GetParameter("Root") + 5) % 12):
33 | buildChord(event, maj_Chord);
34 | break;
35 | // V
36 | case ((GetParameter("Root") + 7) % 12):
37 | buildChord(event, maj_Chord);
38 | break;
39 | // vi
40 | case ((GetParameter("Root") + 9) % 12):
41 | buildChord(event, min_Chord);
42 | break;
43 | // vii°
44 | case ((GetParameter("Root") + 11) % 12):
45 | buildChord(event, dim_Chord);
46 | break;
47 | // Default
48 | default:
49 | break;
50 | }
51 | }
52 | else if (GetParameter("Mode") == 1) {
53 | // MINOR
54 | switch (event.pitch % 12) {
55 | // i
56 | case (GetParameter("Root") % 12):
57 | buildChord(event, min_Chord);
58 | break;
59 | // ii°
60 | case ((GetParameter("Root") + 2) % 12):
61 | buildChord(event, dim_Chord);
62 | break;
63 | // III
64 | case ((GetParameter("Root") + 3) % 12):
65 | buildChord(event, maj_Chord);
66 | break;
67 | // iv
68 | case ((GetParameter("Root") + 5) % 12):
69 | buildChord(event, min_Chord);
70 | break;
71 | // v
72 | case ((GetParameter("Root") + 7) % 12):
73 | buildChord(event, min_Chord);
74 | break;
75 | // VI
76 | case ((GetParameter("Root") + 8) % 12):
77 | buildChord(event, maj_Chord);
78 | break;
79 | // VII
80 | case ((GetParameter("Root") + 10) % 12):
81 | buildChord(event, maj_Chord);
82 | break;
83 | // Default
84 | default:
85 | break;
86 | }
87 | }
88 | }
89 | if (GetParameter("Flavour") == 1) {
90 | if (GetParameter("Mode") == 0) {
91 | // MAJOR
92 | switch (event.pitch % 12) {
93 | // I7
94 | case (GetParameter("Root") % 12):
95 | buildChord(event, maj7th_Chord);
96 | break;
97 | // ii7
98 | case ((GetParameter("Root") + 2) % 12):
99 | buildChord(event, min7th_Chord);
100 | break;
101 | // iii7
102 | case ((GetParameter("Root") + 4) % 12):
103 | buildChord(event, min7th_Chord);
104 | break;
105 | // IV7
106 | case ((GetParameter("Root") + 5) % 12):
107 | buildChord(event, maj7th_Chord);
108 | break;
109 | // V7
110 | case ((GetParameter("Root") + 7) % 12):
111 | buildChord(event, dom7th_Chord);
112 | break;
113 | // vi7
114 | case ((GetParameter("Root") + 9) % 12):
115 | buildChord(event, min7th_Chord);
116 | break;
117 | // vii°7
118 | case ((GetParameter("Root") + 11) % 12):
119 | buildChord(event, dim7th_Chord);
120 | break;
121 | // Default
122 | default:
123 | break;
124 | }
125 | } else if (GetParameter("Mode") == 1) {
126 | // MINOR
127 | switch (event.pitch % 12) {
128 | // i7
129 | case (GetParameter("Root") % 12):
130 | buildChord(event, min7th_Chord);
131 | break;
132 | // ii°7
133 | case ((GetParameter("Root") + 2) % 12):
134 | buildChord(event, dim7th_Chord);
135 | break;
136 | // III7
137 | case ((GetParameter("Root") + 3) % 12):
138 | buildChord(event, maj7th_Chord);
139 | break;
140 | // iv7
141 | case ((GetParameter("Root") + 5) % 12):
142 | buildChord(event, min7th_Chord);
143 | break;
144 | // v7
145 | case ((GetParameter("Root") + 7) % 12):
146 | buildChord(event, min7th_Chord);
147 | break;
148 | // VI7
149 | case ((GetParameter("Root") + 8) % 12):
150 | buildChord(event, maj7th_Chord);
151 | break;
152 | // VII7
153 | case ((GetParameter("Root") + 10) % 12):
154 | buildChord(event, dom7th_Chord);
155 | break;
156 | // Default
157 | default:
158 | break;
159 | }
160 | }
161 | }
162 | }
163 |
164 | function buildChord(root, chordtype) {
165 | if (root instanceof NoteOn) {
166 | var originalNote = new NoteOn(root);
167 | var record = {
168 | originalPitch: root.pitch,
169 | events: [originalNote]
170 | };
171 | root.send();
172 | for (var i = 0; i < chordtype.length; i++) {
173 | var harmony = new NoteOn(root);
174 | harmony.pitch += chordtype[i];
175 | record.events.push(harmony);
176 | harmony.send();
177 | }
178 | activeNotes.push(record);
179 | } else if (root instanceof NoteOff) {
180 | for (var i in activeNotes) {
181 | if (activeNotes[i].originalPitch == root.pitch) {
182 | for (var j = 0; j < activeNotes[i].events.length; j++) {
183 | var noteOff = new NoteOff(activeNotes[i].events[j]);
184 | noteOff.send();
185 | }
186 | activeNotes.splice(i, 1);
187 | break;
188 | }
189 | }
190 | }
191 | }
192 |
193 | ResetParameterDefaults = true;
194 |
195 | var PluginParameters = [{
196 | name: "Chords",
197 | type: "text"
198 | }, {
199 | name: "Root",
200 | type: "menu",
201 | valueStrings: ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"],
202 | defaultValue: 0,
203 | minValue: 0,
204 | maxValue: 11,
205 | numberOfSteps: 12
206 | }, {
207 | name: "Mode",
208 | type: "menu",
209 | valueStrings: ["Major", "Minor"],
210 | defaultValue: 0,
211 | minValue: 0,
212 | maxValue: 1,
213 | numberOfSteps: 2
214 | }, {
215 | name: "Flavour",
216 | type: "menu",
217 | valueStrings: ["Normal", "Jazzy"],
218 | defaultValue: 0,
219 | minValue: 0,
220 | maxValue: 1,
221 | numberOfSteps: 2
222 | }];
223 |
--------------------------------------------------------------------------------
/docs/quickref.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | LPX Scripts
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
Results
25 |
26 |
27 |
28 |
29 |
30 |
Global attributes and functions
31 |
32 |
33 |
NeedsTimingInfo:boolean
34 |
Defining NeedsTimingInfo as true at the global scope enables the GetTimingInfo() function
35 |
36 |
37 |
ResetParameterDefaults:boolean
38 |
Sets UI controls to default values
39 |
40 |
41 |
HandleMIDI(Event)
42 |
This function 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 this function, events pass through the plug-in unaffected.
43 |
44 |
45 |
ProcessMIDI()
46 |
This function is called once per “process block,” which is determined by the host’s audio settings (sample rate and buffer size). This function is often used in combination with the TimingInfo object to make use of timing information from the host application. To enable the GetTimingInfo feature, add NeedsTimingInfo = true at the global script level.
47 |
48 |
49 |
ParameterChanged(integer, real)
50 |
This function is called each time one of the plug-in’s parameters is set to a new value. It is also called once for each parameter when you load a plug-in setting.
51 |
52 |
53 |
Reset()
54 |
This function is called when the plugin is reset
55 |
56 |
57 |
Trace(value)
58 |
Prints a message to the console that represents the supplied value of any type
59 |
60 |
61 |
GetTimingInfo():TimingInfo
62 |
Retrieves a TimingInfo object, which contains timing information that describes the state of the host transport and the current musical tempo and meter.
63 |
64 |
65 |
GetParameter(string):real
66 |
Returns a given parameter’s current value. GetParameter() is typically called inside the HandleMIDI() or ProcessMIDI() functions.
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
Event – Base class for all events
75 |
76 |
77 |
send()
78 |
Send the event
79 |
80 |
81 |
sendAfterMilliseconds(ms:real)
82 |
Send the event after the specified value has elapsed
83 |
84 |
85 |
sendAtBeat(beat:real)
86 |
Send the event at a specific beat in the host’s timeline
87 |
88 |
89 |
sendAfterBeats(beats:real)
90 |
Similar to sendAtBeat(), but uses the beat value as a delay in beats from the current position.
91 |
92 |
93 |
trace()
94 |
Prints the event to the plug-in console
95 |
96 |
97 |
toString()
98 |
Returns a string representation of the event
99 |
100 |
101 |
channel(integer)
102 |
Sets MIDI channel 1 to 16. Note: Event.channel is an event property, rather than a method, so it may be used in expressions such as (evt.channel == 1) where evt is an instance of Event)
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
Note – Base class for note events
111 |
112 |
113 |
Note()
114 |
Constructor
115 |
116 |
117 |
toString()
118 |
Returns a String representation of the Note event.
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
NoteOn – Represents a note on event
127 |
128 |
129 |
NoteOn(Event)
130 |
Constructor
131 |
132 |
133 |
pitch(integer)
134 |
Pitch from 1–127
135 |
136 |
137 |
velocity(integer)
138 |
Velocity from 0–127. A velocity value of 0 is interpreted as a note off event, not a note on.
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
NoteOff – Represents a note off event
147 |
148 |
149 |
NoteOff(Event)
150 |
Constructor
151 |
152 |
153 |
pitch(integer)
154 |
Pitch from 1–127
155 |
156 |
157 |
velocity(integer)
158 |
Velocity from 0–127
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
PolyPressure – Represents a Polyphonic aftertouch event
167 |
168 |
169 |
PolyPressure(Event)
170 |
Constructor
171 |
172 |
173 |
pitch(integer)
174 |
Pitch from 1–127
175 |
176 |
177 |
value(integer)
178 |
Pressure value from 0–127
179 |
180 |
181 |
toString()
182 |
Returns a String representation of the PolyPressure event.
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
ControlChange – Represents a ControlChange event
191 |
192 |
193 |
ControlChange(Event)
194 |
Constructor
195 |
196 |
197 |
number(integer)
198 |
Controller number from 0–127.
199 |
200 |
201 |
value(integer)
202 |
Controller value from 0–127.
203 |
204 |
205 |
toString()
206 |
Returns a String representation of the ControlChange event.
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
ProgramChange – Represents a ProgramChange event
215 |
216 |
217 |
ProgramChange(Event)
218 |
Constructor
219 |
220 |
221 |
number(integer)
222 |
Program change number from 0–127
223 |
224 |
225 |
toString()
226 |
Returns a String representation of the ProgramChange event.
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
ChannelPressure – Represents a ChannelPressure event
235 |
236 |
237 |
ChannelPressure(Event)
238 |
Constructor
239 |
240 |
241 |
value(integer)
242 |
Aftertouch value from 0–127
243 |
244 |
245 |
toString()
246 |
Returns a String representation of the ChannelPressure event.
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
PitchBend – Represents a PitchBend event
255 |
256 |
257 |
PitchBend(Event)
258 |
Constructor
259 |
260 |
261 |
value(integer)
262 |
14-bit pitch bend value from -8192–8191. A value of 0 is center.
263 |
264 |
265 |
toString()
266 |
Returns a String representation of the PitchBend event.
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
Fader – Represents a Fader event
275 |
276 |
277 |
Fader(Event)
278 |
Constructor
279 |
280 |
281 |
value(integer)
282 |
Fader value from 0–127
283 |
284 |
285 |
toString()
286 |
Returns a String representation of the Fader event.
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
TimingInfo – Contains timing information that describes the state of the host transport and the current musical tempo and meter
295 |
296 |
297 |
playing:boolean
298 |
Value is true when the host transport is running
299 |
300 |
301 |
blockStartBeat:real
302 |
Indicates the beat position at the start of the process block
303 |
304 |
305 |
blockEndBeat:real
306 |
Indicates the beat position at the end of the process block
307 |
308 |
309 |
blockLength:real
310 |
Indicates the length of the process block in beats.
311 |
312 |
313 |
tempo:real
314 |
Indicates the host tempo.
315 |
316 |
317 |
meterNumerator:integer
318 |
Indicates the host meter numerator
319 |
320 |
321 |
meterDemoninator:integer
322 |
Indicates the host meter denominator.
323 |
324 |
325 |
cycling:boolean
326 |
Value is true when the host transport is cycling
327 |
328 |
329 |
leftCycleBeat:real
330 |
Indicates the beat position at the start of the cycle range
331 |
332 |
333 |
rightCycleBeat:real
334 |
Indicates the beat position at the end of the cycle range
29 | LPX Scripts is an open source endeavor to complement the Logic Pro Scripter Plugin. LPXscripts
30 | not only serves as a library of scripts that can be used on the plugin, but also aims to
31 | guide Logic Pro users to create their own scripts.
32 |
33 |
34 |
35 |
36 |
How to use the Library
37 |
38 |
39 | The only prerequisite to using the LPX Scripts plugins is plainly that the user must have
40 | access to the Logic Pro software. Since LPX must be purchased for use, the scripts can only
41 | work with access to the software. With that said, there is no need to understand how the
42 | plugins work to use it, meaning that the user does
43 | not need to understand the code to use the software. Once the user finds a file they
44 | would like to use, the steps are pretty simple to going about having them read by Logic Pro.
45 | The following is the step-by-step process of using the plugins:
46 |
47 |
Step 1: Locate MIDI FX
48 |
49 | Open Logic Pro X application on your computer and navigate to the inspector or mixer for the track after having selected a software instrument/MIDI instrument, where you
50 | will find the MIDI FX option.
51 |
52 | Under the MIDI FX option, locate and click on the "scripter" option.
53 |
54 |
Step 2: Open the Scripter settings
55 |
56 | The page that just appeared will be the page where you can make use of the plugin with the
57 | different options the plugin may offer. First we need to input the plugin though, so click
58 | on the "Open Script in Editor" button to continue.
59 |
60 |
61 |
Step 3: Use the Script Editor
62 |
63 | A new page will appear with some text already filling the page, this is the Script editor.
64 | To input the plugin, copy and paste the code from the plugin file in the repository into
65 | the script editor by replacing the code already in the file.
66 |
67 | Once it is placed in the script editor properly, click the button in the top right called
68 | "Run Script".
69 |
70 |
71 |
Step 4: Copy and Paste the Code
72 |
73 | Upon running the plugin, you will be brought back to the Scripter which will show you the
74 | customizable options of the specific plugin. Follow the steps to use that specific plugin
75 | and you should be all set!
76 |
77 |
78 |
79 |
80 |
81 |
Library
82 |
83 |
84 | The following is a list of plugins currently available in the library. All files can be
85 | found in the
86 | /Library folder of the repository.
87 |
Constructs a sequence of notes triggered relative to the base note
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
Reference Guide
117 |
118 |
119 |
120 |
121 |
122 |
124 |
Global attributes and functions
125 |
126 |
127 |
NeedsTimingInfo:boolean
128 |
Defining NeedsTimingInfo as true at the global scope enables the GetTimingInfo() function
129 |
130 |
131 |
ResetParameterDefaults:boolean
132 |
Sets UI controls to default values
133 |
134 |
135 |
HandleMIDI(Event)
136 |
This function 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 this function, events pass through the plug-in unaffected.
137 |
138 |
139 |
ProcessMIDI()
140 |
This function is called once per “process block,” which is determined by the host’s audio settings (sample rate and buffer size). This function is often used in combination with the TimingInfo object to make use of timing information from the host application. To enable the GetTimingInfo feature, add NeedsTimingInfo = true at the global script level.
141 |
142 |
143 |
ParameterChanged(integer, real)
144 |
This function is called each time one of the plug-in’s parameters is set to a new value. It is also called once for each parameter when you load a plug-in setting.
145 |
146 |
147 |
Reset()
148 |
This function is called when the plugin is reset. Can be overriden.
149 |
150 |
151 |
Trace(value)
152 |
Prints a message to the console that represents the supplied value of any type. Similar to console.log(value) in regular javascript
153 |
154 |
155 |
GetTimingInfo():TimingInfo
156 |
Retrieves a TimingInfo object, which contains timing information that describes the state of the host transport and the current musical tempo and meter.
157 |
158 |
159 |
GetParameter(string):real
160 |
Returns a given parameter’s current value. GetParameter() is typically called inside the HandleMIDI() or ProcessMIDI() functions.
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
Event – Base class for all events. Call functions using dot notation.
169 |
170 |
171 |
send()
172 |
Send the event
173 |
174 |
175 |
sendAfterMilliseconds(ms:real)
176 |
Send the event after the specified value has elapsed
177 |
178 |
179 |
sendAtBeat(beat:real)
180 |
Send the event at a specific beat in the host’s timeline
181 |
182 |
183 |
sendAfterBeats(beats:real)
184 |
Similar to sendAtBeat(), but uses the beat value as a delay in beats from the current position.
185 |
186 |
187 |
trace()
188 |
Prints the event to the plug-in console
189 |
190 |
191 |
toString()
192 |
Returns a string representation of the event
193 |
194 |
195 |
channel(integer)
196 |
Sets MIDI channel 1 to 16. Note: Event.channel is an event property, rather than a method, so it may be used in expressions such as (evt.channel == 1) where evt is an instance of Event)
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
Note Events
205 |
206 |
207 |
Note()
208 |
Constructor
209 |
210 |
211 |
toString()
212 |
Returns a String representation of the Note event.
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
NoteOn Events
221 |
222 |
223 |
NoteOn(Event)
224 |
Constructor
225 |
226 |
227 |
pitch(integer)
228 |
Pitch from 1–127
229 |
230 |
231 |
velocity(integer)
232 |
Velocity from 0–127. A velocity value of 0 is interpreted as a note off event, not a note on.
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
NoteOff Events
241 |
242 |
243 |
NoteOff(Event)
244 |
Constructor
245 |
246 |
247 |
pitch(integer)
248 |
Pitch from 1–127
249 |
250 |
251 |
velocity(integer)
252 |
Velocity from 0–127
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
PolyPressure – Represents a Polyphonic aftertouch event
261 |
262 |
263 |
PolyPressure(Event)
264 |
Constructor
265 |
266 |
267 |
pitch(integer)
268 |
Pitch from 1–127
269 |
270 |
271 |
value(integer)
272 |
Pressure value from 0–127
273 |
274 |
275 |
toString()
276 |
Returns a String representation of the PolyPressure event.
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
ControlChange – Represents a ControlChange event
285 |
286 |
287 |
ControlChange(Event)
288 |
Constructor
289 |
290 |
291 |
number(integer)
292 |
Controller number from 0–127.
293 |
294 |
295 |
value(integer)
296 |
Controller value from 0–127.
297 |
298 |
299 |
toString()
300 |
Returns a String representation of the ControlChange event.
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
ProgramChange – Represents a ProgramChange event
309 |
310 |
311 |
ProgramChange(Event)
312 |
Constructor
313 |
314 |
315 |
number(integer)
316 |
Program change number from 0–127
317 |
318 |
319 |
toString()
320 |
Returns a String representation of the ProgramChange event.
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
ChannelPressure – Represents a ChannelPressure event
329 |
330 |
331 |
ChannelPressure(Event)
332 |
Constructor
333 |
334 |
335 |
value(integer)
336 |
Aftertouch value from 0–127
337 |
338 |
339 |
toString()
340 |
Returns a String representation of the ChannelPressure event.
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
PitchBend – Represents a PitchBend event
349 |
350 |
351 |
PitchBend(Event)
352 |
Constructor
353 |
354 |
355 |
value(integer)
356 |
14-bit pitch bend value from -8192–8191. A value of 0 is center.
357 |
358 |
359 |
toString()
360 |
Returns a String representation of the PitchBend event.
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
Fader – Represents a Fader event
369 |
370 |
371 |
Fader(Event)
372 |
Constructor
373 |
374 |
375 |
value(integer)
376 |
Fader value from 0–127
377 |
378 |
379 |
toString()
380 |
Returns a String representation of the Fader event.
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
TimingInfo – Contains timing information that describes the state of the host transport and the current musical tempo and meter
389 |
390 |
391 |
playing:boolean
392 |
Value is true when the host transport is running
393 |
394 |
395 |
blockStartBeat:real
396 |
Indicates the beat position at the start of the process block
397 |
398 |
399 |
blockEndBeat:real
400 |
Indicates the beat position at the end of the process block
401 |
402 |
403 |
blockLength:real
404 |
Indicates the length of the process block in beats.
405 |
406 |
407 |
tempo:real
408 |
Indicates the host tempo.
409 |
410 |
411 |
meterNumerator:integer
412 |
Indicates the host meter numerator
413 |
414 |
415 |
meterDemoninator:integer
416 |
Indicates the host meter denominator.
417 |
418 |
419 |
cycling:boolean
420 |
Value is true when the host transport is cycling
421 |
422 |
423 |
leftCycleBeat:real
424 |
Indicates the beat position at the start of the cycle range
425 |
426 |
427 |
rightCycleBeat:real
428 |
Indicates the beat position at the end of the cycle range