├── .editorconfig ├── .github └── workflows │ └── test.yml ├── .gitignore ├── LICENSE.txt ├── README.md ├── maxpatches ├── ExampleJS.maxpat ├── ExampleJSUI.maxpat └── ExampleObjectCreation.maxpat ├── package-lock.json ├── package.json ├── src ├── ExampleJS.ts ├── ExampleJSUI.ts ├── ExampleMaxObjectsCreation.ts └── ExampleModule.ts └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = tab 5 | indent_size = 4 -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | # Name of our workflow 2 | name: 'Test' 3 | 4 | # Events that will trigger our workflow 5 | on: [ 'pull_request', 'push' ] 6 | 7 | # List of custom jobs 8 | jobs: 9 | # Job is called "test" 10 | test: 11 | # Using a "label" to assign job to a specific hosted runner 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Checks-out our repository under "$GITHUB_WORKSPACE", so our job can access it 15 | - name: 'Checkout repository' 16 | uses: actions/checkout@v3 17 | 18 | # Install the requirements 19 | - name: 'Install' 20 | run: npm install 21 | 22 | # # Runs commands using the runners shell 23 | # - name: 'Run tests' 24 | # run: npx nyc ava && npx nyc report --reporter cobertura --reporter json-summary 25 | 26 | - name: 'compile' 27 | run: npm run compile 28 | 29 | # Upload the compiled js so we can check it if needed, keep it for a week 30 | - uses: actions/upload-artifact@v3 31 | with: 32 | name: compiled-js 33 | path: dist/ 34 | retention-days: 7 35 | 36 | # - name: Code Coverage Report 37 | # uses: irongut/CodeCoverageSummary@v1.3.0 38 | # with: 39 | # filename: ./coverage/cobertura-coverage.xml 40 | # badge: true 41 | # fail_below_min: true 42 | # format: markdown 43 | # hide_branch_rate: false 44 | # hide_complexity: false 45 | # indicators: true 46 | # output: both 47 | # thresholds: '60 80' 48 | # - name: Add Coverage PR Comment 49 | # uses: marocchino/sticky-pull-request-comment@v2 50 | # if: github.event_name == 'pull_request' 51 | # with: 52 | # recreate: true 53 | # path: code-coverage-results.md 54 | # - name: Create Coverage Badges 55 | # uses: jaywcjlove/coverage-badges-cli@main 56 | # with: 57 | # style: flat 58 | # source: ./coverage/coverage-summary.json 59 | # output: ./coverage/badges.svg 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.sublime-project 2 | *.sublime-workspace 3 | node_modules 4 | dist 5 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Thorsten Ørts 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Documentation is property of Cycling '74 and published with permission. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TypeScript for Cycling '74 Max / MSP / Jitter 2 | 3 | Examples showing how to use the Max Javascript type definitions available as part 4 | of the DefinitelyTyped project and more broadly how to compile Javascript that Max 5 | can run. 6 | 7 | `npm install @types/maxmsp --save-dev` 8 | 9 | If you want to contribute to the type definitions themselves please see [DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped) 10 | 11 | [VS Code](https://code.visualstudio.com/) is the recommended TypeScript IDE. 12 | 13 | Follow 14 | [this guide](https://cmatskas.com/getting-started-with-typescript-and-sublime-text/) 15 | to set up Sublime Text. 16 | 17 | ## Getting started 18 | 19 | Clone this repo to your `Max 8/Library` folder 20 | 21 | Install its dependencies with `npm install`. You can then compile the `.ts` 22 | files in `src` to max compatible es3 javascript by running either 23 | `npm run compile` or `tsc`. 24 | 25 | Once you have done this you will see the compiled js files in the `dist` folder 26 | and you can open the patches in the `maxpatches` folder. 27 | 28 | ## Using the definitions in your own project 29 | 30 | You can install these types in your own project by using the command 31 | `npm install @types/maxmsp --save-dev` 32 | 33 | You should ensure that your `tsconfig.json` is set up in a similar one 34 | to this project as there are a few important things that you need to note: 35 | 36 | * Max uses an archaic es5 javascript (for more information see 37 | [here](https://cycling74.com/forums/any-plans-to-update-support-for-recent-versions-of-js#reply-58ed21d5c2991221d9ccad8c)), 38 | which means that for lots of modern functionality you will need to include 39 | polyfills. In our `tsconfig.json` we define this `"target": "es5",` and this 40 | means that we also need to set `"ignoreDeprecations": "5.0",` because es3 41 | support will soon be dropped by Typescript 42 | 43 | * `tsconfig.json` includes `"lib": ["es5"]` to stop Typescript from trying to use 44 | DOM declarations. Not including this lib directive results in duplicate declaration 45 | errors because some max items share names with DOM items. 46 | 47 | * We configure the types so that we can use them from the top level by including 48 | the line `"types": ["maxmsp"],` in our `tsconfig.json` 49 | 50 | ## API Documentation 51 | 52 | See 53 | [Max Javascript Reference](http://max-javascript-reference.tim-schenk.de/#gsc.tab=0) 54 | for full documentation on all functions and properties. 55 | 56 | ## Notes 57 | 58 | * The TypeScript configuration file (`tsconfig.json`) is set up to output a 59 | separate .js file for each .ts file. 60 | 61 | * .ts files for scripts to be used in a [js] or [jsui] object must end in: 62 | 63 | let module = {}; 64 | export = {}; 65 | 66 | This tricks tsc in outputting it as a separate module file, while still 67 | allowing Max to read it as a script. Do not do this in module files. 68 | 69 | * Make sure the compiled JavaScript files are in Max' search path, set this with 70 | `"outDir"` in your `tsconfig.json`. Make sure your TypeScript folder is not in 71 | a Max project directory or Max will mess up the file structure. 72 | 73 | * For continuous development run `tsc --watch` in the directory with your 74 | `tsconfig.json`. The .js files are then generated on save and Max will then 75 | reload automatically. 76 | 77 | * For more information on configuration files, look [here](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). 78 | 79 | * Import modules using non local paths. Max will resolve `ExampleModule` but 80 | `./ExampleModule` will not work without path rewriting. In more complex projects 81 | where you may want to hide subdirectories or use shorter paths you might need to 82 | include a paths directive in your `tsconfig.json`. For example: 83 | 84 | ```json 85 | "paths": { 86 | "Cursor": [ 87 | "Cursor/Cursor" 88 | ] 89 | } 90 | ``` 91 | 92 | ## Assigning properties to objects of type Global 93 | 94 | Cast to `` to assign properties to objects of type `Global` like so: 95 | 96 | ```Typescript 97 | var g = new Global("Foo"); 98 | (g).newProperty = "I am new."; 99 | post("(g).newProperty: " + (g).newProperty + "\n"); 100 | ``` 101 | -------------------------------------------------------------------------------- /maxpatches/ExampleJS.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher" : { 3 | "fileversion" : 1, 4 | "appversion" : { 5 | "major" : 7, 6 | "minor" : 3, 7 | "revision" : 1, 8 | "architecture" : "x86", 9 | "modernui" : 1 10 | } 11 | , 12 | "rect" : [ 1048.0, 238.0, 448.0, 511.0 ], 13 | "bglocked" : 0, 14 | "openinpresentation" : 0, 15 | "default_fontsize" : 12.0, 16 | "default_fontface" : 0, 17 | "default_fontname" : "Arial", 18 | "gridonopen" : 1, 19 | "gridsize" : [ 8.0, 8.0 ], 20 | "gridsnaponopen" : 2, 21 | "objectsnaponopen" : 0, 22 | "statusbarvisible" : 2, 23 | "toolbarvisible" : 1, 24 | "lefttoolbarpinned" : 0, 25 | "toptoolbarpinned" : 0, 26 | "righttoolbarpinned" : 0, 27 | "bottomtoolbarpinned" : 0, 28 | "toolbars_unpinned_last_save" : 0, 29 | "tallnewobj" : 0, 30 | "boxanimatetime" : 500, 31 | "enablehscroll" : 1, 32 | "enablevscroll" : 1, 33 | "devicewidth" : 0.0, 34 | "description" : "", 35 | "digest" : "", 36 | "tags" : "", 37 | "style" : "default", 38 | "subpatcher_template" : "Max Audio Effect_template", 39 | "boxes" : [ { 40 | "box" : { 41 | "format" : 6, 42 | "id" : "obj-9", 43 | "maxclass" : "flonum", 44 | "numinlets" : 1, 45 | "numoutlets" : 2, 46 | "outlettype" : [ "", "bang" ], 47 | "parameter_enable" : 0, 48 | "patching_rect" : [ 96.0, 40.0, 50.0, 22.0 ], 49 | "style" : "" 50 | } 51 | 52 | } 53 | , { 54 | "box" : { 55 | "id" : "obj-7", 56 | "maxclass" : "message", 57 | "numinlets" : 2, 58 | "numoutlets" : 1, 59 | "outlettype" : [ "" ], 60 | "patching_rect" : [ 40.0, 136.0, 296.0, 22.0 ], 61 | "style" : "", 62 | "text" : "5.764801" 63 | } 64 | 65 | } 66 | , { 67 | "box" : { 68 | "id" : "obj-5", 69 | "maxclass" : "button", 70 | "numinlets" : 1, 71 | "numoutlets" : 1, 72 | "outlettype" : [ "bang" ], 73 | "patching_rect" : [ 40.0, 40.0, 40.0, 40.0 ], 74 | "style" : "" 75 | } 76 | 77 | } 78 | , { 79 | "box" : { 80 | "fontface" : 1, 81 | "fontsize" : 20.0, 82 | "id" : "obj-4", 83 | "maxclass" : "message", 84 | "numinlets" : 2, 85 | "numoutlets" : 1, 86 | "outlettype" : [ "" ], 87 | "patching_rect" : [ 360.0, 40.0, 60.0, 31.0 ], 88 | "style" : "", 89 | "text" : "open" 90 | } 91 | 92 | } 93 | , { 94 | "box" : { 95 | "fontface" : 1, 96 | "fontsize" : 20.0, 97 | "id" : "obj-3", 98 | "maxclass" : "message", 99 | "numinlets" : 2, 100 | "numoutlets" : 1, 101 | "outlettype" : [ "" ], 102 | "patching_rect" : [ 256.0, 40.0, 89.0, 31.0 ], 103 | "style" : "", 104 | "text" : "compile" 105 | } 106 | 107 | } 108 | , { 109 | "box" : { 110 | "id" : "obj-1", 111 | "maxclass" : "newobj", 112 | "numinlets" : 1, 113 | "numoutlets" : 1, 114 | "outlettype" : [ "" ], 115 | "patching_rect" : [ 40.0, 96.0, 83.0, 22.0 ], 116 | "saved_object_attributes" : { 117 | "filename" : "ExampleJS.js", 118 | "parameter_enable" : 0 119 | } 120 | , 121 | "style" : "", 122 | "text" : "js ExampleJS" 123 | } 124 | 125 | } 126 | ], 127 | "lines" : [ { 128 | "patchline" : { 129 | "destination" : [ "obj-7", 1 ], 130 | "disabled" : 0, 131 | "hidden" : 0, 132 | "midpoints" : [ 49.5, 125.0, 326.5, 125.0 ], 133 | "source" : [ "obj-1", 0 ] 134 | } 135 | 136 | } 137 | , { 138 | "patchline" : { 139 | "destination" : [ "obj-1", 0 ], 140 | "disabled" : 0, 141 | "hidden" : 0, 142 | "midpoints" : [ 265.5, 88.0, 49.5, 88.0 ], 143 | "source" : [ "obj-3", 0 ] 144 | } 145 | 146 | } 147 | , { 148 | "patchline" : { 149 | "destination" : [ "obj-1", 0 ], 150 | "disabled" : 0, 151 | "hidden" : 0, 152 | "midpoints" : [ 369.5, 88.0, 49.5, 88.0 ], 153 | "source" : [ "obj-4", 0 ] 154 | } 155 | 156 | } 157 | , { 158 | "patchline" : { 159 | "destination" : [ "obj-1", 0 ], 160 | "disabled" : 0, 161 | "hidden" : 0, 162 | "source" : [ "obj-5", 0 ] 163 | } 164 | 165 | } 166 | , { 167 | "patchline" : { 168 | "destination" : [ "obj-1", 0 ], 169 | "disabled" : 0, 170 | "hidden" : 0, 171 | "midpoints" : [ 105.5, 88.0, 49.5, 88.0 ], 172 | "source" : [ "obj-9", 0 ] 173 | } 174 | 175 | } 176 | ], 177 | "dependency_cache" : [ { 178 | "name" : "ExampleJS.js", 179 | "bootpath" : "~/Documents/Max 7/Library/ErnstHot/TypeScript/TypeScript for Max/JavaScript", 180 | "type" : "TEXT", 181 | "implicit" : 1 182 | } 183 | ], 184 | "autosave" : 0 185 | } 186 | 187 | } 188 | -------------------------------------------------------------------------------- /maxpatches/ExampleJSUI.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher" : { 3 | "fileversion" : 1, 4 | "appversion" : { 5 | "major" : 7, 6 | "minor" : 3, 7 | "revision" : 1, 8 | "architecture" : "x86", 9 | "modernui" : 1 10 | } 11 | , 12 | "rect" : [ 514.0, 239.0, 565.0, 509.0 ], 13 | "bglocked" : 0, 14 | "openinpresentation" : 0, 15 | "default_fontsize" : 12.0, 16 | "default_fontface" : 0, 17 | "default_fontname" : "Arial", 18 | "gridonopen" : 1, 19 | "gridsize" : [ 8.0, 8.0 ], 20 | "gridsnaponopen" : 2, 21 | "objectsnaponopen" : 0, 22 | "statusbarvisible" : 2, 23 | "toolbarvisible" : 1, 24 | "lefttoolbarpinned" : 0, 25 | "toptoolbarpinned" : 0, 26 | "righttoolbarpinned" : 0, 27 | "bottomtoolbarpinned" : 0, 28 | "toolbars_unpinned_last_save" : 0, 29 | "tallnewobj" : 0, 30 | "boxanimatetime" : 500, 31 | "enablehscroll" : 1, 32 | "enablevscroll" : 1, 33 | "devicewidth" : 0.0, 34 | "description" : "", 35 | "digest" : "", 36 | "tags" : "", 37 | "style" : "default", 38 | "subpatcher_template" : "Max Audio Effect_template", 39 | "boxes" : [ { 40 | "box" : { 41 | "id" : "obj-17", 42 | "maxclass" : "message", 43 | "numinlets" : 2, 44 | "numoutlets" : 1, 45 | "outlettype" : [ "" ], 46 | "patching_rect" : [ 256.0, 72.0, 65.0, 22.0 ], 47 | "style" : "", 48 | "text" : "setRes $1" 49 | } 50 | 51 | } 52 | , { 53 | "box" : { 54 | "id" : "obj-18", 55 | "maxclass" : "number", 56 | "maximum" : 128, 57 | "minimum" : 2, 58 | "numinlets" : 1, 59 | "numoutlets" : 2, 60 | "outlettype" : [ "", "bang" ], 61 | "parameter_enable" : 0, 62 | "patching_rect" : [ 256.0, 32.0, 50.0, 22.0 ], 63 | "style" : "" 64 | } 65 | 66 | } 67 | , { 68 | "box" : { 69 | "id" : "obj-15", 70 | "maxclass" : "message", 71 | "numinlets" : 2, 72 | "numoutlets" : 1, 73 | "outlettype" : [ "" ], 74 | "patching_rect" : [ 192.0, 72.0, 51.0, 22.0 ], 75 | "style" : "", 76 | "text" : "setB $1" 77 | } 78 | 79 | } 80 | , { 81 | "box" : { 82 | "format" : 6, 83 | "id" : "obj-16", 84 | "maxclass" : "flonum", 85 | "maximum" : 20.0, 86 | "minimum" : 0.0, 87 | "numinlets" : 1, 88 | "numoutlets" : 2, 89 | "outlettype" : [ "", "bang" ], 90 | "parameter_enable" : 0, 91 | "patching_rect" : [ 192.0, 32.0, 50.0, 22.0 ], 92 | "style" : "" 93 | } 94 | 95 | } 96 | , { 97 | "box" : { 98 | "id" : "obj-14", 99 | "maxclass" : "message", 100 | "numinlets" : 2, 101 | "numoutlets" : 1, 102 | "outlettype" : [ "" ], 103 | "patching_rect" : [ 128.0, 72.0, 51.0, 22.0 ], 104 | "style" : "", 105 | "text" : "setA $1" 106 | } 107 | 108 | } 109 | , { 110 | "box" : { 111 | "format" : 6, 112 | "id" : "obj-12", 113 | "maxclass" : "flonum", 114 | "maximum" : 30.0, 115 | "minimum" : 0.0, 116 | "numinlets" : 1, 117 | "numoutlets" : 2, 118 | "outlettype" : [ "", "bang" ], 119 | "parameter_enable" : 0, 120 | "patching_rect" : [ 128.0, 32.0, 50.0, 22.0 ], 121 | "style" : "" 122 | } 123 | 124 | } 125 | , { 126 | "box" : { 127 | "id" : "obj-10", 128 | "maxclass" : "toggle", 129 | "numinlets" : 1, 130 | "numoutlets" : 1, 131 | "outlettype" : [ "int" ], 132 | "parameter_enable" : 0, 133 | "patching_rect" : [ 48.0, 32.0, 48.0, 48.0 ], 134 | "style" : "" 135 | } 136 | 137 | } 138 | , { 139 | "box" : { 140 | "id" : "obj-8", 141 | "maxclass" : "newobj", 142 | "numinlets" : 2, 143 | "numoutlets" : 1, 144 | "outlettype" : [ "bang" ], 145 | "patching_rect" : [ 48.0, 96.0, 65.0, 22.0 ], 146 | "style" : "", 147 | "text" : "qmetro 16" 148 | } 149 | 150 | } 151 | , { 152 | "box" : { 153 | "id" : "obj-5", 154 | "maxclass" : "button", 155 | "numinlets" : 1, 156 | "numoutlets" : 1, 157 | "outlettype" : [ "bang" ], 158 | "patching_rect" : [ 48.0, 136.0, 32.0, 32.0 ], 159 | "style" : "" 160 | } 161 | 162 | } 163 | , { 164 | "box" : { 165 | "fontface" : 1, 166 | "fontsize" : 20.0, 167 | "id" : "obj-4", 168 | "maxclass" : "message", 169 | "numinlets" : 2, 170 | "numoutlets" : 1, 171 | "outlettype" : [ "" ], 172 | "patching_rect" : [ 448.0, 32.0, 60.0, 31.0 ], 173 | "style" : "", 174 | "text" : "open" 175 | } 176 | 177 | } 178 | , { 179 | "box" : { 180 | "fontface" : 1, 181 | "fontsize" : 20.0, 182 | "id" : "obj-3", 183 | "maxclass" : "message", 184 | "numinlets" : 2, 185 | "numoutlets" : 1, 186 | "outlettype" : [ "" ], 187 | "patching_rect" : [ 344.0, 32.0, 89.0, 31.0 ], 188 | "style" : "", 189 | "text" : "compile" 190 | } 191 | 192 | } 193 | , { 194 | "box" : { 195 | "filename" : "ExampleJSUI.js", 196 | "id" : "obj-1", 197 | "maxclass" : "jsui", 198 | "nofsaa" : 1, 199 | "numinlets" : 1, 200 | "numoutlets" : 1, 201 | "outlettype" : [ "" ], 202 | "parameter_enable" : 0, 203 | "patching_rect" : [ 48.0, 200.0, 256.0, 256.0 ] 204 | } 205 | 206 | } 207 | ], 208 | "lines" : [ { 209 | "patchline" : { 210 | "destination" : [ "obj-8", 0 ], 211 | "disabled" : 0, 212 | "hidden" : 0, 213 | "source" : [ "obj-10", 0 ] 214 | } 215 | 216 | } 217 | , { 218 | "patchline" : { 219 | "destination" : [ "obj-14", 0 ], 220 | "disabled" : 0, 221 | "hidden" : 0, 222 | "source" : [ "obj-12", 0 ] 223 | } 224 | 225 | } 226 | , { 227 | "patchline" : { 228 | "destination" : [ "obj-1", 0 ], 229 | "disabled" : 0, 230 | "hidden" : 0, 231 | "midpoints" : [ 137.5, 186.0, 57.5, 186.0 ], 232 | "source" : [ "obj-14", 0 ] 233 | } 234 | 235 | } 236 | , { 237 | "patchline" : { 238 | "destination" : [ "obj-1", 0 ], 239 | "disabled" : 0, 240 | "hidden" : 0, 241 | "midpoints" : [ 201.5, 186.0, 57.5, 186.0 ], 242 | "source" : [ "obj-15", 0 ] 243 | } 244 | 245 | } 246 | , { 247 | "patchline" : { 248 | "destination" : [ "obj-15", 0 ], 249 | "disabled" : 0, 250 | "hidden" : 0, 251 | "source" : [ "obj-16", 0 ] 252 | } 253 | 254 | } 255 | , { 256 | "patchline" : { 257 | "destination" : [ "obj-1", 0 ], 258 | "disabled" : 0, 259 | "hidden" : 0, 260 | "midpoints" : [ 265.5, 186.0, 57.5, 186.0 ], 261 | "source" : [ "obj-17", 0 ] 262 | } 263 | 264 | } 265 | , { 266 | "patchline" : { 267 | "destination" : [ "obj-17", 0 ], 268 | "disabled" : 0, 269 | "hidden" : 0, 270 | "source" : [ "obj-18", 0 ] 271 | } 272 | 273 | } 274 | , { 275 | "patchline" : { 276 | "destination" : [ "obj-1", 0 ], 277 | "disabled" : 0, 278 | "hidden" : 0, 279 | "midpoints" : [ 353.5, 186.0, 57.5, 186.0 ], 280 | "source" : [ "obj-3", 0 ] 281 | } 282 | 283 | } 284 | , { 285 | "patchline" : { 286 | "destination" : [ "obj-1", 0 ], 287 | "disabled" : 0, 288 | "hidden" : 0, 289 | "midpoints" : [ 457.5, 185.0, 57.5, 185.0 ], 290 | "source" : [ "obj-4", 0 ] 291 | } 292 | 293 | } 294 | , { 295 | "patchline" : { 296 | "destination" : [ "obj-1", 0 ], 297 | "disabled" : 0, 298 | "hidden" : 0, 299 | "source" : [ "obj-5", 0 ] 300 | } 301 | 302 | } 303 | , { 304 | "patchline" : { 305 | "destination" : [ "obj-1", 0 ], 306 | "disabled" : 0, 307 | "hidden" : 0, 308 | "midpoints" : [ 57.5, 124.0, 37.0, 124.0, 37.0, 181.0, 57.5, 181.0 ], 309 | "source" : [ "obj-8", 0 ] 310 | } 311 | 312 | } 313 | ], 314 | "dependency_cache" : [ { 315 | "name" : "ExampleJSUI.js", 316 | "bootpath" : "~/Documents/Max 7/Library/ErnstHot/TypeScript/TypeScript-for-Max/JavaScript", 317 | "type" : "TEXT", 318 | "implicit" : 1 319 | } 320 | ], 321 | "autosave" : 0 322 | } 323 | 324 | } 325 | -------------------------------------------------------------------------------- /maxpatches/ExampleObjectCreation.maxpat: -------------------------------------------------------------------------------- 1 | { 2 | "patcher" : { 3 | "fileversion" : 1, 4 | "appversion" : { 5 | "major" : 8, 6 | "minor" : 5, 7 | "revision" : 4, 8 | "architecture" : "x64", 9 | "modernui" : 1 10 | } 11 | , 12 | "classnamespace" : "box", 13 | "rect" : [ 111.0, 496.0, 640.0, 480.0 ], 14 | "bglocked" : 0, 15 | "openinpresentation" : 0, 16 | "default_fontsize" : 12.0, 17 | "default_fontface" : 0, 18 | "default_fontname" : "Arial", 19 | "gridonopen" : 1, 20 | "gridsize" : [ 15.0, 15.0 ], 21 | "gridsnaponopen" : 1, 22 | "objectsnaponopen" : 1, 23 | "statusbarvisible" : 2, 24 | "toolbarvisible" : 1, 25 | "lefttoolbarpinned" : 0, 26 | "toptoolbarpinned" : 0, 27 | "righttoolbarpinned" : 0, 28 | "bottomtoolbarpinned" : 0, 29 | "toolbars_unpinned_last_save" : 0, 30 | "tallnewobj" : 0, 31 | "boxanimatetime" : 200, 32 | "enablehscroll" : 1, 33 | "enablevscroll" : 1, 34 | "devicewidth" : 0.0, 35 | "description" : "", 36 | "digest" : "", 37 | "tags" : "", 38 | "style" : "", 39 | "subpatcher_template" : "", 40 | "assistshowspatchername" : 0, 41 | "boxes" : [ { 42 | "box" : { 43 | "id" : "obj-5", 44 | "linecount" : 3, 45 | "maxclass" : "comment", 46 | "numinlets" : 1, 47 | "numoutlets" : 0, 48 | "patching_rect" : [ 229.0, 96.0, 150.0, 47.0 ], 49 | "text" : "Click bang and you will see a subpatcher get created from Javascript" 50 | } 51 | 52 | } 53 | , { 54 | "box" : { 55 | "id" : "obj-3", 56 | "maxclass" : "button", 57 | "numinlets" : 1, 58 | "numoutlets" : 1, 59 | "outlettype" : [ "bang" ], 60 | "parameter_enable" : 0, 61 | "patching_rect" : [ 175.0, 96.0, 47.0, 47.0 ] 62 | } 63 | 64 | } 65 | , { 66 | "box" : { 67 | "id" : "obj-1", 68 | "maxclass" : "newobj", 69 | "numinlets" : 1, 70 | "numoutlets" : 1, 71 | "outlettype" : [ "" ], 72 | "patching_rect" : [ 175.0, 167.0, 204.0, 22.0 ], 73 | "saved_object_attributes" : { 74 | "filename" : "ExampleMaxObjectsCreation", 75 | "parameter_enable" : 0 76 | } 77 | , 78 | "text" : "js ExampleMaxObjectsCreation" 79 | } 80 | 81 | } 82 | ], 83 | "lines" : [ { 84 | "patchline" : { 85 | "destination" : [ "obj-1", 0 ], 86 | "source" : [ "obj-3", 0 ] 87 | } 88 | 89 | } 90 | ], 91 | "dependency_cache" : [ { 92 | "name" : "ExampleMaxObjectsCreation.js", 93 | "bootpath" : "~/Documents/Max 8/Library/TypeScript-for-Max/dist", 94 | "patcherrelativepath" : "../dist", 95 | "type" : "TEXT", 96 | "implicit" : 1 97 | } 98 | ], 99 | "autosave" : 0 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-for-max", 3 | "version": "1.0.0", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "typescript-for-max", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@types/maxmsp": "^1.0.12" 13 | } 14 | }, 15 | "node_modules/@types/maxmsp": { 16 | "version": "1.0.12", 17 | "resolved": "https://registry.npmjs.org/@types/maxmsp/-/maxmsp-1.0.12.tgz", 18 | "integrity": "sha512-KU6rJkMIujhCKAXMhaxwZ7KNf8nRRipNZZhl5Rra+/tfI1sCnUJ6mFH2ROnLKKtiEm22H0Ui2N4YgHPcpXx7Mw==", 19 | "dev": true, 20 | "license": "MIT" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-for-max", 3 | "version": "1.0.0", 4 | "description": "Some examples of how to use typescript and type definitions for [js]/[jsui] objects", 5 | "scripts": { 6 | "compile": "tsc" 7 | }, 8 | "keywords": [ 9 | "maxmsp", 10 | "max" 11 | ], 12 | "author": "Thorsten Ørts", 13 | "contributors": [ 14 | "Tom Whiston (https://github.com/twhiston)" 15 | ], 16 | "license": "MIT", 17 | "devDependencies": { 18 | "@types/maxmsp": "^1.0.12" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ExampleJS.ts: -------------------------------------------------------------------------------- 1 | import * as em from 'ExampleModule' 2 | // If you uncomment this line below you can require the module in a different, more es3 style 3 | // If you do this you should comment out the two lines at the end of this file 4 | // You will also need to `npm install @types/node --save-dev` 5 | //var em = require('ExampleModule'); 6 | 7 | inlets = 1; 8 | outlets = 1; 9 | autowatch = 1; 10 | 11 | function bang() { 12 | let theObject = new em.TheClass(42); 13 | post("theObject.getIndex(): " + theObject.getIndex() + "\n"); 14 | post("The square of pi is " + em.square(Math.PI) + "\n"); 15 | 16 | // Cast to to assign properties to objects of type Global. 17 | // You must give the global a name, otherwise it may cause crashes in max 18 | // when the global is freed 19 | var g = new Global("TypescriptTest"); 20 | (g).newProperty = "I am new."; 21 | 22 | post("(g).newProperty: " + (g).newProperty + "\n"); 23 | } 24 | 25 | function msg_float(v: number) 26 | { 27 | outlet(0, em.square(v)); 28 | } 29 | 30 | function msg_int(v: number) 31 | { 32 | outlet(0, em.square(v)); 33 | } 34 | 35 | // .ts files with this at the end become a script usable in a [js] or [jsui] object 36 | // If you are going to require your module instead of import it then you should comment 37 | // these two lines out of this script 38 | let module = {}; 39 | export = {}; -------------------------------------------------------------------------------- /src/ExampleJSUI.ts: -------------------------------------------------------------------------------- 1 | import * as em from 'ExampleModule' 2 | 3 | inlets = 1; 4 | outlets = 1; 5 | autowatch = 1; 6 | 7 | // See: https://docs.cycling74.com/max8/vignettes/jsmgraphics 8 | // for more about how to use mgraphics 9 | var m = mgraphics; 10 | m.init(); 11 | m.relative_coords = 0; 12 | m.autofill = 0; 13 | 14 | 15 | var t = 0; 16 | var a = 10.0; 17 | var b = 2.0; 18 | var div = 8; 19 | 20 | function paint(){ 21 | var width = box.rect[2] - box.rect[0]; 22 | var height = box.rect[3] - box.rect[1]; 23 | 24 | m.set_source_rgba(0.0, 0.0, 0.0, 1.0); 25 | m.rectangle(0, 0, width, height); 26 | m.fill(); 27 | 28 | for (var y = 0; y < height; y += div) { 29 | for (var x = 0; x < width; x += div) { 30 | let c = em.pixelFn(x / width, y / height, t, a, b); 31 | m.set_source_rgba(c); 32 | m.rectangle(x, y, x + div, y + div); 33 | m.fill(); 34 | } 35 | } 36 | } 37 | 38 | function bang() { 39 | t += 0.01; 40 | m.redraw(); 41 | } 42 | 43 | function setA(v: number){ 44 | a = v; 45 | m.redraw(); 46 | } 47 | 48 | function setB(v: number){ 49 | b = v; 50 | m.redraw(); 51 | } 52 | 53 | function setRes(v: number){ 54 | div = Math.floor(v); 55 | m.redraw(); 56 | } 57 | 58 | // .ts files with this at the end become a script usable in a [js] or [jsui] object 59 | let module = {}; 60 | export = {}; -------------------------------------------------------------------------------- /src/ExampleMaxObjectsCreation.ts: -------------------------------------------------------------------------------- 1 | function createMidiChannelFilterPatch() { 2 | 3 | // Uses 100,100,400,400 as default window coordinates. 4 | // Note that Typescript understands the Patcher type because of 5 | // our type definitions and can help autocomplete methods etc. 6 | var parentPatcher = new Patcher(); 7 | 8 | // Create a patcher with a custom name 9 | var timestamp = new Date().getTime(); 10 | var subpatcherName = "midi_channel_filter_" + timestamp; 11 | var subpatcher = parentPatcher.newdefault(0, 0, "p", subpatcherName); 12 | var subpatcherObj = subpatcher.subpatcher(0); 13 | 14 | // Create new max objects in the patcher 15 | var midiin = subpatcherObj.newdefault(100, 20, "midiin"); 16 | var midiparse = subpatcherObj.newdefault(100, 60, "midiparse"); 17 | var gate = subpatcherObj.newdefault(20, 150, "gate"); 18 | var eqq = subpatcherObj.newdefault(170, 100, "==", 2); 19 | var pack = subpatcherObj.newdefault(100, 185, "pack", "1", "1", "1", "1", "1", "1"); 20 | var midiformat = subpatcherObj.newdefault(100, 220, "midiformat"); 21 | var midiout = subpatcherObj.newdefault(100, 250, "midiout"); 22 | var comment = subpatcherObj.newdefault(20, 280, "comment"); 23 | // Send the "set" message to the comment box with the comment contents 24 | comment.message("set", "MIDI Channel 2 Filter - Create with Javascript") 25 | 26 | // Hook everything up 27 | subpatcherObj.hiddenconnect(midiin, 0, midiparse, 0); 28 | subpatcherObj.hiddenconnect(midiparse, 0, gate, 1); 29 | subpatcherObj.hiddenconnect(midiparse, 1, pack, 1); 30 | subpatcherObj.hiddenconnect(midiparse, 2, pack, 2); 31 | subpatcherObj.hiddenconnect(midiparse, 3, pack, 3); 32 | subpatcherObj.hiddenconnect(midiparse, 4, pack, 4); 33 | subpatcherObj.hiddenconnect(midiparse, 5, pack, 5); 34 | subpatcherObj.hiddenconnect(midiparse, 6, eqq, 0); 35 | subpatcherObj.hiddenconnect(eqq, 0, gate, 0); 36 | subpatcherObj.hiddenconnect(gate, 0, pack, 0); 37 | subpatcherObj.hiddenconnect(pack, 0, midiformat, 0); 38 | subpatcherObj.hiddenconnect(midiformat, 0, midiout, 0); 39 | } 40 | 41 | function bang() { 42 | createMidiChannelFilterPatch(); 43 | } 44 | -------------------------------------------------------------------------------- /src/ExampleModule.ts: -------------------------------------------------------------------------------- 1 | 2 | // These two functions are painfully slow ;) 3 | export function colorFn(x: number): number[] { 4 | return [Math.sin(x) * 0.5 + 0.5, 5 | Math.sin(x + 0.333 * Math.PI) * 0.5 + 0.5, 6 | Math.sin(x + 0.666 * Math.PI) * 0.5 + 0.5, 7 | 1.0]; 8 | } 9 | 10 | export function pixelFn(x: number, y: number, t: number, prmA: number, prmB: number): number[] { 11 | let r = Math.sin(t + x * 2.0) + Math.cos(t + y * 2.0); 12 | r += Math.sin(t + x * Math.sin(t + x * 0.02) * prmA) + Math.cos(t + y * (Math.cos(t * 0.7) * 5.0)) * prmB; 13 | return colorFn(r + t); 14 | } 15 | 16 | export function square(x: number): number { 17 | return x * x; 18 | } 19 | 20 | export class TheClass { 21 | 22 | private index: number; 23 | 24 | constructor(index: number) { 25 | this.index = index; 26 | post("TheClass.constructor was called with the number parameter " + index + "\n"); 27 | } 28 | 29 | getIndex(): number { 30 | return this.index; 31 | } 32 | 33 | post(): void { 34 | post("TheClass: post!"); 35 | post(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "module": "CommonJS", 5 | "target": "ES5", 6 | "ignoreDeprecations": "5.0", 7 | "strict": true, 8 | "noImplicitAny": true, 9 | "sourceMap": false, 10 | "outDir": "./dist", 11 | "baseUrl": "src", 12 | "types": ["maxmsp"], 13 | "lib": ["es5"] 14 | }, 15 | "include": [ 16 | "./src/*.ts", 17 | "./src/**/*.ts" 18 | ], 19 | "exclude": [ 20 | "node_modules" 21 | ] 22 | } --------------------------------------------------------------------------------