├── .gitignore ├── docs ├── .DS_Store ├── images │ ├── .DS_Store │ ├── Scripter.png │ ├── Settings.png │ ├── Sidebar.png │ └── ScriptEditor.png ├── package-lock.json ├── style.css ├── menu.html ├── style.js ├── quickref.html └── index.html ├── RESOURCES.md ├── LICENSE.md ├── Library ├── plugin.js ├── sequencer.js ├── arpeggiator.js ├── repeater.js └── chords.js ├── CHANGELOG.md ├── README.md ├── CODE_OF_CONDUCT.md └── CONTRIBUTING.md /.gitignore: -------------------------------------------------------------------------------- 1 | test.js 2 | -------------------------------------------------------------------------------- /docs/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kabirnagral/LPXscripts/HEAD/docs/.DS_Store -------------------------------------------------------------------------------- /docs/images/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kabirnagral/LPXscripts/HEAD/docs/images/.DS_Store -------------------------------------------------------------------------------- /docs/images/Scripter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kabirnagral/LPXscripts/HEAD/docs/images/Scripter.png -------------------------------------------------------------------------------- /docs/images/Settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kabirnagral/LPXscripts/HEAD/docs/images/Settings.png -------------------------------------------------------------------------------- /docs/images/Sidebar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kabirnagral/LPXscripts/HEAD/docs/images/Sidebar.png -------------------------------------------------------------------------------- /docs/images/ScriptEditor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kabirnagral/LPXscripts/HEAD/docs/images/ScriptEditor.png -------------------------------------------------------------------------------- /docs/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "jquery": { 6 | "version": "3.3.1", 7 | "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz", 8 | "integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /RESOURCES.md: -------------------------------------------------------------------------------- 1 | # Resources 2 | 3 | ## Contents 4 | 5 | [Logic Pro Scripter Plugin](#logic-pro-scripter-plugin) 6 | 7 | [Git](#git) 8 | 9 | [GitHub](#github) 10 | 11 | [Accessibility](#accessibility) 12 | 13 | ## Logic Pro Scripter Plugin 14 | 15 | [Official Guide on the Logic Pro Scripter Plugin](http://help.apple.com/logicpro-effects/mac/10.3/#/lgce728c68f6) 16 | 17 | ## Git 18 | 19 | [Guide](http://rogerdudler.github.io/git-guide/) 20 | 21 | ## GitHub 22 | 23 | You should be able to find solutions to any GitHub problems you run into using the guide. The subsequent links are for specific procedures on GitHub 24 | 25 | [Guide](https://help.github.com/) 26 | 27 | [Forking a Repository](https://help.github.com/articles/fork-a-repo/) 28 | 29 | [Pull Requests](http://help.github.com/pull-requests/) 30 | 31 | ## Accessibility 32 | 33 | [Web Accessibility Inititative Guide](https://www.w3.org/WAI/) 34 | 35 | The A11Y Project has great [resources](https://a11yproject.com/resources) on accessibility. 36 | -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | body,h1,h2,h3,h4,h5 2 | { 3 | font-family: "Poppins", sans-serif 4 | } 5 | 6 | body 7 | { 8 | font-size:16px; 9 | } 10 | .w3-half img 11 | { 12 | margin-bottom:-6px;margin-top:16px;opacity:0.8;cursor:pointer 13 | } 14 | .w3-half img:hover 15 | { 16 | opacity:1 17 | } 18 | #mySidebar 19 | { 20 | z-index:3; 21 | width:300px; 22 | font-weight:bold; 23 | } 24 | #closeMenu 25 | { 26 | width:100%; 27 | font-size:22px; 28 | } 29 | #pageContent 30 | { 31 | margin-left:320px; 32 | margin-right:20px; 33 | margin-top: 20px; 34 | background-color: #cbcbcf; 35 | padding: 50px; 36 | } 37 | 38 | #resultsTable 39 | { 40 | overflow-x: scroll; 41 | overflow-y: scroll; 42 | } 43 | 44 | p 45 | { 46 | line-height: 2.0; 47 | text-align: justify; 48 | } 49 | 50 | th 51 | { 52 | cursor: pointer; 53 | } 54 | 55 | /* 56 | #resultsTable{ 57 | border: 1px solid black; 58 | }*/ 59 | 60 | /*tr.bottom{ 61 | border-bottom: 1px solid #3F51B5; 62 | } 63 | 64 | tr.item{ 65 | border-bottom: 1px dashed #3F51B5; 66 | }*/ 67 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | ===================== 3 | 4 | Copyright © 2018 Kabir Nagral 5 | 6 | Permission is hereby granted, free of charge, to any person 7 | obtaining a copy of this software and associated documentation 8 | files (the “Software”), to deal in the Software without 9 | restriction, including without limitation the rights to use, 10 | copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the 12 | Software is furnished to do so, subject to the following 13 | conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 25 | OTHER DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /Library/plugin.js: -------------------------------------------------------------------------------- 1 | // Copy and paste this chunk of code into your script editor to create controls in your plugin 2 | 3 | var NeedsTimingInfo = true; 4 | 5 | var PluginParameters = []; 6 | 7 | // Types of Plugin Parameters 8 | const LINEAR_FADER = "lin"; 9 | const LOGARITHMIC_FADER = "log"; 10 | const MOMENTARY_BUTTON = "momentary"; 11 | const MENU = "menu"; 12 | const NOT_NEEDED = ""; 13 | 14 | /* 15 | 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: 16 | 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"]); 17 | */ 18 | 19 | function createPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { 20 | if (type == MENU) { 21 | PluginParameters.push (createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings)); 22 | } 23 | else { 24 | PluginParameters.push (createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text)); 25 | } 26 | } 27 | 28 | function createBasicPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text) { 29 | return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text}; 30 | } 31 | 32 | function createMenuPluginParameter (name, type, minValue, maxValue, defaultValue, numberOfSteps, unit, text, valueStrings) { 33 | return {name: name, type: type, minValue: minValue, maxValue: maxValue, numberOfSteps: numberOfSteps, unit: unit, text: text, valueStrings: valueStrings}; 34 | } 35 | 36 | //Parameters for the plugin 37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## Contents 4 | 5 | [Features](#features) 6 | 7 | [Daily Commits](#daily-commits) 8 | 9 | ## Features 10 | 11 | ## Daily Commits 12 | 13 | To format this for the majority of our contributors and our international contributor base, the date format will be (DD/MM/YYYY). We apologize in advance to our contributors who use alternative forms of date formats. The dates will be in descending order. 14 | 15 | The format for daily commits should be as follows: 16 | 17 | A clear and coherent message for whatever was committed. Files edited: List of files edited (it isn't necessary to include markdown files unless there are significant changes). 18 | 19 | #### 21/02/2018 20 | 21 | Updated the webite and did researched website accessibility. Files edited: index.html 22 | 23 | #### 20/02/2018 24 | 25 | Updated the scripts with comments and renamed one of the scripts. Also did research on making the website accessible. Files edited: All 26 | 27 | #### 19/02/2018 28 | 29 | Merged the [pull request](https://github.com/kabirnagral/LPXscripts/pull/10) from Pyeskyhigh. Edited index.html to make images appear. Files edited: index.html, [the other files edited in the pull request that was merged](https://github.com/kabirnagral/LPXscripts/pull/10/files). 30 | 31 | #### 08/02/2018 32 | 33 | Refined the sequencer.js plugin script to work. Files edited: sequencer.js 34 | 35 | #### 07/02/2018 36 | 37 | Figured out how to make the sequencer.js plugin script work. Files edited: sequencer.js 38 | 39 | #### 06/02/2018 40 | 41 | Created some scripts. Files edited: arpeggiator.js, loopPedal.js, sequencer.js, chords.js, plugin.js 42 | 43 | #### 31/01/2018 44 | 45 | Created a sidebar structure for the guide website. Files edited: menu.html, style.js, style.css 46 | 47 | #### 30/01/2018 48 | 49 | Started creating a framework for the guide website. Files edited: index.html menu.html, about.html, quickref.html, style.css, style.js 50 | 51 | #### 26/01/2018 52 | 53 | Created a Change Log. Files edited: CHANGELOG.md 54 | 55 | #### 29/01/2018 56 | 57 | Added an image to assets. Started working on functions for the library. Files Edited: plugin.js, strum.js, assets/images 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LPXscripts 2 | 3 | ## About 4 | 5 | LPXscripts is an open source endeavor to complement the Logic Pro Scripter Plugin. It has two major components: a library of scripts for the plugin, and a [website](https://kabirnagral.github.io/LPXscripts/) that serves as a guide to the plugin. 6 | 7 | ## Library 8 | 9 | LPXscripts has a library of functions written in Javascript that are meant to be used as user-created scripts for the Logic Pro scripter plugin. 10 | 11 | ### Locating the Library 12 | 13 | The library of scripts can be found in the *Library* folder. 14 | 15 | ### Using the Library 16 | 17 | Open the *Library* folder. Open one of the javascript files (the files with the *.js* file format). Copy the code from the file and paste it into the plugin's Script Editor. Run the script and you're good to go! 18 | 19 | Refer to [this guide](https://kabirnagral.github.io/LPXscripts/#how-to-use-library) for more! 20 | 21 | ### Contributing to the Library 22 | 23 | Want to contribute to the library? See the [CONTRIBUTING.md](https://github.com/kabirnagral/LPXscripts/blob/master/CONTRIBUTING.md) file to read more about how to contribute. 24 | 25 | ## Guide 26 | 27 | LPXscripts also has a guide to the Logic Pro Scipter plugin in the form of a website. 28 | 29 | ### Locating the Guide 30 | 31 | The guide can be found on the [website](https://kabirnagral.github.io/LPXscripts/). 32 | 33 | ### Using the Guide 34 | 35 | Navigate to the [website](https://kabirnagral.github.io/LPXscripts/). 36 | 37 | If you have any feedback or suggestions, please raise an issue. (Don't know how to raise an issue? Remember that you don't know *yet*. See [this guide](https://help.github.com/articles/creating-an-issue/) on raising issues.) 38 | 39 | ### Contributing to the Guide 40 | 41 | Want to contribute to the guide website? See the [CONTRIBUTING.md](https://github.com/kabirnagral/LPXscripts/blob/master/CONTRIBUTING.md) file to read more about how to contribute. 42 | 43 | ## Contributing 44 | 45 | This project was made to be a collaborative effort. Contributions are welcomed and much appreciated. See the [CONTRIBUTING.md](https://github.com/kabirnagral/LPXscripts/blob/master/CONTRIBUTING.md) file to read more about how to contribute. 46 | 47 | ## Link to website 48 | 49 | Visit the website at https://kabirnagral.github.io/LPXscripts/. 50 | -------------------------------------------------------------------------------- /docs/menu.html: -------------------------------------------------------------------------------- 1 | 47 | 48 | 49 |
50 | 51 | LPX Scripts 52 |
53 | 54 | 55 |
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 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 |
Global attributes and functions
NeedsTimingInfo:booleanDefining NeedsTimingInfo as true at the global scope enables the GetTimingInfo() function
ResetParameterDefaults:booleanSets UI controls to default values
HandleMIDI(Event)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.
ProcessMIDI()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.
ParameterChanged(integer, real)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.
Reset()This function is called when the plugin is reset
Trace(value)Prints a message to the console that represents the supplied value of any type
GetTimingInfo():TimingInfoRetrieves a TimingInfo object, which contains timing information that describes the state of the host transport and the current musical tempo and meter.
GetParameter(string):realReturns a given parameter’s current value. GetParameter() is typically called inside the HandleMIDI() or ProcessMIDI() functions.
70 | 71 |

72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 |
Event – Base class for all events
send()Send the event
sendAfterMilliseconds(ms:real)Send the event after the specified value has elapsed
sendAtBeat(beat:real)Send the event at a specific beat in the host’s timeline
sendAfterBeats(beats:real)Similar to sendAtBeat(), but uses the beat value as a delay in beats from the current position.
trace()Prints the event to the plug-in console
toString()Returns a string representation of the event
channel(integer)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)
106 | 107 |

108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 |
Note – Base class for note events
Note()Constructor
toString()Returns a String representation of the Note event.
122 | 123 |

124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 |
NoteOn – Represents a note on event
NoteOn(Event)Constructor
pitch(integer)Pitch from 1–127
velocity(integer)Velocity from 0–127. A velocity value of 0 is interpreted as a note off event, not a note on.
142 | 143 |

144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 |
NoteOff – Represents a note off event
NoteOff(Event)Constructor
pitch(integer)Pitch from 1–127
velocity(integer)Velocity from 0–127
162 | 163 |

164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 |
PolyPressure – Represents a Polyphonic aftertouch event
PolyPressure(Event)Constructor
pitch(integer)Pitch from 1–127
value(integer)Pressure value from 0–127
toString()Returns a String representation of the PolyPressure event.
186 | 187 |

188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 |
ControlChange – Represents a ControlChange event
ControlChange(Event)Constructor
number(integer)Controller number from 0–127.
value(integer)Controller value from 0–127.
toString()Returns a String representation of the ControlChange event.
210 | 211 |

212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 |
ProgramChange – Represents a ProgramChange event
ProgramChange(Event)Constructor
number(integer)Program change number from 0–127
toString()Returns a String representation of the ProgramChange event.
230 | 231 |

232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 |
ChannelPressure – Represents a ChannelPressure event
ChannelPressure(Event)Constructor
value(integer)Aftertouch value from 0–127
toString()Returns a String representation of the ChannelPressure event.
250 | 251 |

252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 |
PitchBend – Represents a PitchBend event
PitchBend(Event)Constructor
value(integer)14-bit pitch bend value from -8192–8191. A value of 0 is center.
toString()Returns a String representation of the PitchBend event.
270 | 271 |

272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 |
Fader – Represents a Fader event
Fader(Event)Constructor
value(integer)Fader value from 0–127
toString()Returns a String representation of the Fader event.
290 | 291 |

292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 |
TimingInfo – Contains timing information that describes the state of the host transport and the current musical tempo and meter
playing:booleanValue is true when the host transport is running
blockStartBeat:realIndicates the beat position at the start of the process block
blockEndBeat:realIndicates the beat position at the end of the process block
blockLength:realIndicates the length of the process block in beats.
tempo:realIndicates the host tempo.
meterNumerator:integerIndicates the host meter numerator
meterDemoninator:integerIndicates the host meter denominator.
cycling:booleanValue is true when the host transport is cycling
leftCycleBeat:realIndicates the beat position at the start of the cycle range
rightCycleBeat:real Indicates the beat position at the end of the cycle range
338 | 339 |

340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 |
MIDI – Contains class-level variables and functions (you don’t instantiate MIDI).
_noteNames:string[]Contains names such as C and G# for all 128 MIDI notes
_ccNames:string[]Contains names such as Expression and Sustain for all 128 MIDI controller numbers
noteNumber(string)Returns the MIDI note number for a given note name. For example: C3 or B#2. Flats not permitted.
noteName(real)Returns the name for a given MIDI note number.
ccName(real)Returns the controller name for a given controller number
allNotesOff()Sends the all notes off message on all MIDI channels
normalizeStatus(real)Normalizes a value to the safe range of MIDI status bytes (128–239)
normalizeChannel(real)Normalizes a value to the safe range of MIDI channels (1–16)
normalizeData(real)Normalizes a value to the safe range of MIDI data bytes (0–127)
_sendEventOnAllChannels(Event)Sends a given event to all MIDI channels
386 | 387 |
388 |
389 |
390 | 391 | 392 | 393 | -------------------------------------------------------------------------------- /docs/index.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 | 25 |
26 |

LPX Scripts

27 |

A Guide To The Logic Pro Scripter Plugin

28 |

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 |

88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
arpeggiator.jsAllows users to create a sequence that keeps repeating. Example use case: to test out melodies.
chords.jsTriggers chords derived from played note
repeater.jsRepeats note that is played with specified beat divisions
plugin.jsCopy and paste this chunk of code into your script editor to create controls in your plugin
sequencer.jsConstructs a sequence of notes triggered relative to the base note
112 |
113 |
114 | 115 |
116 |

Reference Guide

117 |
118 | 119 | 120 | 121 |
122 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 |
Global attributes and functions
NeedsTimingInfo:booleanDefining NeedsTimingInfo as true at the global scope enables the GetTimingInfo() function
ResetParameterDefaults:booleanSets UI controls to default values
HandleMIDI(Event)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.
ProcessMIDI()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.
ParameterChanged(integer, real)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.
Reset()This function is called when the plugin is reset. Can be overriden.
Trace(value)Prints a message to the console that represents the supplied value of any type. Similar to console.log(value) in regular javascript
GetTimingInfo():TimingInfoRetrieves a TimingInfo object, which contains timing information that describes the state of the host transport and the current musical tempo and meter.
GetParameter(string):realReturns a given parameter’s current value. GetParameter() is typically called inside the HandleMIDI() or ProcessMIDI() functions.
164 | 165 |

166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 |
Event – Base class for all events. Call functions using dot notation.
send()Send the event
sendAfterMilliseconds(ms:real)Send the event after the specified value has elapsed
sendAtBeat(beat:real)Send the event at a specific beat in the host’s timeline
sendAfterBeats(beats:real)Similar to sendAtBeat(), but uses the beat value as a delay in beats from the current position.
trace()Prints the event to the plug-in console
toString()Returns a string representation of the event
channel(integer)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)
200 | 201 |

202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 |
Note Events
Note()Constructor
toString()Returns a String representation of the Note event.
216 | 217 |

218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 |
NoteOn Events
NoteOn(Event)Constructor
pitch(integer)Pitch from 1–127
velocity(integer)Velocity from 0–127. A velocity value of 0 is interpreted as a note off event, not a note on.
236 | 237 |

238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 |
NoteOff Events
NoteOff(Event)Constructor
pitch(integer)Pitch from 1–127
velocity(integer)Velocity from 0–127
256 | 257 |

258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 |
PolyPressure – Represents a Polyphonic aftertouch event
PolyPressure(Event)Constructor
pitch(integer)Pitch from 1–127
value(integer)Pressure value from 0–127
toString()Returns a String representation of the PolyPressure event.
280 | 281 |

282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 |
ControlChange – Represents a ControlChange event
ControlChange(Event)Constructor
number(integer)Controller number from 0–127.
value(integer)Controller value from 0–127.
toString()Returns a String representation of the ControlChange event.
304 | 305 |

306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 |
ProgramChange – Represents a ProgramChange event
ProgramChange(Event)Constructor
number(integer)Program change number from 0–127
toString()Returns a String representation of the ProgramChange event.
324 | 325 |

326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 |
ChannelPressure – Represents a ChannelPressure event
ChannelPressure(Event)Constructor
value(integer)Aftertouch value from 0–127
toString()Returns a String representation of the ChannelPressure event.
344 | 345 |

346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 |
PitchBend – Represents a PitchBend event
PitchBend(Event)Constructor
value(integer)14-bit pitch bend value from -8192–8191. A value of 0 is center.
toString()Returns a String representation of the PitchBend event.
364 | 365 |

366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 |
Fader – Represents a Fader event
Fader(Event)Constructor
value(integer)Fader value from 0–127
toString()Returns a String representation of the Fader event.
384 | 385 |

386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 |
TimingInfo – Contains timing information that describes the state of the host transport and the current musical tempo and meter
playing:booleanValue is true when the host transport is running
blockStartBeat:realIndicates the beat position at the start of the process block
blockEndBeat:realIndicates the beat position at the end of the process block
blockLength:realIndicates the length of the process block in beats.
tempo:realIndicates the host tempo.
meterNumerator:integerIndicates the host meter numerator
meterDemoninator:integerIndicates the host meter denominator.
cycling:booleanValue is true when the host transport is cycling
leftCycleBeat:realIndicates the beat position at the start of the cycle range
rightCycleBeat:real Indicates the beat position at the end of the cycle range
432 | 433 |

434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 |
MIDI – Contains class-level variables and functions (you don’t instantiate MIDI).
_noteNames:string[]Contains names such as C and G# for all 128 MIDI notes
_ccNames:string[]Contains names such as Expression and Sustain for all 128 MIDI controller numbers
noteNumber(string)Returns the MIDI note number for a given note name. For example: C3 or B#2. Flats not permitted.
noteName(real)Returns the name for a given MIDI note number.
ccName(real)Returns the controller name for a given controller number
allNotesOff()Sends the all notes off message on all MIDI channels
normalizeStatus(real)Normalizes a value to the safe range of MIDI status bytes (128–239)
normalizeChannel(real)Normalizes a value to the safe range of MIDI channels (1–16)
normalizeData(real)Normalizes a value to the safe range of MIDI data bytes (0–127)
_sendEventOnAllChannels(Event)Sends a given event to all MIDI channels
480 | 481 |
482 |
483 | 484 |
485 |

Resources

486 |
487 | 488 | 489 | Logic Pro X Scripter Manual from Apple 490 | 491 | 492 |
493 | 494 |
495 | 496 | 497 | --------------------------------------------------------------------------------