├── .eslintignore ├── .prettierignore ├── gulpfile.js ├── .gitignore ├── keymaps └── foxdot.json ├── .prettierrc.yml ├── tasks ├── generate-autocomplete.js └── generate-autocomplete.py ├── tsconfig.json ├── src ├── autocomplete.ts ├── logging.ts ├── index.ts └── foxdot.ts ├── lib ├── autocomplete.js ├── logging.js ├── index.js └── foxdot.js ├── Readme.md ├── styles └── foxdot.less ├── .eslintrc.yml ├── package.json ├── menus └── foxdot.json └── data └── autocomplete.json /.eslintignore: -------------------------------------------------------------------------------- 1 | lib 2 | node_modules 3 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /lib 2 | /package-lock.json 3 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | require('require-dir')('tasks'); 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /*.log 2 | /npm-debug.log* 3 | /node_modules 4 | -------------------------------------------------------------------------------- /keymaps/foxdot.json: -------------------------------------------------------------------------------- 1 | { 2 | ".workspace .editor[data-grammar='source python']": { 3 | "ctrl-alt-f": "foxdot:toggle", 4 | "ctrl-enter": "foxdot:evaluate-blocks", 5 | "ctrl-alt-enter": "foxdot:evaluate-file", 6 | "alt-enter": "foxdot:evaluate-lines", 7 | "ctrl-.": "foxdot:clear-clock" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | overrides: 2 | - files: 3 | - "*.js" 4 | - "*.less" 5 | - "*.ts" 6 | options: 7 | arrowParens: always 8 | singleQuote: true 9 | trailingComma: es5 10 | useTabs: true 11 | - files: 12 | - "*.json" 13 | - "*.yml" 14 | options: 15 | tabWidth: 2 16 | -------------------------------------------------------------------------------- /tasks/generate-autocomplete.js: -------------------------------------------------------------------------------- 1 | const { spawn } = require('child_process'); 2 | const gulp = require('gulp'); 3 | 4 | gulp.task('generate-autocomplete', () => { 5 | return new Promise((resolve, reject) => { 6 | const pythonPath = process.env.PYTHONPATH || 'python'; 7 | const childProcess = spawn(pythonPath, ['tasks/generate-autocomplete.py']); 8 | 9 | childProcess.on('close', (code) => { 10 | if (code) { 11 | return reject(`Python process exited with code ${code}.`); 12 | } 13 | 14 | return resolve(); 15 | }); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": false, 4 | "esModuleInterop": true, 5 | "experimentalDecorators": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "lib": ["DOM", "ESNext", "ESNext.AsyncIterable"], 8 | "module": "commonjs", 9 | "moduleResolution": "node", 10 | "noFallthroughCasesInSwitch": true, 11 | "noImplicitReturns": true, 12 | "outDir": "./lib", 13 | "rootDir": "./src", 14 | "sourceMap": false, 15 | "strict": true, 16 | "target": "ES2015" 17 | }, 18 | "include": ["./src/**/*"] 19 | } 20 | -------------------------------------------------------------------------------- /src/autocomplete.ts: -------------------------------------------------------------------------------- 1 | const suggestions = require('../data/autocomplete') as Record< 2 | string, 3 | unknown 4 | >[]; 5 | 6 | export default { 7 | disableForSelector: '.source.python .comment', 8 | enabled: false, 9 | filterSuggestions: true, 10 | 11 | getSuggestions({ prefix }: { prefix: string }) { 12 | if (!this.enabled) { 13 | return null; 14 | } 15 | 16 | const suggestionsWithReplacementPrefixes = suggestions.map( 17 | (suggestion) => ({ 18 | ...suggestion, 19 | replacementPrefix: prefix, 20 | }) 21 | ); 22 | return suggestionsWithReplacementPrefixes; 23 | }, 24 | 25 | inclusionPriority: 10, 26 | selector: '.source.python', 27 | suggestionPriority: 10, 28 | }; 29 | -------------------------------------------------------------------------------- /lib/autocomplete.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const suggestions = require('../data/autocomplete'); 4 | exports.default = { 5 | disableForSelector: '.source.python .comment', 6 | enabled: false, 7 | filterSuggestions: true, 8 | getSuggestions({ prefix }) { 9 | if (!this.enabled) { 10 | return null; 11 | } 12 | const suggestionsWithReplacementPrefixes = suggestions.map((suggestion) => (Object.assign(Object.assign({}, suggestion), { replacementPrefix: prefix }))); 13 | return suggestionsWithReplacementPrefixes; 14 | }, 15 | inclusionPriority: 10, 16 | selector: '.source.python', 17 | suggestionPriority: 10, 18 | }; 19 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # FoxDot interface for Atom 2 | 3 | See [FoxDot's repository](https://github.com/Qirky/FoxDot) for installation and usage instructions. 4 | 5 | It basically works like the native interface, with some extras: 6 | 7 | - Multiple cursors are executed in order of creation. 8 | - Can evaluate the entire file. 9 | - Autocompletion. 10 | 11 | ## Start livecoding 12 | 13 | This only works in the scope of python files. 14 | 15 | **Toggle FoxDot** (`ctrl-alt-f`) in order to start it. 16 | 17 | ## Key bindings 18 | 19 | | Binding | Command | 20 | | - | - | 21 | | `ctrl-alt-f` | Toggle | 22 | | `ctrl-enter` | Evaluate block(s) | 23 | | `ctrl-alt-enter` | Evaluate file | 24 | | `alt-enter` | Evaluate line(s) | 25 | | `ctrl-.` | Clear clock | 26 | -------------------------------------------------------------------------------- /styles/foxdot.less: -------------------------------------------------------------------------------- 1 | @import 'syntax-variables'; 2 | 3 | @keyframes foxdot-flash { 4 | from { 5 | opacity: 1; 6 | } 7 | to { 8 | opacity: 0; 9 | } 10 | } 11 | 12 | atom-text-editor.editor { 13 | .highlight.foxdot-flash .region { 14 | animation: foxdot-flash 300ms linear forwards; 15 | background-color: @syntax-selection-flash-color; 16 | z-index: -2; 17 | } 18 | } 19 | 20 | atom-pane div.foxdot-logger { 21 | padding: 3px 10px; 22 | overflow: scroll; 23 | 24 | > pre { 25 | font-family: Consolas, monospace; 26 | font-size: 14px; 27 | margin-bottom: 2px; 28 | white-space: pre-wrap; 29 | word-break: keep-all; 30 | } 31 | 32 | > .error { 33 | color: @text-color-error; 34 | } 35 | 36 | > .stdin { 37 | font-style: italic; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | env: 2 | es2020: true 3 | node: true 4 | extends: 5 | - eslint:recommended 6 | - prettier 7 | - plugin:import/errors 8 | - plugin:import/warnings 9 | overrides: 10 | - files: "src/**/*.ts" 11 | extends: 12 | - prettier/@typescript-eslint 13 | - plugin:@typescript-eslint/eslint-recommended 14 | - plugin:@typescript-eslint/recommended 15 | - plugin:@typescript-eslint/recommended-requiring-type-checking 16 | - plugin:import/typescript 17 | parser: "@typescript-eslint/parser" 18 | parserOptions: 19 | project: tsconfig.json 20 | sourceType: module 21 | rules: 22 | "@typescript-eslint/explicit-module-boundary-types": off 23 | "@typescript-eslint/no-var-requires": off 24 | plugins: 25 | - import 26 | - sort-keys-fix 27 | rules: 28 | import/no-extraneous-dependencies: error 29 | import/order: 30 | - error 31 | - alphabetize: 32 | order: asc 33 | sort-keys-fix/sort-keys-fix: error 34 | settings: 35 | import/core-modules: 36 | - atom 37 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foxdot", 3 | "main": "lib/index.js", 4 | "types": "lib/index.d.ts", 5 | "version": "1.3.0", 6 | "description": "FoxDot interface for Atom.", 7 | "keywords": [ 8 | "algorave", 9 | "livecoding", 10 | "supercollider" 11 | ], 12 | "repository": "https://github.com/KoltesDigital/atom-foxdot", 13 | "license": "MIT", 14 | "engines": { 15 | "atom": ">=1.0.0 <2.0.0" 16 | }, 17 | "scripts": { 18 | "clean": "shx rm -rf lib", 19 | "format": "eslint . --ext .ts --fix && prettier --write **/*{.js,.json,.ts,.yml}", 20 | "lint": "eslint . --ext .ts && prettier --check **/*{.js,.json,.ts,.yml}", 21 | "watch": "tsc --watch" 22 | }, 23 | "providedServices": { 24 | "autocomplete.provider": { 25 | "versions": { 26 | "2.0.0": "provideAutocomplete" 27 | } 28 | } 29 | }, 30 | "dependencies": {}, 31 | "devDependencies": { 32 | "@types/atom": "^1.40.6", 33 | "@types/node": "^14.14.20", 34 | "@typescript-eslint/eslint-plugin": "^4.13.0", 35 | "@typescript-eslint/parser": "^4.13.0", 36 | "babel-eslint": "^10.1.0", 37 | "eslint": "^7.17.0", 38 | "eslint-config-prettier": "^7.1.0", 39 | "eslint-plugin-import": "^2.22.1", 40 | "eslint-plugin-prettier": "^3.3.1", 41 | "eslint-plugin-sort-keys-fix": "^1.1.1", 42 | "gulp": "^4.0.2", 43 | "prettier": "^2.2.1", 44 | "require-dir": "^1.2.0", 45 | "shx": "^0.3.3", 46 | "typescript": "^4.1.3" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /menus/foxdot.json: -------------------------------------------------------------------------------- 1 | { 2 | "context-menu": { 3 | "atom-text-editor": [ 4 | { 5 | "label": "FoxDot", 6 | "submenu": [ 7 | { 8 | "label": "Toggle", 9 | "command": "foxdot:toggle" 10 | }, 11 | { 12 | "type": "separator" 13 | }, 14 | { 15 | "label": "Evaluate file", 16 | "command": "foxdot:evaluate-file" 17 | }, 18 | { 19 | "label": "Evaluate block(s)", 20 | "command": "foxdot:evaluate-blocks" 21 | }, 22 | { 23 | "label": "Evaluate line(s)", 24 | "command": "foxdot:evaluate-lines" 25 | }, 26 | { 27 | "type": "separator" 28 | }, 29 | { 30 | "label": "Clear clock", 31 | "command": "foxdot:clear-clock" 32 | } 33 | ] 34 | } 35 | ] 36 | }, 37 | "menu": [ 38 | { 39 | "label": "Packages", 40 | "submenu": [ 41 | { 42 | "label": "FoxDot", 43 | "submenu": [ 44 | { 45 | "label": "Toggle", 46 | "command": "foxdot:toggle" 47 | }, 48 | { 49 | "type": "separator" 50 | }, 51 | { 52 | "label": "Evaluate file", 53 | "command": "foxdot:evaluate-file" 54 | }, 55 | { 56 | "label": "Evaluate block(s)", 57 | "command": "foxdot:evaluate-blocks" 58 | }, 59 | { 60 | "label": "Evaluate line(s)", 61 | "command": "foxdot:evaluate-lines" 62 | }, 63 | { 64 | "type": "separator" 65 | }, 66 | { 67 | "label": "Clear clock", 68 | "command": "foxdot:clear-clock" 69 | } 70 | ] 71 | } 72 | ] 73 | } 74 | ] 75 | } 76 | -------------------------------------------------------------------------------- /tasks/generate-autocomplete.py: -------------------------------------------------------------------------------- 1 | import json 2 | import FoxDot 3 | from operator import itemgetter 4 | 5 | constants = [ 6 | 'Clock', 7 | 'DefaultServer', 8 | 'Group', 9 | 'inf', 10 | 'Root', 11 | 'Samples', 12 | 'Scale', 13 | ] 14 | 15 | functions = [ 16 | 'expvar', 17 | 'linvar', 18 | 'mapvar', 19 | 'P', 20 | 'Pvar', 21 | 'var', 22 | ] 23 | 24 | keywords = [ 25 | 'when', 26 | ] 27 | 28 | variables = [ 29 | 'Clock.bpm', 30 | 'Scale.default', 31 | ] 32 | 33 | suggestions = [] 34 | 35 | def make_suggestion(name, type, container=None): 36 | suggestion = { 37 | 'text': name, 38 | 'type': type, 39 | } 40 | if container is not None: 41 | doc = getattr(container, name).__doc__ 42 | if doc is not None: 43 | suggestion['description'] = doc.strip() 44 | return suggestion 45 | 46 | suggestions.extend([make_suggestion(name, 'constant', FoxDot) for name in constants]) 47 | suggestions.extend([make_suggestion(name, 'function', FoxDot) for name in functions]) 48 | suggestions.extend([make_suggestion(name, 'keyword') for name in keywords]) 49 | suggestions.extend([make_suggestion(name, 'variable') for name in variables]) 50 | 51 | suggestions.extend([make_suggestion(name, 'class', FoxDot) for name in FoxDot.Code.classes(FoxDot)]) 52 | suggestions.extend([make_suggestion(name, 'class', FoxDot.Patterns.Generators) for name in FoxDot.Code.classes(FoxDot.Patterns.Generators)]) 53 | suggestions.extend([make_suggestion(name, 'class', FoxDot.Patterns.Main) for name in FoxDot.Code.classes(FoxDot.Patterns.Main)]) 54 | suggestions.extend([make_suggestion(name, 'function', FoxDot.Patterns.Sequences) for name in FoxDot.Code.functions(FoxDot.Patterns.Sequences)]) 55 | suggestions.extend([make_suggestion(name, 'method') for name in dir(FoxDot.Player) if callable(getattr(FoxDot.Player, name)) and name[0].islower()]) 56 | suggestions.extend([make_suggestion(name, 'property') for name in FoxDot.Player.Attributes()]) 57 | 58 | suggestions.extend([make_suggestion(name, 'function', FoxDot) for name in FoxDot.SynthDefs if name != 'play1' and name != 'play2']) 59 | suggestions.append(make_suggestion('play', 'function', FoxDot)) 60 | 61 | suggestions.extend([make_suggestion('Scale.' + name, 'constant') for name in FoxDot.Scale.names()]) 62 | 63 | suggestions = [dict(t) for t in set([tuple(d.items()) for d in suggestions])] 64 | suggestions.sort(key=itemgetter('text')) 65 | 66 | with open('data/autocomplete.json', 'w') as f: 67 | json.dump(suggestions, f, indent=2) 68 | -------------------------------------------------------------------------------- /lib/logging.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.LoggerInWorkspace = exports.LOGGER_IN_WORKSPACE_URI = void 0; 4 | exports.LOGGER_IN_WORKSPACE_URI = 'atom://foxdot/logger'; 5 | class LoggerInWorkspace { 6 | constructor() { 7 | this.changeTitleCallbacks = []; 8 | this.terminated = false; 9 | this.element = document.createElement('div'); 10 | this.element.classList.add('foxdot-logger', 'native-key-bindings'); 11 | this.element.setAttribute('tabindex', '-1'); 12 | this.element.setAttribute('style', 'overflow-y: scroll;'); 13 | void atom.workspace.open(this, { 14 | activatePane: false, 15 | }); 16 | atom.workspace.getBottomDock().show(); 17 | } 18 | dispose() { 19 | this.element.remove(); 20 | } 21 | getDefaultLocation() { 22 | return 'bottom'; 23 | } 24 | getTitle() { 25 | return this.terminated ? 'FoxDot (Terminated)' : 'FoxDot'; 26 | } 27 | getURI() { 28 | return exports.LOGGER_IN_WORKSPACE_URI; 29 | } 30 | onDidChangeTitle(callback) { 31 | this.changeTitleCallbacks.push(callback); 32 | return { 33 | dispose: () => { 34 | const index = this.changeTitleCallbacks.indexOf(callback); 35 | if (index !== -1) { 36 | this.changeTitleCallbacks.splice(index, 1); 37 | } 38 | }, 39 | }; 40 | } 41 | setTerminated() { 42 | this.terminated = true; 43 | this.changeTitleCallbacks.forEach((callback) => callback()); 44 | } 45 | service(message, error) { 46 | if (!atom.config.get('foxdot.logging.logServiceMessages')) { 47 | return; 48 | } 49 | const element = document.createElement('div'); 50 | element.className = 'service'; 51 | element.textContent = message; 52 | return this.addMessage(element, error); 53 | } 54 | stdin(message) { 55 | if (!atom.config.get('foxdot.logging.logStdin')) { 56 | return; 57 | } 58 | const element = document.createElement('pre'); 59 | element.className = 'stdin'; 60 | element.textContent = message; 61 | return this.addMessage(element, false); 62 | } 63 | stdout(message) { 64 | if (!atom.config.get('foxdot.logging.logStdout')) { 65 | return; 66 | } 67 | const element = document.createElement('pre'); 68 | element.className = 'stdout'; 69 | element.textContent = message; 70 | return this.addMessage(element, false); 71 | } 72 | stderr(message) { 73 | if (!atom.config.get('foxdot.logging.logStderr')) { 74 | return; 75 | } 76 | const element = document.createElement('pre'); 77 | element.className = 'stderr'; 78 | element.textContent = message; 79 | return this.addMessage(element, true); 80 | } 81 | addMessage(element, error) { 82 | if (error) { 83 | element.classList.add('error'); 84 | } 85 | this.element.appendChild(element); 86 | this.element.scrollTop = this.element.scrollHeight; 87 | } 88 | } 89 | exports.LoggerInWorkspace = LoggerInWorkspace; 90 | -------------------------------------------------------------------------------- /src/logging.ts: -------------------------------------------------------------------------------- 1 | import { ViewModel } from 'atom'; 2 | 3 | export interface Logger { 4 | service(message: string, error: boolean): void; 5 | stdin(message: string): void; 6 | stdout(message: string): void; 7 | stderr(message: string): void; 8 | } 9 | 10 | export const LOGGER_IN_WORKSPACE_URI = 'atom://foxdot/logger'; 11 | 12 | export class LoggerInWorkspace implements Logger, ViewModel { 13 | readonly element: HTMLDivElement; 14 | changeTitleCallbacks: (() => void)[] = []; 15 | terminated = false; 16 | 17 | constructor() { 18 | this.element = document.createElement('div'); 19 | this.element.classList.add('foxdot-logger', 'native-key-bindings'); 20 | this.element.setAttribute('tabindex', '-1'); 21 | this.element.setAttribute('style', 'overflow-y: scroll;'); 22 | 23 | void atom.workspace.open(this, { 24 | activatePane: false, 25 | }); 26 | 27 | atom.workspace.getBottomDock().show(); 28 | } 29 | 30 | dispose() { 31 | this.element.remove(); 32 | } 33 | 34 | getDefaultLocation() { 35 | return 'bottom'; 36 | } 37 | 38 | getTitle() { 39 | return this.terminated ? 'FoxDot (Terminated)' : 'FoxDot'; 40 | } 41 | 42 | getURI() { 43 | return LOGGER_IN_WORKSPACE_URI; 44 | } 45 | 46 | onDidChangeTitle(callback: () => void) { 47 | this.changeTitleCallbacks.push(callback); 48 | 49 | return { 50 | dispose: () => { 51 | const index = this.changeTitleCallbacks.indexOf(callback); 52 | if (index !== -1) { 53 | this.changeTitleCallbacks.splice(index, 1); 54 | } 55 | }, 56 | }; 57 | } 58 | 59 | setTerminated() { 60 | this.terminated = true; 61 | 62 | this.changeTitleCallbacks.forEach((callback) => callback()); 63 | } 64 | 65 | service(message: string, error: boolean) { 66 | if (!atom.config.get('foxdot.logging.logServiceMessages')) { 67 | return; 68 | } 69 | 70 | const element = document.createElement('div'); 71 | element.className = 'service'; 72 | element.textContent = message; 73 | 74 | return this.addMessage(element, error); 75 | } 76 | 77 | stdin(message: string) { 78 | if (!atom.config.get('foxdot.logging.logStdin')) { 79 | return; 80 | } 81 | 82 | const element = document.createElement('pre'); 83 | element.className = 'stdin'; 84 | element.textContent = message; 85 | 86 | return this.addMessage(element, false); 87 | } 88 | 89 | stdout(message: string) { 90 | if (!atom.config.get('foxdot.logging.logStdout')) { 91 | return; 92 | } 93 | 94 | const element = document.createElement('pre'); 95 | element.className = 'stdout'; 96 | element.textContent = message; 97 | 98 | return this.addMessage(element, false); 99 | } 100 | 101 | stderr(message: string) { 102 | if (!atom.config.get('foxdot.logging.logStderr')) { 103 | return; 104 | } 105 | 106 | const element = document.createElement('pre'); 107 | element.className = 'stderr'; 108 | element.textContent = message; 109 | 110 | return this.addMessage(element, true); 111 | } 112 | 113 | private addMessage(element: HTMLElement, error: boolean) { 114 | if (error) { 115 | element.classList.add('error'); 116 | } 117 | 118 | this.element.appendChild(element); 119 | 120 | this.element.scrollTop = this.element.scrollHeight; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { CompositeDisposable } from 'atom'; 2 | import autocomplete from './autocomplete'; 3 | import { FoxDot } from './foxdot'; 4 | import { LoggerInWorkspace, LOGGER_IN_WORKSPACE_URI } from './logging'; 5 | 6 | let foxDot: FoxDot | undefined; 7 | let logger: LoggerInWorkspace | undefined; 8 | let subscriptions: CompositeDisposable | undefined; 9 | 10 | function start() { 11 | autocomplete.enabled = true; 12 | 13 | if (atom.config.get('foxdot.logging.enabled')) { 14 | logger = new LoggerInWorkspace(); 15 | } 16 | 17 | foxDot = new FoxDot(logger); 18 | foxDot.on('stop', () => { 19 | logger?.setTerminated(); 20 | 21 | foxDot = undefined; 22 | logger = undefined; 23 | }); 24 | } 25 | 26 | function stop() { 27 | foxDot?.dispose(); 28 | 29 | autocomplete.enabled = false; 30 | } 31 | 32 | export const config = { 33 | logging: { 34 | properties: { 35 | enabled: { 36 | default: true, 37 | description: 'Takes effect at the next plugin startup.', 38 | type: 'boolean', 39 | }, 40 | logServiceMessages: { 41 | default: true, 42 | type: 'boolean', 43 | }, 44 | logStderr: { 45 | default: true, 46 | type: 'boolean', 47 | }, 48 | logStdin: { 49 | default: true, 50 | type: 'boolean', 51 | }, 52 | logStdout: { 53 | default: true, 54 | type: 'boolean', 55 | }, 56 | }, 57 | type: 'object', 58 | }, 59 | pythonPath: { 60 | default: '', 61 | description: 62 | 'Leave empty to use python from the PATH environment variable.', 63 | type: 'string', 64 | }, 65 | samplesDirectory: { 66 | default: '', 67 | description: 68 | 'Use an alternate directory for looking up samples (restart FoxDot session to take effect).', 69 | type: 'string', 70 | }, 71 | useSC3Plugins: { 72 | default: false, 73 | description: 'Use SC3 plugins (restart FoxDot session to take effect).', 74 | type: 'boolean', 75 | }, 76 | }; 77 | 78 | export function activate() { 79 | subscriptions = new CompositeDisposable( 80 | atom.workspace.addOpener((uri) => { 81 | if (uri === LOGGER_IN_WORKSPACE_URI) { 82 | return new LoggerInWorkspace(); 83 | } 84 | return undefined; 85 | }), 86 | 87 | atom.commands.add('atom-workspace', { 88 | 'foxdot:clear-clock': (event) => { 89 | if (!foxDot) { 90 | return event.abortKeyBinding(); 91 | } else { 92 | foxDot.clearClock(); 93 | } 94 | }, 95 | 'foxdot:evaluate-blocks': (event) => { 96 | if (!foxDot) { 97 | return event.abortKeyBinding(); 98 | } else { 99 | foxDot.evaluateBlocks(); 100 | } 101 | }, 102 | 'foxdot:evaluate-file': (event) => { 103 | if (!foxDot) { 104 | return event.abortKeyBinding(); 105 | } else { 106 | foxDot.evaluateFile(); 107 | } 108 | }, 109 | 'foxdot:evaluate-lines': (event) => { 110 | if (!foxDot) { 111 | return event.abortKeyBinding(); 112 | } else { 113 | foxDot.evaluateLines(); 114 | } 115 | }, 116 | 'foxdot:toggle': () => { 117 | if (!foxDot) { 118 | start(); 119 | } else { 120 | stop(); 121 | } 122 | }, 123 | }) 124 | ); 125 | } 126 | 127 | export function deactivate() { 128 | stop(); 129 | if (subscriptions) { 130 | subscriptions.dispose(); 131 | } 132 | } 133 | 134 | export function provideAutocomplete() { 135 | return autocomplete; 136 | } 137 | 138 | export function serialize() { 139 | return {}; 140 | } 141 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var __importDefault = (this && this.__importDefault) || function (mod) { 3 | return (mod && mod.__esModule) ? mod : { "default": mod }; 4 | }; 5 | Object.defineProperty(exports, "__esModule", { value: true }); 6 | exports.serialize = exports.provideAutocomplete = exports.deactivate = exports.activate = exports.config = void 0; 7 | const atom_1 = require("atom"); 8 | const autocomplete_1 = __importDefault(require("./autocomplete")); 9 | const foxdot_1 = require("./foxdot"); 10 | const logging_1 = require("./logging"); 11 | let foxDot; 12 | let logger; 13 | let subscriptions; 14 | function start() { 15 | autocomplete_1.default.enabled = true; 16 | if (atom.config.get('foxdot.logging.enabled')) { 17 | logger = new logging_1.LoggerInWorkspace(); 18 | } 19 | foxDot = new foxdot_1.FoxDot(logger); 20 | foxDot.on('stop', () => { 21 | logger === null || logger === void 0 ? void 0 : logger.setTerminated(); 22 | foxDot = undefined; 23 | logger = undefined; 24 | }); 25 | } 26 | function stop() { 27 | foxDot === null || foxDot === void 0 ? void 0 : foxDot.dispose(); 28 | autocomplete_1.default.enabled = false; 29 | } 30 | exports.config = { 31 | logging: { 32 | properties: { 33 | enabled: { 34 | default: true, 35 | description: 'Takes effect at the next plugin startup.', 36 | type: 'boolean', 37 | }, 38 | logServiceMessages: { 39 | default: true, 40 | type: 'boolean', 41 | }, 42 | logStderr: { 43 | default: true, 44 | type: 'boolean', 45 | }, 46 | logStdin: { 47 | default: true, 48 | type: 'boolean', 49 | }, 50 | logStdout: { 51 | default: true, 52 | type: 'boolean', 53 | }, 54 | }, 55 | type: 'object', 56 | }, 57 | pythonPath: { 58 | default: '', 59 | description: 'Leave empty to use python from the PATH environment variable.', 60 | type: 'string', 61 | }, 62 | samplesDirectory: { 63 | default: '', 64 | description: 'Use an alternate directory for looking up samples (restart FoxDot session to take effect).', 65 | type: 'string', 66 | }, 67 | useSC3Plugins: { 68 | default: false, 69 | description: 'Use SC3 plugins (restart FoxDot session to take effect).', 70 | type: 'boolean', 71 | }, 72 | }; 73 | function activate() { 74 | subscriptions = new atom_1.CompositeDisposable(atom.workspace.addOpener((uri) => { 75 | if (uri === logging_1.LOGGER_IN_WORKSPACE_URI) { 76 | return new logging_1.LoggerInWorkspace(); 77 | } 78 | return undefined; 79 | }), atom.commands.add('atom-workspace', { 80 | 'foxdot:clear-clock': (event) => { 81 | if (!foxDot) { 82 | return event.abortKeyBinding(); 83 | } 84 | else { 85 | foxDot.clearClock(); 86 | } 87 | }, 88 | 'foxdot:evaluate-blocks': (event) => { 89 | if (!foxDot) { 90 | return event.abortKeyBinding(); 91 | } 92 | else { 93 | foxDot.evaluateBlocks(); 94 | } 95 | }, 96 | 'foxdot:evaluate-file': (event) => { 97 | if (!foxDot) { 98 | return event.abortKeyBinding(); 99 | } 100 | else { 101 | foxDot.evaluateFile(); 102 | } 103 | }, 104 | 'foxdot:evaluate-lines': (event) => { 105 | if (!foxDot) { 106 | return event.abortKeyBinding(); 107 | } 108 | else { 109 | foxDot.evaluateLines(); 110 | } 111 | }, 112 | 'foxdot:toggle': () => { 113 | if (!foxDot) { 114 | start(); 115 | } 116 | else { 117 | stop(); 118 | } 119 | }, 120 | })); 121 | } 122 | exports.activate = activate; 123 | function deactivate() { 124 | stop(); 125 | if (subscriptions) { 126 | subscriptions.dispose(); 127 | } 128 | } 129 | exports.deactivate = deactivate; 130 | function provideAutocomplete() { 131 | return autocomplete_1.default; 132 | } 133 | exports.provideAutocomplete = provideAutocomplete; 134 | function serialize() { 135 | return {}; 136 | } 137 | exports.serialize = serialize; 138 | -------------------------------------------------------------------------------- /src/foxdot.ts: -------------------------------------------------------------------------------- 1 | import { RangeCompatible } from 'atom'; 2 | import { spawn, ChildProcessWithoutNullStreams } from 'child_process'; 3 | import { EventEmitter } from 'events'; 4 | import { Logger } from './logging'; 5 | 6 | export class FoxDot extends EventEmitter { 7 | childProcess?: ChildProcessWithoutNullStreams; 8 | logger?: Logger; 9 | 10 | constructor(logger?: Logger) { 11 | super(); 12 | 13 | this.logger = logger; 14 | 15 | const pythonPath = 16 | (atom.config.get('foxdot.pythonPath') as string) || 'python'; 17 | const samplesDirectory = atom.config.get( 18 | 'foxdot.samplesDirectory' 19 | ) as string; 20 | 21 | let command = ['-m', 'FoxDot', '--pipe']; 22 | if (samplesDirectory !== '') { 23 | logger?.service(`Using samples from ${samplesDirectory}.`, false); 24 | command = command.concat(['-d', samplesDirectory]); 25 | } 26 | 27 | try { 28 | this.childProcess = spawn(pythonPath, command, { 29 | env: { 30 | ...process.env, 31 | SC3_PLUGINS: (atom.config.get('foxdot.useSC3Plugins') as boolean) 32 | ? '1' 33 | : undefined, 34 | }, 35 | }); 36 | 37 | this.childProcess.stdout.on('data', (data) => { 38 | logger?.stdout(data); 39 | }); 40 | 41 | this.childProcess.stderr.on('data', (data) => { 42 | logger?.stderr(data); 43 | }); 44 | 45 | this.childProcess.on('error', (err: Error & { code?: unknown }) => { 46 | if (err.code === 'ENOENT') { 47 | logger?.service( 48 | `Python was not found. Check that you have Python installed. You may need to give the full path to the Python executable in the FoxDot package's settings.`, 49 | true 50 | ); 51 | } 52 | logger?.service(err.toString(), true); 53 | }); 54 | 55 | this.childProcess.on('close', (code) => { 56 | if (code) { 57 | logger?.service(`FoxDot has exited with code ${code}.`, true); 58 | } else { 59 | logger?.service('FoxDot has stopped.', false); 60 | } 61 | 62 | this.childProcess = undefined; 63 | this.emit('stop'); 64 | }); 65 | 66 | logger?.service('FoxDot has started.', false); 67 | } catch (err: unknown) { 68 | if (err instanceof Error) { 69 | logger?.service(err.toString(), true); 70 | } else { 71 | logger?.service('Unknown error', true); 72 | } 73 | } 74 | } 75 | 76 | dispose() { 77 | this.childProcess?.kill(); 78 | } 79 | 80 | clearClock() { 81 | return this.evaluateCode('Clock.clear()'); 82 | } 83 | 84 | evaluateBlocks() { 85 | const editor = atom.workspace.getActiveTextEditor(); 86 | if (!editor) { 87 | return; 88 | } 89 | 90 | const buffer = editor.getBuffer(); 91 | const lines = buffer.getLines(); 92 | const selectedRanges = editor.getSelectedBufferRanges(); 93 | const ranges = selectedRanges.map((selectedRange) => { 94 | if (!selectedRange.isEmpty()) { 95 | return selectedRange; 96 | } 97 | 98 | const row = selectedRange.start.row; 99 | 100 | let rowBefore = row; 101 | while (rowBefore >= 0 && lines[rowBefore] !== '') { 102 | --rowBefore; 103 | } 104 | 105 | let rowAfter = row; 106 | while (rowAfter < lines.length && lines[rowAfter] !== '') { 107 | ++rowAfter; 108 | } 109 | 110 | const range: RangeCompatible = [ 111 | [rowBefore + 1, 0], 112 | [rowAfter, 0], 113 | ]; 114 | return buffer.clipRange(range); 115 | }); 116 | 117 | return this.evaluateRanges(ranges); 118 | } 119 | 120 | evaluateCode(code: string) { 121 | if (!this.childProcess) { 122 | return; 123 | } 124 | 125 | const stdin = this.childProcess.stdin; 126 | stdin.write(code); 127 | stdin.write('\n\n'); 128 | 129 | this.logger?.stdin(code); 130 | } 131 | 132 | evaluateFile() { 133 | const editor = atom.workspace.getActiveTextEditor(); 134 | if (!editor) { 135 | return; 136 | } 137 | 138 | const range = editor.getBuffer().getRange(); 139 | return this.evaluateRange(range); 140 | } 141 | 142 | evaluateLines() { 143 | const editor = atom.workspace.getActiveTextEditor(); 144 | if (!editor) { 145 | return; 146 | } 147 | 148 | const buffer = editor.getBuffer(); 149 | const positions = editor.getCursorBufferPositions(); 150 | const ranges = positions.map((position) => { 151 | const row = position.row; 152 | return buffer.rangeForRow(row, true); 153 | }); 154 | return this.evaluateRanges(ranges); 155 | } 156 | 157 | evaluateRange(range: RangeCompatible) { 158 | const editor = atom.workspace.getActiveTextEditor(); 159 | if (!editor) { 160 | return; 161 | } 162 | 163 | const buffer = editor.getBuffer(); 164 | 165 | const marker = editor.markBufferRange(range); 166 | editor.decorateMarker(marker, { 167 | class: 'foxdot-flash', 168 | type: 'highlight', 169 | }); 170 | setTimeout(() => { 171 | marker.destroy(); 172 | }, 300); 173 | 174 | const code = buffer.getTextInRange(range); 175 | this.evaluateCode(code); 176 | } 177 | 178 | evaluateRanges(ranges: RangeCompatible[]) { 179 | return ranges.forEach((range) => this.evaluateRange(range)); 180 | } 181 | } 182 | -------------------------------------------------------------------------------- /lib/foxdot.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.FoxDot = void 0; 4 | const child_process_1 = require("child_process"); 5 | const events_1 = require("events"); 6 | class FoxDot extends events_1.EventEmitter { 7 | constructor(logger) { 8 | super(); 9 | this.logger = logger; 10 | const pythonPath = atom.config.get('foxdot.pythonPath') || 'python'; 11 | const samplesDirectory = atom.config.get('foxdot.samplesDirectory'); 12 | let command = ['-m', 'FoxDot', '--pipe']; 13 | if (samplesDirectory !== '') { 14 | logger === null || logger === void 0 ? void 0 : logger.service(`Using samples from ${samplesDirectory}.`, false); 15 | command = command.concat(['-d', samplesDirectory]); 16 | } 17 | try { 18 | this.childProcess = child_process_1.spawn(pythonPath, command, { 19 | env: Object.assign(Object.assign({}, process.env), { SC3_PLUGINS: atom.config.get('foxdot.useSC3Plugins') 20 | ? '1' 21 | : undefined }), 22 | }); 23 | this.childProcess.stdout.on('data', (data) => { 24 | logger === null || logger === void 0 ? void 0 : logger.stdout(data); 25 | }); 26 | this.childProcess.stderr.on('data', (data) => { 27 | logger === null || logger === void 0 ? void 0 : logger.stderr(data); 28 | }); 29 | this.childProcess.on('error', (err) => { 30 | if (err.code === 'ENOENT') { 31 | logger === null || logger === void 0 ? void 0 : logger.service(`Python was not found. Check that you have Python installed. You may need to give the full path to the Python executable in the FoxDot package's settings.`, true); 32 | } 33 | logger === null || logger === void 0 ? void 0 : logger.service(err.toString(), true); 34 | }); 35 | this.childProcess.on('close', (code) => { 36 | if (code) { 37 | logger === null || logger === void 0 ? void 0 : logger.service(`FoxDot has exited with code ${code}.`, true); 38 | } 39 | else { 40 | logger === null || logger === void 0 ? void 0 : logger.service('FoxDot has stopped.', false); 41 | } 42 | this.childProcess = undefined; 43 | this.emit('stop'); 44 | }); 45 | logger === null || logger === void 0 ? void 0 : logger.service('FoxDot has started.', false); 46 | } 47 | catch (err) { 48 | if (err instanceof Error) { 49 | logger === null || logger === void 0 ? void 0 : logger.service(err.toString(), true); 50 | } 51 | else { 52 | logger === null || logger === void 0 ? void 0 : logger.service('Unknown error', true); 53 | } 54 | } 55 | } 56 | dispose() { 57 | var _a; 58 | (_a = this.childProcess) === null || _a === void 0 ? void 0 : _a.kill(); 59 | } 60 | clearClock() { 61 | return this.evaluateCode('Clock.clear()'); 62 | } 63 | evaluateBlocks() { 64 | const editor = atom.workspace.getActiveTextEditor(); 65 | if (!editor) { 66 | return; 67 | } 68 | const buffer = editor.getBuffer(); 69 | const lines = buffer.getLines(); 70 | const selectedRanges = editor.getSelectedBufferRanges(); 71 | const ranges = selectedRanges.map((selectedRange) => { 72 | if (!selectedRange.isEmpty()) { 73 | return selectedRange; 74 | } 75 | const row = selectedRange.start.row; 76 | let rowBefore = row; 77 | while (rowBefore >= 0 && lines[rowBefore] !== '') { 78 | --rowBefore; 79 | } 80 | let rowAfter = row; 81 | while (rowAfter < lines.length && lines[rowAfter] !== '') { 82 | ++rowAfter; 83 | } 84 | const range = [ 85 | [rowBefore + 1, 0], 86 | [rowAfter, 0], 87 | ]; 88 | return buffer.clipRange(range); 89 | }); 90 | return this.evaluateRanges(ranges); 91 | } 92 | evaluateCode(code) { 93 | var _a; 94 | if (!this.childProcess) { 95 | return; 96 | } 97 | const stdin = this.childProcess.stdin; 98 | stdin.write(code); 99 | stdin.write('\n\n'); 100 | (_a = this.logger) === null || _a === void 0 ? void 0 : _a.stdin(code); 101 | } 102 | evaluateFile() { 103 | const editor = atom.workspace.getActiveTextEditor(); 104 | if (!editor) { 105 | return; 106 | } 107 | const range = editor.getBuffer().getRange(); 108 | return this.evaluateRange(range); 109 | } 110 | evaluateLines() { 111 | const editor = atom.workspace.getActiveTextEditor(); 112 | if (!editor) { 113 | return; 114 | } 115 | const buffer = editor.getBuffer(); 116 | const positions = editor.getCursorBufferPositions(); 117 | const ranges = positions.map((position) => { 118 | const row = position.row; 119 | return buffer.rangeForRow(row, true); 120 | }); 121 | return this.evaluateRanges(ranges); 122 | } 123 | evaluateRange(range) { 124 | const editor = atom.workspace.getActiveTextEditor(); 125 | if (!editor) { 126 | return; 127 | } 128 | const buffer = editor.getBuffer(); 129 | const marker = editor.markBufferRange(range); 130 | editor.decorateMarker(marker, { 131 | class: 'foxdot-flash', 132 | type: 'highlight', 133 | }); 134 | setTimeout(() => { 135 | marker.destroy(); 136 | }, 300); 137 | const code = buffer.getTextInRange(range); 138 | this.evaluateCode(code); 139 | } 140 | evaluateRanges(ranges) { 141 | return ranges.forEach((range) => this.evaluateRange(range)); 142 | } 143 | } 144 | exports.FoxDot = FoxDot; 145 | -------------------------------------------------------------------------------- /data/autocomplete.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "text": "Accompany", 4 | "type": "class", 5 | "description": "Like PlayerKey except it returns" 6 | }, 7 | { 8 | "text": "Add", 9 | "type": "function" 10 | }, 11 | { 12 | "text": "Bang", 13 | "type": "class" 14 | }, 15 | { 16 | "text": "BufChar", 17 | "type": "class" 18 | }, 19 | { 20 | "text": "Buffer", 21 | "type": "class" 22 | }, 23 | { 24 | "text": "BufferManager", 25 | "type": "class" 26 | }, 27 | { 28 | "text": "COLOURS", 29 | "type": "class" 30 | }, 31 | { 32 | "text": "ClassPatternMethod", 33 | "type": "function", 34 | "description": "Decorator that makes a function into a metaPattern class method" 35 | }, 36 | { 37 | "text": "Clock", 38 | "type": "constant" 39 | }, 40 | { 41 | "text": "Clock.bpm", 42 | "type": "variable" 43 | }, 44 | { 45 | "text": "CodeString", 46 | "type": "class" 47 | }, 48 | { 49 | "text": "CodeType", 50 | "type": "class", 51 | "description": "code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,\n constants, names, varnames, filename, name, firstlineno,\n lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart." 52 | }, 53 | { 54 | "text": "CompiledSynthDef", 55 | "type": "class" 56 | }, 57 | { 58 | "text": "Convert", 59 | "type": "function", 60 | "description": "Returns tuples/PGroups as PGroups, and anything else as Patterns" 61 | }, 62 | { 63 | "text": "DatagramRequestHandler", 64 | "type": "class", 65 | "description": "Define self.rfile and self.wfile for datagram sockets." 66 | }, 67 | { 68 | "text": "DefaultServer", 69 | "type": "constant" 70 | }, 71 | { 72 | "text": "Div", 73 | "type": "function" 74 | }, 75 | { 76 | "text": "DominantPattern", 77 | "type": "function", 78 | "description": "Returns the class (and the relative pattern) for the\n type of Pattern to use in a mathematical operation" 79 | }, 80 | { 81 | "text": "Effect", 82 | "type": "class" 83 | }, 84 | { 85 | "text": "EffectManager", 86 | "type": "class" 87 | }, 88 | { 89 | "text": "EmptyItem", 90 | "type": "class", 91 | "description": "Can be used in a pattern and and is essentially not there" 92 | }, 93 | { 94 | "text": "EuclidsAlgorithm", 95 | "type": "function" 96 | }, 97 | { 98 | "text": "FileSynthDef", 99 | "type": "class" 100 | }, 101 | { 102 | "text": "FloorDiv", 103 | "type": "function" 104 | }, 105 | { 106 | "text": "ForkingMixIn", 107 | "type": "class", 108 | "description": "Mix-in class to handle each request in a new thread." 109 | }, 110 | { 111 | "text": "ForkingOSCServer", 112 | "type": "class", 113 | "description": "An Asynchronous OSCServer.\n\tThis server forks a new process to handle each incoming request." 114 | }, 115 | { 116 | "text": "Format", 117 | "type": "function", 118 | "description": "If data is a list, returns Pattern(data). If data is a tuple, returns PGroup(data).\n Returns data if neither." 119 | }, 120 | { 121 | "text": "FoxDotCode", 122 | "type": "class" 123 | }, 124 | { 125 | "text": "FunctionType", 126 | "type": "class", 127 | "description": "function(code, globals[, name[, argdefs[, closure]]])\n\nCreate a function object from a code object and a dictionary.\nThe optional name string overrides the name from the code object.\nThe optional argdefs tuple specifies the default argument values.\nThe optional closure tuple supplies the bindings for free variables." 128 | }, 129 | { 130 | "text": "GeneratorPattern", 131 | "type": "class", 132 | "description": "Used for when a Pattern does not generate a set length pattern,\n e.g. random patterns" 133 | }, 134 | { 135 | "text": "Get", 136 | "type": "function" 137 | }, 138 | { 139 | "text": "Group", 140 | "type": "constant" 141 | }, 142 | { 143 | "text": "Group", 144 | "type": "class" 145 | }, 146 | { 147 | "text": "GroupAttr", 148 | "type": "class" 149 | }, 150 | { 151 | "text": "History", 152 | "type": "class", 153 | "description": "Stores osc messages send from the TempoClock so that if the\n Clock is reveresed we can just send the osc messages already sent" 154 | }, 155 | { 156 | "text": "In", 157 | "type": "class" 158 | }, 159 | { 160 | "text": "LCM", 161 | "type": "function", 162 | "description": "Lowest Common Multiple" 163 | }, 164 | { 165 | "text": "LiveObject", 166 | "type": "class" 167 | }, 168 | { 169 | "text": "LoopFile", 170 | "type": "class" 171 | }, 172 | { 173 | "text": "LoopSynthDef", 174 | "type": "class" 175 | }, 176 | { 177 | "text": "MIDIDeviceNotFound", 178 | "type": "class" 179 | }, 180 | { 181 | "text": "Message", 182 | "type": "class", 183 | "description": "Wrapper for JSON messages sent to the server" 184 | }, 185 | { 186 | "text": "MethodCall", 187 | "type": "class", 188 | "description": "Class to represent an object's method call that,\n when called, schedules itself in the future" 189 | }, 190 | { 191 | "text": "MethodList", 192 | "type": "class" 193 | }, 194 | { 195 | "text": "MethodType", 196 | "type": "class", 197 | "description": "method(function, instance)\n\nCreate a bound instance method object." 198 | }, 199 | { 200 | "text": "MidiIn", 201 | "type": "class" 202 | }, 203 | { 204 | "text": "MidiOut", 205 | "type": "class" 206 | }, 207 | { 208 | "text": "Mod", 209 | "type": "function" 210 | }, 211 | { 212 | "text": "Mul", 213 | "type": "function" 214 | }, 215 | { 216 | "text": "Nil", 217 | "type": "function" 218 | }, 219 | { 220 | "text": "NoCallbackError", 221 | "type": "class", 222 | "description": "This error is raised (by an OSCServer) when an OSCMessage with an 'unmatched' address-pattern\n\tis received, and no 'default' handler is registered." 223 | }, 224 | { 225 | "text": "NotSubscribedError", 226 | "type": "class", 227 | "description": "This error is raised (by an OSCMultiClient) when an attempt is made to unsubscribe a host\n\tthat isn't subscribed." 228 | }, 229 | { 230 | "text": "NumberKey", 231 | "type": "class" 232 | }, 233 | { 234 | "text": "OSCAddressSpace", 235 | "type": "class" 236 | }, 237 | { 238 | "text": "OSCBundle", 239 | "type": "class", 240 | "description": "Builds a 'bundle' of OSC messages.\n\t\n\tOSCBundle objects are container objects for building OSC-bundles of OSC-messages.\n\tAn OSC-bundle is a special kind of OSC-message which contains a list of OSC-messages\n\t(And yes, OSC-bundles may contain other OSC-bundles...)\n\t\n\tOSCBundle objects behave much the same as OSCMessage objects, with these exceptions:\n\t - if an item or items to be appended or inserted are not OSCMessage objects, \n\t OSCMessage objectss are created to encapsulate the item(s)\n\t - an OSC-bundle does not have an address of its own, only the contained OSC-messages do.\n\t The OSCBundle's 'address' is inherited by any OSCMessage the OSCBundle object creates.\n\t - OSC-bundles have a timetag to tell the receiver when the bundle should be processed.\n\t The default timetag value (0) means 'immediately'" 241 | }, 242 | { 243 | "text": "OSCClient", 244 | "type": "class", 245 | "description": "Simple OSC Client. Handles the sending of OSC-Packets (OSCMessage or OSCBundle) via a UDP-socket" 246 | }, 247 | { 248 | "text": "OSCClientError", 249 | "type": "class", 250 | "description": "Class for all OSCClient errors" 251 | }, 252 | { 253 | "text": "OSCConnect", 254 | "type": "class" 255 | }, 256 | { 257 | "text": "OSCError", 258 | "type": "class", 259 | "description": "Base Class for all OSC-related errors" 260 | }, 261 | { 262 | "text": "OSCMessage", 263 | "type": "class", 264 | "description": "Builds typetagged OSC messages. \n\t\n\tOSCMessage objects are container objects for building OSC-messages.\n\tOn the 'front' end, they behave much like list-objects, and on the 'back' end\n\tthey generate a binary representation of the message, which can be sent over a network socket.\n\tOSC-messages consist of an 'address'-string (not to be confused with a (host, port) IP-address!),\n\tfollowed by a string of 'typetags' associated with the message's arguments (ie. 'payload'), \n\tand finally the arguments themselves, encoded in an OSC-specific way.\n\t\n\tOn the Python end, OSCMessage are lists of arguments, prepended by the message's address.\n\tThe message contents can be manipulated much like a list:\n\t >>> msg = OSCMessage(\"/my/osc/address\")\n\t >>> msg.append('something')\n\t >>> msg.insert(0, 'something else')\n\t >>> msg[1] = 'entirely'\n\t >>> msg.extend([1,2,3.])\n\t >>> msg += [4, 5, 6.]\n\t >>> del msg[3:6]\n\t >>> msg.pop(-2)\n\t 5\n\t >>> print msg\n\t /my/osc/address ['something else', 'entirely', 1, 6.0]\n\n\tOSCMessages can be concatenated with the + operator. In this case, the resulting OSCMessage\n\tinherits its address from the left-hand operand. The right-hand operand's address is ignored.\n\tTo construct an 'OSC-bundle' from multiple OSCMessage, see OSCBundle!\n\t\n\tAdditional methods exist for retreiving typetags or manipulating items as (typetag, value) tuples." 265 | }, 266 | { 267 | "text": "OSCMultiClient", 268 | "type": "class", 269 | "description": "'Multiple-Unicast' OSC Client. Handles the sending of OSC-Packets (OSCMessage or OSCBundle) via a UDP-socket\n\tThis client keeps a dict of 'OSCTargets'. and sends each OSCMessage to each OSCTarget\n\tThe OSCTargets are simply (host, port) tuples, and may be associated with an OSC-address prefix.\n\tthe OSCTarget's prefix gets prepended to each OSCMessage sent to that target." 270 | }, 271 | { 272 | "text": "OSCRequestHandler", 273 | "type": "class", 274 | "description": "RequestHandler class for the OSCServer" 275 | }, 276 | { 277 | "text": "OSCServer", 278 | "type": "class", 279 | "description": "A Synchronous OSCServer\n\tServes one request at-a-time, until the OSCServer is closed.\n\tThe OSC address-pattern is matched against a set of OSC-adresses\n\tthat have been registered to the server with a callback-function.\n\tIf the adress-pattern of the message machtes the registered address of a callback,\n\tthat function is called." 280 | }, 281 | { 282 | "text": "OSCServerError", 283 | "type": "class", 284 | "description": "Class for all OSCServer errors" 285 | }, 286 | { 287 | "text": "OSCStreamRequestHandler", 288 | "type": "class", 289 | "description": "This is the central class of a streaming OSC server. If a client\n\tconnects to the server, the server instantiates a OSCStreamRequestHandler\n\tfor each new connection. This is fundamentally different to a packet\n\toriented server which has a single address space for all connections.\n\tThis connection based (streaming) OSC server maintains an address space\n\tfor each single connection, because usually tcp server spawn a new thread\n\tor process for each new connection. This would generate severe\n\tmultithreading synchronization problems when each thread would operate on\n\tthe same address space object. Therefore: To implement a streaming/TCP OSC\n\tserver a custom handler must be implemented which implements the\n\tsetupAddressSpace member in which it creates its own address space for this\n\tvery connection. This has been done within the testbench and can serve as\n\tinspiration." 290 | }, 291 | { 292 | "text": "OSCStreamingClient", 293 | "type": "class", 294 | "description": "OSC streaming client.\n\tA streaming client establishes a connection to a streaming server but must\n\tbe able to handle replies by the server as well. To accomplish this the\n\treceiving takes place in a secondary thread, because no one knows if we\n\thave to expect a reply or not, i.e. synchronous architecture doesn't make\n\tmuch sense.\n\tReplies will be matched against the local address space. If message\n\thandlers access code of the main thread (where the client messages are sent\n\tto the server) care must be taken e.g. by installing sychronization\n\tmechanisms or by using an event dispatcher which can handle events\n\toriginating from other threads." 295 | }, 296 | { 297 | "text": "OSCStreamingServer", 298 | "type": "class", 299 | "description": "A connection oriented (TCP/IP) OSC server." 300 | }, 301 | { 302 | "text": "OSCStreamingServerThreading", 303 | "type": "class" 304 | }, 305 | { 306 | "text": "Or", 307 | "type": "function" 308 | }, 309 | { 310 | "text": "P", 311 | "type": "function", 312 | "description": "Used to define lists as patterns:\n\n `P[1,2,3]` is equivalent to `Pattern([1,2,3])` and\n `P(1,2,3)` is equivalent to `Pattern((1,2,3))` and\n `P+(1,2,3)` is equivalient to `Pattern((1,2,3))`.\n\n Ranges can be created using slicing, e.g. `P[1:6:2]` will generate the range\n 1 to 6 in steps of 2, thus creating the Pattern `[1, 3, 5]`. Slices can be\n combined with other values in a Pattern such that `P[0,2,1:10]` will return\n the Pattern `P[0, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9]`" 313 | }, 314 | { 315 | "text": "P10", 316 | "type": "function", 317 | "description": "Returns an n-length Pattern of a randomly generated series of 1's and 0's" 318 | }, 319 | { 320 | "text": "PAlt", 321 | "type": "function", 322 | "description": "Returns a Pattern generated by alternating the values in the given sequences" 323 | }, 324 | { 325 | "text": "PBeat", 326 | "type": "function", 327 | "description": "Returns a Pattern of durations based on an input string where\n non-whitespace denote a pulse e.g.\n ```\n >>> PTab(\"x xxx x\")\n P[1, 0.5, 0.5, 1, 0.5]" 328 | }, 329 | { 330 | "text": "PChain", 331 | "type": "class" 332 | }, 333 | { 334 | "text": "PDelay", 335 | "type": "function" 336 | }, 337 | { 338 | "text": "PDur", 339 | "type": "function", 340 | "description": "Returns the *actual* durations based on Euclidean rhythms (see PEuclid) where dur\n is the length of each step.\n e.g. `PDur(3, 8)` will return `P[0.75, 0.75, 0.5]`" 341 | }, 342 | { 343 | "text": "PEq", 344 | "type": "function" 345 | }, 346 | { 347 | "text": "PEuclid", 348 | "type": "function", 349 | "description": "Returns the Euclidean rhythm which spreads 'n' pulses over 'k' steps as evenly as possible.\n e.g. `PEuclid(3, 8)` will return `P[1, 0, 0, 1, 0, 0, 1, 0]`" 350 | }, 351 | { 352 | "text": "PEuclid2", 353 | "type": "function", 354 | "description": "Same as PEuclid except it returns an array filled with 'lo' value instead of 0\n and 'hi' value instead of 1. Can be used to generate characters patterns used to\n play sample like play(PEuclid2(3,8,'-','X')) will be equivalent to\n play(P['X', '-', '-', 'X', '-', '-', 'X', '-'])\n that's like saying play(\"X--X--X-\")" 355 | }, 356 | { 357 | "text": "PFibMod", 358 | "type": "class", 359 | "description": "Returns the fibonacci sequence -- maybe a bad idea" 360 | }, 361 | { 362 | "text": "PGroup", 363 | "type": "class", 364 | "description": "Class to represent any groupings of notes as denoted by brackets.\n PGroups should only be found within a Pattern object." 365 | }, 366 | { 367 | "text": "PGroupDiv", 368 | "type": "class", 369 | "description": "Stutter every other request" 370 | }, 371 | { 372 | "text": "PGroupMod", 373 | "type": "class", 374 | "description": "Useful for when you want many nested groups. This PGroup flattens the original\n but the delay times are calculated in the same way as if the values were neseted" 375 | }, 376 | { 377 | "text": "PGroupPlus", 378 | "type": "class", 379 | "description": "Stutters the values over the length of and event's 'sus'" 380 | }, 381 | { 382 | "text": "PGroupPow", 383 | "type": "class", 384 | "description": "Stutters a shuffled version the values over the length of and event's 'dur'" 385 | }, 386 | { 387 | "text": "PGroupPrime", 388 | "type": "class" 389 | }, 390 | { 391 | "text": "PGroupStar", 392 | "type": "class", 393 | "description": "Stutters the values over the length of and event's 'dur'" 394 | }, 395 | { 396 | "text": "PGroupXor", 397 | "type": "class", 398 | "description": "The delay of this PGroup is s" 399 | }, 400 | { 401 | "text": "PIndex", 402 | "type": "class", 403 | "description": "Returns the index being accessed" 404 | }, 405 | { 406 | "text": "PJoin", 407 | "type": "function" 408 | }, 409 | { 410 | "text": "PNe", 411 | "type": "function" 412 | }, 413 | { 414 | "text": "POperand", 415 | "type": "class" 416 | }, 417 | { 418 | "text": "PPairs", 419 | "type": "function", 420 | "description": "Laces a sequence with a second sequence obtained\n by performing a function on the original. By default this is\n `lambda n: 8 - n`." 421 | }, 422 | { 423 | "text": "PQuicken", 424 | "type": "function" 425 | }, 426 | { 427 | "text": "PRand", 428 | "type": "class", 429 | "description": "Returns a random integer between start and stop. If start is a container-type it returns\n a random item for that container." 430 | }, 431 | { 432 | "text": "PRange", 433 | "type": "function", 434 | "description": "Returns a Pattern equivalent to `Pattern(range(start, stop, step))" 435 | }, 436 | { 437 | "text": "PRhythm", 438 | "type": "function", 439 | "description": "[1,(3,8)] -> [(1,2.75,3.5),2]\n *work in progress*" 440 | }, 441 | { 442 | "text": "PShuf", 443 | "type": "function", 444 | "description": "PShuf(seq) -> Returns a shuffled version of seq" 445 | }, 446 | { 447 | "text": "PSine", 448 | "type": "function", 449 | "description": "Returns values of one cycle of sine wave split into 'n' parts" 450 | }, 451 | { 452 | "text": "PSq", 453 | "type": "function", 454 | "description": "Returns a Pattern" 455 | }, 456 | { 457 | "text": "PSquare", 458 | "type": "class", 459 | "description": "Returns the square of the index being accessed" 460 | }, 461 | { 462 | "text": "PStep", 463 | "type": "function", 464 | "description": "Returns a Pattern that every n-term is 'value' otherwise 'default'" 465 | }, 466 | { 467 | "text": "PStretch", 468 | "type": "function", 469 | "description": "Returns 'seq' as a Pattern and looped until its length is 'size'\n e.g. `PStretch([0,1,2], 5)` returns `P[0, 1, 2, 0, 1]`" 470 | }, 471 | { 472 | "text": "PStutter", 473 | "type": "function", 474 | "description": "PStutter(seq, n) -> Creates a pattern such that each item in the array is repeated n times (n can be a pattern)" 475 | }, 476 | { 477 | "text": "PSum", 478 | "type": "function", 479 | "description": "Returns a Pattern of length 'n' that sums to equal 'total'\n\n ```\n e.g. PSum(3,8) -> P[3, 3, 2]\n PSum(5,4) -> P[1, 0.75, 0.75, 0.75, 0.75]\n ```" 480 | }, 481 | { 482 | "text": "PTree", 483 | "type": "class", 484 | "description": "Takes a starting value and two functions as arguments. The first function, f, must\n take one value and return a container-type of values and the second function, choose,\n must take a container-type and return a single value. In essence you are creating a\n tree based on the f(n) where n is the last value chosen by choose." 485 | }, 486 | { 487 | "text": "PTri", 488 | "type": "function", 489 | "description": "Returns a Pattern equivalent to `Pattern(range(start, stop, step)) with its reversed form appended." 490 | }, 491 | { 492 | "text": "PWalk", 493 | "type": "class" 494 | }, 495 | { 496 | "text": "PWhite", 497 | "type": "class", 498 | "description": "Returns random floating point values between 'lo' and 'hi'" 499 | }, 500 | { 501 | "text": "PZip", 502 | "type": "function", 503 | "description": "Creates a Pattern that 'zips' together multiple patterns. `PZip([0,1,2], [3,4])`\n will create the Pattern `P[(0, 3), (1, 4), (2, 3), (0, 4), (1, 3), (2, 4)]`" 504 | }, 505 | { 506 | "text": "PZip2", 507 | "type": "function", 508 | "description": "Like `PZip` but only uses two Patterns. Zips together values if they satisfy the rule." 509 | }, 510 | { 511 | "text": "ParseError", 512 | "type": "class" 513 | }, 514 | { 515 | "text": "Pattern", 516 | "type": "class", 517 | "description": "Base type pattern" 518 | }, 519 | { 520 | "text": "PatternContainer", 521 | "type": "class" 522 | }, 523 | { 524 | "text": "PatternFormat", 525 | "type": "function", 526 | "description": "If data is a list, returns Pattern(data). If data is a tuple, returns PGroup(data).\n Returns data if neither." 527 | }, 528 | { 529 | "text": "PatternMethod", 530 | "type": "function", 531 | "description": "Decorator that makes a function into a metaPattern method" 532 | }, 533 | { 534 | "text": "PlayString", 535 | "type": "class", 536 | "description": "Container for character objects" 537 | }, 538 | { 539 | "text": "Player", 540 | "type": "class", 541 | "description": "FoxDot generates music by creating instances of `Player` and giving them instructions\n to follow. At startup FoxDot creates many instances of `Player` and assigns them to\n any valid two character variable. This is so that when you start playing you don't \n have to worry about typing `myPlayer = Player()` and `myPlayer_2 = Player()` every\n time you want to do something new. Of course there is nothing stopping you from \n doing that if yo so wish.\n\n Instances of `Player` are given instructions to generate music using the `>>` syntax,\n overriding the bitshift operator, and should be given an instance of `SynthDefProxy`.\n A `SynthDefProxy` is created when calling an instance of `SynthDef` - these are the\n \"instruments\" used by player objects and are written in SuperCollider code. You can\n see more information about these in the `SCLang` module. Below describes how to assign\n a `SynthDefProxy` of the `SynthDef` `pads` to a `Player` instance called `p1`:\n\n ```python\n # Calling pads as if it were a function returns a \n # pads SynthDefProxy object which is assigned to p1\n p1 >> pads()\n\n # You could store several instances and assign them at different times\n proxy_1 = pads([0,1,2,3], dur=1/2)\n proxy_2 = pads([4,5,6,7], dur=1)\n\n p1 >> proxy_1 # Assign the first to p1\n p1 >> proxy_2 # This replaces the instructions being followed by p1\n ```" 542 | }, 543 | { 544 | "text": "PlayerKey", 545 | "type": "class" 546 | }, 547 | { 548 | "text": "PlayerKeyException", 549 | "type": "class" 550 | }, 551 | { 552 | "text": "Pow", 553 | "type": "function" 554 | }, 555 | { 556 | "text": "PulsesToDurations", 557 | "type": "function", 558 | "description": "Returns a list of durations based on pulses (1s) and blanks (0s).\n Data should be a list of [1,0] where 1 is a pulse." 559 | }, 560 | { 561 | "text": "Pvar", 562 | "type": "function", 563 | "description": "A TimeVar that represents Patterns that change over time e.g.\n ```\n >>> a = Pvar([ [0,1,2,3], [4,5] ], 4)\n >>> print a # time is 0\n P[0, 1, 2, 3]\n >>> print a # time is 4\n P[4, 5]" 564 | }, 565 | { 566 | "text": "Pvar", 567 | "type": "class", 568 | "description": "A TimeVar that represents Patterns that change over time e.g.\n ```\n >>> a = Pvar([ [0,1,2,3], [4,5] ], 4)\n >>> print a # time is 0\n P[0, 1, 2, 3]\n >>> print a # time is 4\n P[4, 5]" 569 | }, 570 | { 571 | "text": "PvarGenerator", 572 | "type": "class", 573 | "description": "If a TimeVar is used in a Pattern function e.g. `PDur(var([3,5]), 8)`\n then a `PvarGenerator` is returned. Each argument is stored as a TimeVar\n and the function is called whenever the arguments are changed" 574 | }, 575 | { 576 | "text": "PvarGeneratorEx", 577 | "type": "class", 578 | "description": "Un-Documented" 579 | }, 580 | { 581 | "text": "PwRand", 582 | "type": "class" 583 | }, 584 | { 585 | "text": "PxRand", 586 | "type": "class" 587 | }, 588 | { 589 | "text": "Queue", 590 | "type": "class" 591 | }, 592 | { 593 | "text": "QueueBlock", 594 | "type": "class" 595 | }, 596 | { 597 | "text": "QueueObj", 598 | "type": "class", 599 | "description": "Class representing each item in a `QueueBlock` instance" 600 | }, 601 | { 602 | "text": "Repeatable", 603 | "type": "class" 604 | }, 605 | { 606 | "text": "RequestHandler", 607 | "type": "class", 608 | "description": "Created whenever a new connection to the server is made:\n self.request = socket\n self.server = Server instance\n self.client_address = (address, port)" 609 | }, 610 | { 611 | "text": "RequestTimeout", 612 | "type": "class", 613 | "description": "Raised if expecting a response from the server but received none" 614 | }, 615 | { 616 | "text": "Root", 617 | "type": "constant" 618 | }, 619 | { 620 | "text": "SCLangBidirectionalClient", 621 | "type": "class", 622 | "description": "This is a combination client/server\n\n The UDP server is necessary for receiving responses from the SCLang server\n when we query it with requests.\n\n Note that this is not thread-safe, as the receive() method can discard messages" 623 | }, 624 | { 625 | "text": "SCLangClient", 626 | "type": "class" 627 | }, 628 | { 629 | "text": "SCLangServerManager", 630 | "type": "class" 631 | }, 632 | { 633 | "text": "SampleSynthDef", 634 | "type": "class" 635 | }, 636 | { 637 | "text": "Samples", 638 | "type": "constant" 639 | }, 640 | { 641 | "text": "Scale", 642 | "type": "constant" 643 | }, 644 | { 645 | "text": "Scale.chromatic", 646 | "type": "constant" 647 | }, 648 | { 649 | "text": "Scale.default", 650 | "type": "variable" 651 | }, 652 | { 653 | "text": "Scale.dorian", 654 | "type": "constant" 655 | }, 656 | { 657 | "text": "Scale.dorian2", 658 | "type": "constant" 659 | }, 660 | { 661 | "text": "Scale.egyptian", 662 | "type": "constant" 663 | }, 664 | { 665 | "text": "Scale.freq", 666 | "type": "constant" 667 | }, 668 | { 669 | "text": "Scale.harmonicMajor", 670 | "type": "constant" 671 | }, 672 | { 673 | "text": "Scale.harmonicMinor", 674 | "type": "constant" 675 | }, 676 | { 677 | "text": "Scale.indian", 678 | "type": "constant" 679 | }, 680 | { 681 | "text": "Scale.justMajor", 682 | "type": "constant" 683 | }, 684 | { 685 | "text": "Scale.justMinor", 686 | "type": "constant" 687 | }, 688 | { 689 | "text": "Scale.locrian", 690 | "type": "constant" 691 | }, 692 | { 693 | "text": "Scale.locrianMajor", 694 | "type": "constant" 695 | }, 696 | { 697 | "text": "Scale.lydian", 698 | "type": "constant" 699 | }, 700 | { 701 | "text": "Scale.lydianMinor", 702 | "type": "constant" 703 | }, 704 | { 705 | "text": "Scale.major", 706 | "type": "constant" 707 | }, 708 | { 709 | "text": "Scale.majorPentatonic", 710 | "type": "constant" 711 | }, 712 | { 713 | "text": "Scale.melodicMinor", 714 | "type": "constant" 715 | }, 716 | { 717 | "text": "Scale.minor", 718 | "type": "constant" 719 | }, 720 | { 721 | "text": "Scale.minorPentatonic", 722 | "type": "constant" 723 | }, 724 | { 725 | "text": "Scale.mixolydian", 726 | "type": "constant" 727 | }, 728 | { 729 | "text": "Scale.phrygian", 730 | "type": "constant" 731 | }, 732 | { 733 | "text": "Scale.prometheus", 734 | "type": "constant" 735 | }, 736 | { 737 | "text": "Scale.ryan", 738 | "type": "constant" 739 | }, 740 | { 741 | "text": "Scale.zhi", 742 | "type": "constant" 743 | }, 744 | { 745 | "text": "ScalePattern", 746 | "type": "class" 747 | }, 748 | { 749 | "text": "ScheduleError", 750 | "type": "class" 751 | }, 752 | { 753 | "text": "ServerInfo", 754 | "type": "class", 755 | "description": "ServerInfo(sample_rate, actual_sample_rate, num_synths, num_groups, num_audio_bus_channels, num_control_bus_channels, num_input_bus_channels, num_output_bus_channels, num_buffers, max_nodes, max_synth_defs)" 756 | }, 757 | { 758 | "text": "ServerManager", 759 | "type": "class" 760 | }, 761 | { 762 | "text": "SoloPlayer", 763 | "type": "class", 764 | "description": "SoloPlayer objects" 765 | }, 766 | { 767 | "text": "StaticPatternMethod", 768 | "type": "function", 769 | "description": "Decorator that makes a function into a metaPattern static method" 770 | }, 771 | { 772 | "text": "StreamRequestHandler", 773 | "type": "class", 774 | "description": "Define self.rfile and self.wfile for stream sockets." 775 | }, 776 | { 777 | "text": "Sub", 778 | "type": "function" 779 | }, 780 | { 781 | "text": "SynthDef", 782 | "type": "class" 783 | }, 784 | { 785 | "text": "SynthDefProxy", 786 | "type": "class" 787 | }, 788 | { 789 | "text": "TCPServer", 790 | "type": "class", 791 | "description": "Base class for various socket-based server classes.\n\n Defaults to synchronous IP stream (i.e., TCP).\n\n Methods for the caller:\n\n - __init__(server_address, RequestHandlerClass, bind_and_activate=True)\n - serve_forever(poll_interval=0.5)\n - shutdown()\n - handle_request() # if you don't use serve_forever()\n - fileno() -> int # for selector\n\n Methods that may be overridden:\n\n - server_bind()\n - server_activate()\n - get_request() -> request, client_address\n - handle_timeout()\n - verify_request(request, client_address)\n - process_request(request, client_address)\n - shutdown_request(request)\n - close_request(request)\n - handle_error()\n\n Methods for derived classes:\n\n - finish_request(request, client_address)\n\n Class variables that may be overridden by derived classes or\n instances:\n\n - timeout\n - address_family\n - socket_type\n - request_queue_size (only for stream sockets)\n - allow_reuse_address\n\n Instance variables:\n\n - server_address\n - RequestHandlerClass\n - socket" 792 | }, 793 | { 794 | "text": "TempoClient", 795 | "type": "class" 796 | }, 797 | { 798 | "text": "TempoClock", 799 | "type": "class" 800 | }, 801 | { 802 | "text": "TempoServer", 803 | "type": "class", 804 | "description": "Used in TempoClock.py to connect to instances of FoxDot over a network. Sends\n bpm changes over the network. On initial request this sends the start_time value\n of the clock" 805 | }, 806 | { 807 | "text": "Thread", 808 | "type": "class", 809 | "description": "A class that represents a thread of control.\n\n This class can be safely subclassed in a limited fashion. There are two ways\n to specify the activity: by passing a callable object to the constructor, or\n by overriding the run() method in a subclass." 810 | }, 811 | { 812 | "text": "ThreadedServer", 813 | "type": "class", 814 | "description": "Base class" 815 | }, 816 | { 817 | "text": "ThreadingMixIn", 818 | "type": "class", 819 | "description": "Mix-in class to handle each request in a new thread." 820 | }, 821 | { 822 | "text": "ThreadingOSCRequestHandler", 823 | "type": "class", 824 | "description": "Multi-threaded OSCRequestHandler;\n\tStarts a new RequestHandler thread for each unbundled OSCMessage" 825 | }, 826 | { 827 | "text": "ThreadingOSCServer", 828 | "type": "class", 829 | "description": "An Asynchronous OSCServer.\n\tThis server starts a new thread to handle each incoming request." 830 | }, 831 | { 832 | "text": "TimeVar", 833 | "type": "class", 834 | "description": "Var(values [,durs=[4]])" 835 | }, 836 | { 837 | "text": "TypeType", 838 | "type": "class", 839 | "description": "type(object_or_name, bases, dict)\ntype(object) -> the object's type\ntype(name, bases, dict) -> a new type" 840 | }, 841 | { 842 | "text": "UDPServer", 843 | "type": "class", 844 | "description": "UDP server class." 845 | }, 846 | { 847 | "text": "Wrapper", 848 | "type": "class" 849 | }, 850 | { 851 | "text": "Xor", 852 | "type": "function" 853 | }, 854 | { 855 | "text": "accompany", 856 | "type": "method" 857 | }, 858 | { 859 | "text": "addfx", 860 | "type": "method" 861 | }, 862 | { 863 | "text": "after", 864 | "type": "method" 865 | }, 866 | { 867 | "text": "ambi", 868 | "type": "function" 869 | }, 870 | { 871 | "text": "amp", 872 | "type": "property" 873 | }, 874 | { 875 | "text": "amplify", 876 | "type": "property" 877 | }, 878 | { 879 | "text": "arpy", 880 | "type": "function" 881 | }, 882 | { 883 | "text": "asPattern", 884 | "type": "function" 885 | }, 886 | { 887 | "text": "asStream", 888 | "type": "function", 889 | "description": "Forces any data into a [pattern] form" 890 | }, 891 | { 892 | "text": "audioin", 893 | "type": "function" 894 | }, 895 | { 896 | "text": "bang", 897 | "type": "method" 898 | }, 899 | { 900 | "text": "bass", 901 | "type": "function" 902 | }, 903 | { 904 | "text": "bell", 905 | "type": "function" 906 | }, 907 | { 908 | "text": "bend", 909 | "type": "property" 910 | }, 911 | { 912 | "text": "benddelay", 913 | "type": "property" 914 | }, 915 | { 916 | "text": "bits", 917 | "type": "property" 918 | }, 919 | { 920 | "text": "blip", 921 | "type": "function" 922 | }, 923 | { 924 | "text": "blur", 925 | "type": "property" 926 | }, 927 | { 928 | "text": "bpf", 929 | "type": "property" 930 | }, 931 | { 932 | "text": "bpm", 933 | "type": "property" 934 | }, 935 | { 936 | "text": "bpnoise", 937 | "type": "property" 938 | }, 939 | { 940 | "text": "bpr", 941 | "type": "property" 942 | }, 943 | { 944 | "text": "braces_type", 945 | "type": "class", 946 | "description": "Returns a random integer between start and stop. If start is a container-type it returns\n a random item for that container." 947 | }, 948 | { 949 | "text": "buf", 950 | "type": "property" 951 | }, 952 | { 953 | "text": "bug", 954 | "type": "function" 955 | }, 956 | { 957 | "text": "changeSynth", 958 | "type": "method" 959 | }, 960 | { 961 | "text": "channel", 962 | "type": "property" 963 | }, 964 | { 965 | "text": "charm", 966 | "type": "function" 967 | }, 968 | { 969 | "text": "chop", 970 | "type": "property" 971 | }, 972 | { 973 | "text": "cls", 974 | "type": "class" 975 | }, 976 | { 977 | "text": "coarse", 978 | "type": "property" 979 | }, 980 | { 981 | "text": "const", 982 | "type": "class", 983 | "description": "A number value that cannot be changed" 984 | }, 985 | { 986 | "text": "count", 987 | "type": "method" 988 | }, 989 | { 990 | "text": "creep", 991 | "type": "function" 992 | }, 993 | { 994 | "text": "crunch", 995 | "type": "function" 996 | }, 997 | { 998 | "text": "crush", 999 | "type": "property" 1000 | }, 1001 | { 1002 | "text": "cut", 1003 | "type": "property" 1004 | }, 1005 | { 1006 | "text": "dab", 1007 | "type": "function" 1008 | }, 1009 | { 1010 | "text": "decay", 1011 | "type": "property" 1012 | }, 1013 | { 1014 | "text": "deepcopy", 1015 | "type": "function", 1016 | "description": "Deep copy operation on arbitrary Python objects.\n\n See the module's __doc__ string for more info." 1017 | }, 1018 | { 1019 | "text": "default_root", 1020 | "type": "method" 1021 | }, 1022 | { 1023 | "text": "default_scale", 1024 | "type": "method" 1025 | }, 1026 | { 1027 | "text": "degrade", 1028 | "type": "method" 1029 | }, 1030 | { 1031 | "text": "degree", 1032 | "type": "property" 1033 | }, 1034 | { 1035 | "text": "delay", 1036 | "type": "property" 1037 | }, 1038 | { 1039 | "text": "dirt", 1040 | "type": "function" 1041 | }, 1042 | { 1043 | "text": "dist", 1044 | "type": "property" 1045 | }, 1046 | { 1047 | "text": "donk", 1048 | "type": "function" 1049 | }, 1050 | { 1051 | "text": "dots", 1052 | "type": "class", 1053 | "description": "Class for representing long Patterns in strings" 1054 | }, 1055 | { 1056 | "text": "dub", 1057 | "type": "function" 1058 | }, 1059 | { 1060 | "text": "dur", 1061 | "type": "property" 1062 | }, 1063 | { 1064 | "text": "dur_updated", 1065 | "type": "method" 1066 | }, 1067 | { 1068 | "text": "echo", 1069 | "type": "property" 1070 | }, 1071 | { 1072 | "text": "env", 1073 | "type": "property" 1074 | }, 1075 | { 1076 | "text": "equal_values", 1077 | "type": "function", 1078 | "description": "Returns True if this == that" 1079 | }, 1080 | { 1081 | "text": "every", 1082 | "type": "method" 1083 | }, 1084 | { 1085 | "text": "expvar", 1086 | "type": "function" 1087 | }, 1088 | { 1089 | "text": "expvar", 1090 | "type": "class" 1091 | }, 1092 | { 1093 | "text": "fmod", 1094 | "type": "property" 1095 | }, 1096 | { 1097 | "text": "follow", 1098 | "type": "method" 1099 | }, 1100 | { 1101 | "text": "formant", 1102 | "type": "property" 1103 | }, 1104 | { 1105 | "text": "freq", 1106 | "type": "property" 1107 | }, 1108 | { 1109 | "text": "fuzz", 1110 | "type": "function" 1111 | }, 1112 | { 1113 | "text": "get_attributes", 1114 | "type": "method" 1115 | }, 1116 | { 1117 | "text": "get_event", 1118 | "type": "method" 1119 | }, 1120 | { 1121 | "text": "get_event_length", 1122 | "type": "method" 1123 | }, 1124 | { 1125 | "text": "get_expanded_len", 1126 | "type": "function", 1127 | "description": "(0,(0,2)) returns 4. int returns 1" 1128 | }, 1129 | { 1130 | "text": "get_inverse_op", 1131 | "type": "function", 1132 | "description": "Returns the opposite __dunder__ method e.g.\n get_inverse_op(\"__add__\") -> \"__radd__\"\n get_inverse_op(\"__ror__\") -> \"__or__\"" 1133 | }, 1134 | { 1135 | "text": "get_key", 1136 | "type": "method" 1137 | }, 1138 | { 1139 | "text": "get_method_by_name", 1140 | "type": "method" 1141 | }, 1142 | { 1143 | "text": "get_prime_funcs", 1144 | "type": "method" 1145 | }, 1146 | { 1147 | "text": "get_synth_name", 1148 | "type": "method" 1149 | }, 1150 | { 1151 | "text": "glass", 1152 | "type": "function" 1153 | }, 1154 | { 1155 | "text": "gong", 1156 | "type": "function" 1157 | }, 1158 | { 1159 | "text": "group_modi", 1160 | "type": "function", 1161 | "description": "Returns value from pgroup that modular indexes nested groups" 1162 | }, 1163 | { 1164 | "text": "growl", 1165 | "type": "function" 1166 | }, 1167 | { 1168 | "text": "hpf", 1169 | "type": "property" 1170 | }, 1171 | { 1172 | "text": "hpr", 1173 | "type": "property" 1174 | }, 1175 | { 1176 | "text": "inf", 1177 | "type": "constant", 1178 | "description": "Un-implemented" 1179 | }, 1180 | { 1181 | "text": "info", 1182 | "type": "method" 1183 | }, 1184 | { 1185 | "text": "instance", 1186 | "type": "class" 1187 | }, 1188 | { 1189 | "text": "karp", 1190 | "type": "function" 1191 | }, 1192 | { 1193 | "text": "kill", 1194 | "type": "method" 1195 | }, 1196 | { 1197 | "text": "klank", 1198 | "type": "function" 1199 | }, 1200 | { 1201 | "text": "largest_attribute", 1202 | "type": "method" 1203 | }, 1204 | { 1205 | "text": "lazer", 1206 | "type": "function" 1207 | }, 1208 | { 1209 | "text": "linvar", 1210 | "type": "function" 1211 | }, 1212 | { 1213 | "text": "linvar", 1214 | "type": "class" 1215 | }, 1216 | { 1217 | "text": "long", 1218 | "type": "class", 1219 | "description": "int(x=0) -> integer\nint(x, base=10) -> integer\n\nConvert a number or string to an integer, or return 0 if no arguments\nare given. If x is a number, return x.__int__(). For floating point\nnumbers, this truncates towards zero.\n\nIf x is not a number or if base is given, then x must be a string,\nbytes, or bytearray instance representing an integer literal in the\ngiven base. The literal can be preceded by '+' or '-' and be surrounded\nby whitespace. The base defaults to 10. Valid bases are 0 and 2-36.\nBase 0 means to interpret the base from the string as an integer literal.\n>>> int('0b100', base=0)\n4" 1220 | }, 1221 | { 1222 | "text": "loop", 1223 | "type": "function" 1224 | }, 1225 | { 1226 | "text": "loop_pattern_func", 1227 | "type": "function", 1228 | "description": "Decorator for allowing any Pattern function to create\n multiple Patterns by using Patterns or TimeVars as arguments" 1229 | }, 1230 | { 1231 | "text": "loop_pattern_method", 1232 | "type": "function", 1233 | "description": "Decorator for allowing any Pattern method to create\n multiple (or rather, longer) Patterns by using Patterns as arguments" 1234 | }, 1235 | { 1236 | "text": "lpf", 1237 | "type": "property" 1238 | }, 1239 | { 1240 | "text": "lpr", 1241 | "type": "property" 1242 | }, 1243 | { 1244 | "text": "lshift", 1245 | "type": "method" 1246 | }, 1247 | { 1248 | "text": "map", 1249 | "type": "method" 1250 | }, 1251 | { 1252 | "text": "mapvar", 1253 | "type": "class", 1254 | "description": "Like a `Pvar`, the `mapvar` returns a whole `Pattern` as opposed to a single\n value, but instead of using the global clock to find the current value it\n uses the value in an instance of the `PlayerKey` class." 1255 | }, 1256 | { 1257 | "text": "mapvar", 1258 | "type": "function", 1259 | "description": "Like a `Pvar`, the `mapvar` returns a whole `Pattern` as opposed to a single\n value, but instead of using the global clock to find the current value it\n uses the value in an instance of the `PlayerKey` class." 1260 | }, 1261 | { 1262 | "text": "marimba", 1263 | "type": "function" 1264 | }, 1265 | { 1266 | "text": "max_length", 1267 | "type": "function", 1268 | "description": "Returns the largest length pattern" 1269 | }, 1270 | { 1271 | "text": "metaPattern", 1272 | "type": "class", 1273 | "description": "Abstract base class for Patterns" 1274 | }, 1275 | { 1276 | "text": "midinote", 1277 | "type": "property" 1278 | }, 1279 | { 1280 | "text": "mirror", 1281 | "type": "method" 1282 | }, 1283 | { 1284 | "text": "mix", 1285 | "type": "property" 1286 | }, 1287 | { 1288 | "text": "modi", 1289 | "type": "function", 1290 | "description": "Returns the modulo index i.e. modi([0,1,2],4) will return 1" 1291 | }, 1292 | { 1293 | "text": "multiply", 1294 | "type": "method" 1295 | }, 1296 | { 1297 | "text": "never", 1298 | "type": "method" 1299 | }, 1300 | { 1301 | "text": "new_message", 1302 | "type": "method" 1303 | }, 1304 | { 1305 | "text": "noise", 1306 | "type": "function" 1307 | }, 1308 | { 1309 | "text": "now", 1310 | "type": "method" 1311 | }, 1312 | { 1313 | "text": "num_key_references", 1314 | "type": "method" 1315 | }, 1316 | { 1317 | "text": "number_attr", 1318 | "type": "method" 1319 | }, 1320 | { 1321 | "text": "number_of_layers", 1322 | "type": "method" 1323 | }, 1324 | { 1325 | "text": "nylon", 1326 | "type": "function" 1327 | }, 1328 | { 1329 | "text": "oct", 1330 | "type": "property" 1331 | }, 1332 | { 1333 | "text": "offbeat", 1334 | "type": "method" 1335 | }, 1336 | { 1337 | "text": "only", 1338 | "type": "method" 1339 | }, 1340 | { 1341 | "text": "orient", 1342 | "type": "function" 1343 | }, 1344 | { 1345 | "text": "osc_message", 1346 | "type": "method" 1347 | }, 1348 | { 1349 | "text": "pads", 1350 | "type": "function" 1351 | }, 1352 | { 1353 | "text": "pan", 1354 | "type": "property" 1355 | }, 1356 | { 1357 | "text": "partial", 1358 | "type": "class", 1359 | "description": "partial(func, *args, **keywords) - new function with partial application\n of the given arguments and keywords." 1360 | }, 1361 | { 1362 | "text": "pattern_depth", 1363 | "type": "function", 1364 | "description": "Returns the level of nested arrays" 1365 | }, 1366 | { 1367 | "text": "patternclass", 1368 | "type": "function" 1369 | }, 1370 | { 1371 | "text": "pause", 1372 | "type": "method" 1373 | }, 1374 | { 1375 | "text": "piano", 1376 | "type": "function" 1377 | }, 1378 | { 1379 | "text": "play", 1380 | "type": "function" 1381 | }, 1382 | { 1383 | "text": "play", 1384 | "type": "method" 1385 | }, 1386 | { 1387 | "text": "pluck", 1388 | "type": "function" 1389 | }, 1390 | { 1391 | "text": "prophet", 1392 | "type": "function" 1393 | }, 1394 | { 1395 | "text": "pshift", 1396 | "type": "property" 1397 | }, 1398 | { 1399 | "text": "pulse", 1400 | "type": "function" 1401 | }, 1402 | { 1403 | "text": "quin", 1404 | "type": "function" 1405 | }, 1406 | { 1407 | "text": "rAdd", 1408 | "type": "function" 1409 | }, 1410 | { 1411 | "text": "rDiv", 1412 | "type": "function" 1413 | }, 1414 | { 1415 | "text": "rFloorDiv", 1416 | "type": "function" 1417 | }, 1418 | { 1419 | "text": "rGet", 1420 | "type": "function" 1421 | }, 1422 | { 1423 | "text": "rMod", 1424 | "type": "function" 1425 | }, 1426 | { 1427 | "text": "rOr", 1428 | "type": "function" 1429 | }, 1430 | { 1431 | "text": "rPow", 1432 | "type": "function" 1433 | }, 1434 | { 1435 | "text": "rSub", 1436 | "type": "function" 1437 | }, 1438 | { 1439 | "text": "rXor", 1440 | "type": "function" 1441 | }, 1442 | { 1443 | "text": "rate", 1444 | "type": "property" 1445 | }, 1446 | { 1447 | "text": "rave", 1448 | "type": "function" 1449 | }, 1450 | { 1451 | "text": "razz", 1452 | "type": "function" 1453 | }, 1454 | { 1455 | "text": "reset", 1456 | "type": "method" 1457 | }, 1458 | { 1459 | "text": "rest", 1460 | "type": "class", 1461 | "description": "Represents a rest when used with a Player's `dur` keyword" 1462 | }, 1463 | { 1464 | "text": "reverse", 1465 | "type": "method" 1466 | }, 1467 | { 1468 | "text": "rhythm", 1469 | "type": "method" 1470 | }, 1471 | { 1472 | "text": "ripple", 1473 | "type": "function" 1474 | }, 1475 | { 1476 | "text": "room", 1477 | "type": "property" 1478 | }, 1479 | { 1480 | "text": "rotate", 1481 | "type": "method" 1482 | }, 1483 | { 1484 | "text": "rshift", 1485 | "type": "method" 1486 | }, 1487 | { 1488 | "text": "rtMidiNotFound", 1489 | "type": "class" 1490 | }, 1491 | { 1492 | "text": "sample", 1493 | "type": "property" 1494 | }, 1495 | { 1496 | "text": "saw", 1497 | "type": "function" 1498 | }, 1499 | { 1500 | "text": "sawbass", 1501 | "type": "function" 1502 | }, 1503 | { 1504 | "text": "scale", 1505 | "type": "property" 1506 | }, 1507 | { 1508 | "text": "scatter", 1509 | "type": "function" 1510 | }, 1511 | { 1512 | "text": "scratch", 1513 | "type": "function" 1514 | }, 1515 | { 1516 | "text": "send", 1517 | "type": "method" 1518 | }, 1519 | { 1520 | "text": "set_clock", 1521 | "type": "method" 1522 | }, 1523 | { 1524 | "text": "set_queue_block", 1525 | "type": "method" 1526 | }, 1527 | { 1528 | "text": "set_sample_bank", 1529 | "type": "method" 1530 | }, 1531 | { 1532 | "text": "shape", 1533 | "type": "property" 1534 | }, 1535 | { 1536 | "text": "shuffle", 1537 | "type": "method" 1538 | }, 1539 | { 1540 | "text": "sitar", 1541 | "type": "function" 1542 | }, 1543 | { 1544 | "text": "sliceToRange", 1545 | "type": "function" 1546 | }, 1547 | { 1548 | "text": "slide", 1549 | "type": "property" 1550 | }, 1551 | { 1552 | "text": "slidedelay", 1553 | "type": "property" 1554 | }, 1555 | { 1556 | "text": "slidefrom", 1557 | "type": "property" 1558 | }, 1559 | { 1560 | "text": "slider", 1561 | "type": "method" 1562 | }, 1563 | { 1564 | "text": "smap", 1565 | "type": "method" 1566 | }, 1567 | { 1568 | "text": "snick", 1569 | "type": "function" 1570 | }, 1571 | { 1572 | "text": "soft", 1573 | "type": "function" 1574 | }, 1575 | { 1576 | "text": "solo", 1577 | "type": "method" 1578 | }, 1579 | { 1580 | "text": "soprano", 1581 | "type": "function" 1582 | }, 1583 | { 1584 | "text": "spark", 1585 | "type": "function" 1586 | }, 1587 | { 1588 | "text": "spin", 1589 | "type": "property" 1590 | }, 1591 | { 1592 | "text": "spread", 1593 | "type": "method" 1594 | }, 1595 | { 1596 | "text": "square_type", 1597 | "type": "class", 1598 | "description": "Useful for when you want many nested groups. This PGroup flattens the original\n but the delay times are calculated in the same way as if the values were neseted" 1599 | }, 1600 | { 1601 | "text": "squish", 1602 | "type": "function" 1603 | }, 1604 | { 1605 | "text": "star", 1606 | "type": "function" 1607 | }, 1608 | { 1609 | "text": "stdout", 1610 | "type": "function", 1611 | "description": "Forces prints to stdout and not console" 1612 | }, 1613 | { 1614 | "text": "stop", 1615 | "type": "method" 1616 | }, 1617 | { 1618 | "text": "stop_calling_all", 1619 | "type": "method" 1620 | }, 1621 | { 1622 | "text": "strum", 1623 | "type": "method" 1624 | }, 1625 | { 1626 | "text": "stutter", 1627 | "type": "method" 1628 | }, 1629 | { 1630 | "text": "sus", 1631 | "type": "property" 1632 | }, 1633 | { 1634 | "text": "swell", 1635 | "type": "function" 1636 | }, 1637 | { 1638 | "text": "swell", 1639 | "type": "property" 1640 | }, 1641 | { 1642 | "text": "test_for_circular_reference", 1643 | "type": "method" 1644 | }, 1645 | { 1646 | "text": "twang", 1647 | "type": "function" 1648 | }, 1649 | { 1650 | "text": "unpack", 1651 | "type": "method" 1652 | }, 1653 | { 1654 | "text": "update", 1655 | "type": "method" 1656 | }, 1657 | { 1658 | "text": "update_all_player_keys", 1659 | "type": "method" 1660 | }, 1661 | { 1662 | "text": "update_pattern_methods", 1663 | "type": "method" 1664 | }, 1665 | { 1666 | "text": "update_pattern_root", 1667 | "type": "method" 1668 | }, 1669 | { 1670 | "text": "update_player_key", 1671 | "type": "method" 1672 | }, 1673 | { 1674 | "text": "var", 1675 | "type": "function", 1676 | "description": "This is the TimeVar generator used in FoxDot. Calling it like `var()`\n returns a TimeVar but setting an attribute `var.foo = var([1,2],4)` will\n update the TimeVar that is already in `var.foo`.\n\n In short, using `var.name = var([i, j])` means you don't have to delete\n some of the text and replace it with `var.name.update([k, l])` you can\n just use `var.name = var([k, l])` and the contents of the var will be\n updated everywhere else in the program." 1677 | }, 1678 | { 1679 | "text": "varsaw", 1680 | "type": "function" 1681 | }, 1682 | { 1683 | "text": "versus", 1684 | "type": "method" 1685 | }, 1686 | { 1687 | "text": "vib", 1688 | "type": "property" 1689 | }, 1690 | { 1691 | "text": "vibdepth", 1692 | "type": "property" 1693 | }, 1694 | { 1695 | "text": "viola", 1696 | "type": "function" 1697 | }, 1698 | { 1699 | "text": "when", 1700 | "type": "keyword" 1701 | }, 1702 | { 1703 | "text": "zap", 1704 | "type": "function" 1705 | } 1706 | ] 1707 | --------------------------------------------------------------------------------