├── .gitattributes ├── .gitignore ├── LICENSE.md ├── Makefile ├── Project.ede ├── README.md ├── SkoarPyon ├── apparatus.py ├── lex.py ├── rdpp.py ├── skoarmantics.py ├── skoarmantics_template.py ├── toke_inspector.py └── toke_inspector_template.py ├── Skoar_SC.testsettings ├── Skoarcery ├── SkoarPyon │ └── .gitignore ├── dragonsets.py ├── emissions.py ├── factoary │ ├── Build_Py.py │ ├── Build_Sc.py │ ├── Buildoar.py │ ├── Code_Lexer_Py.py │ ├── Code_Lexer_Sc.py │ ├── Code_Parser_Py.py │ └── Code_Parser_Sc.py ├── laboaratoary │ ├── TestDragonSpells.py │ ├── TestNonterminals.py │ ├── TestParseTable.py │ ├── TestTerminals.py │ └── Test_Sclang.py ├── langoids.py ├── nonterminals.py ├── parsetable.py ├── terminals.py └── underskoar.py ├── SuperCollider ├── Skoar │ ├── apparatus.sc │ ├── beaty.sc │ ├── decorating.sc │ ├── fairy.sc │ ├── koar.sc │ ├── lex.sc │ ├── minstrel.sc │ ├── operatoars.sc │ ├── pitchy.sc │ ├── rdpp.sc │ ├── skoar.sc │ ├── skoarpions.sc │ ├── skoarpuscles.sc │ └── toker.sc ├── Testing │ ├── cats.scd │ ├── dev.scd │ ├── increments.scd │ ├── levels.scd │ ├── noaty.scd │ ├── ops.scd │ ├── ops_dev.scd │ ├── regex.scd │ ├── sanity.scd │ ├── spawn_skeletons.scd │ └── unittests.sc ├── examples │ ├── brandnewshoes.scd │ ├── dungeontimes.scd │ ├── synthdefs.scd │ ├── windwaker.scd │ ├── yay.scd │ └── zelda.scd └── testing │ ├── bigskoar.scd │ └── conditionals.scd ├── Testing ├── SC_tests.playlist └── Skoarcery.playlist ├── build.py ├── examples.md ├── sanity.py └── skoarcery.el /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __* 3 | .DS_* 4 | 5 | Skoarcery.pyproj 6 | Skoarcery.pyproj.user 7 | Skoarcery.sln 8 | Skoarcery.v12.suo -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The Artistic License 2.0 3 | 4 | Copyright (c) 2014 Lucas Adrianus Cornelisse 5 | 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | This license establishes the terms under which a given free software 12 | Package may be copied, modified, distributed, and/or redistributed. 13 | The intent is that the Copyright Holder maintains some artistic 14 | control over the development of that Package while still keeping the 15 | Package available as open source and free software. 16 | 17 | You are always permitted to make arrangements wholly outside of this 18 | license directly with the Copyright Holder of a given Package. If the 19 | terms of this license do not permit the full use that you propose to 20 | make of the Package, you should contact the Copyright Holder and seek 21 | a different licensing arrangement. 22 | 23 | Definitions 24 | 25 | "Copyright Holder" means the individual(s) or organization(s) 26 | named in the copyright notice for the entire Package. 27 | 28 | "Contributor" means any party that has contributed code or other 29 | material to the Package, in accordance with the Copyright Holder's 30 | procedures. 31 | 32 | "You" and "your" means any person who would like to copy, 33 | distribute, or modify the Package. 34 | 35 | "Package" means the collection of files distributed by the 36 | Copyright Holder, and derivatives of that collection and/or of 37 | those files. A given Package may consist of either the Standard 38 | Version, or a Modified Version. 39 | 40 | "Distribute" means providing a copy of the Package or making it 41 | accessible to anyone else, or in the case of a company or 42 | organization, to others outside of your company or organization. 43 | 44 | "Distributor Fee" means any fee that you charge for Distributing 45 | this Package or providing support for this Package to another 46 | party. It does not mean licensing fees. 47 | 48 | "Standard Version" refers to the Package if it has not been 49 | modified, or has been modified only in ways explicitly requested 50 | by the Copyright Holder. 51 | 52 | "Modified Version" means the Package, if it has been changed, and 53 | such changes were not explicitly requested by the Copyright 54 | Holder. 55 | 56 | "Original License" means this Artistic License as Distributed with 57 | the Standard Version of the Package, in its current version or as 58 | it may be modified by The Perl Foundation in the future. 59 | 60 | "Source" form means the source code, documentation source, and 61 | configuration files for the Package. 62 | 63 | "Compiled" form means the compiled bytecode, object code, binary, 64 | or any other form resulting from mechanical transformation or 65 | translation of the Source form. 66 | 67 | 68 | Permission for Use and Modification Without Distribution 69 | 70 | (1) You are permitted to use the Standard Version and create and use 71 | Modified Versions for any purpose without restriction, provided that 72 | you do not Distribute the Modified Version. 73 | 74 | 75 | Permissions for Redistribution of the Standard Version 76 | 77 | (2) You may Distribute verbatim copies of the Source form of the 78 | Standard Version of this Package in any medium without restriction, 79 | either gratis or for a Distributor Fee, provided that you duplicate 80 | all of the original copyright notices and associated disclaimers. At 81 | your discretion, such verbatim copies may or may not include a 82 | Compiled form of the Package. 83 | 84 | (3) You may apply any bug fixes, portability changes, and other 85 | modifications made available from the Copyright Holder. The resulting 86 | Package will still be considered the Standard Version, and as such 87 | will be subject to the Original License. 88 | 89 | 90 | Distribution of Modified Versions of the Package as Source 91 | 92 | (4) You may Distribute your Modified Version as Source (either gratis 93 | or for a Distributor Fee, and with or without a Compiled form of the 94 | Modified Version) provided that you clearly document how it differs 95 | from the Standard Version, including, but not limited to, documenting 96 | any non-standard features, executables, or modules, and provided that 97 | you do at least ONE of the following: 98 | 99 | (a) make the Modified Version available to the Copyright Holder 100 | of the Standard Version, under the Original License, so that the 101 | Copyright Holder may include your modifications in the Standard 102 | Version. 103 | 104 | (b) ensure that installation of your Modified Version does not 105 | prevent the user installing or running the Standard Version. In 106 | addition, the Modified Version must bear a name that is different 107 | from the name of the Standard Version. 108 | 109 | (c) allow anyone who receives a copy of the Modified Version to 110 | make the Source form of the Modified Version available to others 111 | under 112 | 113 | (i) the Original License or 114 | 115 | (ii) a license that permits the licensee to freely copy, 116 | modify and redistribute the Modified Version using the same 117 | licensing terms that apply to the copy that the licensee 118 | received, and requires that the Source form of the Modified 119 | Version, and of any works derived from it, be made freely 120 | available in that license fees are prohibited but Distributor 121 | Fees are allowed. 122 | 123 | 124 | Distribution of Compiled Forms of the Standard Version 125 | or Modified Versions without the Source 126 | 127 | (5) You may Distribute Compiled forms of the Standard Version without 128 | the Source, provided that you include complete instructions on how to 129 | get the Source of the Standard Version. Such instructions must be 130 | valid at the time of your distribution. If these instructions, at any 131 | time while you are carrying out such distribution, become invalid, you 132 | must provide new instructions on demand or cease further distribution. 133 | If you provide valid instructions or cease distribution within thirty 134 | days after you become aware that the instructions are invalid, then 135 | you do not forfeit any of your rights under this license. 136 | 137 | (6) You may Distribute a Modified Version in Compiled form without 138 | the Source, provided that you comply with Section 4 with respect to 139 | the Source of the Modified Version. 140 | 141 | 142 | Aggregating or Linking the Package 143 | 144 | (7) You may aggregate the Package (either the Standard Version or 145 | Modified Version) with other packages and Distribute the resulting 146 | aggregation provided that you do not charge a licensing fee for the 147 | Package. Distributor Fees are permitted, and licensing fees for other 148 | components in the aggregation are permitted. The terms of this license 149 | apply to the use and Distribution of the Standard or Modified Versions 150 | as included in the aggregation. 151 | 152 | (8) You are permitted to link Modified and Standard Versions with 153 | other works, to embed the Package in a larger work of your own, or to 154 | build stand-alone binary or bytecode versions of applications that 155 | include the Package, and Distribute the result without restriction, 156 | provided the result does not expose a direct interface to the Package. 157 | 158 | 159 | Items That are Not Considered Part of a Modified Version 160 | 161 | (9) Works (including, but not limited to, modules and scripts) that 162 | merely extend or make use of the Package, do not, by themselves, cause 163 | the Package to be a Modified Version. In addition, such works are not 164 | considered parts of the Package itself, and are not subject to the 165 | terms of this license. 166 | 167 | 168 | General Provisions 169 | 170 | (10) Any use, modification, and distribution of the Standard or 171 | Modified Versions is governed by this Artistic License. By using, 172 | modifying or distributing the Package, you accept this license. Do not 173 | use, modify, or distribute the Package, if you do not accept this 174 | license. 175 | 176 | (11) If your Modified Version has been derived from a Modified 177 | Version made by someone other than you, you are nevertheless required 178 | to ensure that your Modified Version complies with the requirements of 179 | this license. 180 | 181 | (12) This license does not grant you the right to use any trademark, 182 | service mark, tradename, or logo of the Copyright Holder. 183 | 184 | (13) This license includes the non-exclusive, worldwide, 185 | free-of-charge patent license to make, have made, use, offer to sell, 186 | sell, import and otherwise transfer the Package with respect to any 187 | patent claims licensable by the Copyright Holder that are necessarily 188 | infringed by the Package. If you institute patent litigation 189 | (including a cross-claim or counterclaim) against any party alleging 190 | that the Package constitutes direct or contributory patent 191 | infringement, then this Artistic License to you shall terminate on the 192 | date that such litigation is filed. 193 | 194 | (14) Disclaimer of Warranty: 195 | THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS 196 | IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED 197 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 198 | NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL 199 | LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL 200 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 201 | DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF 202 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 203 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | test_grammar: Skoarcery\terminals.py Skoarcery\nonterminals.py Skoarcery\emissions.py Skoarcery\underskoar.py 3 | python -m unittest .\Skoarcery\laboaratory\TestDragonSpells.py 4 | python -m unittest .\Skoarcery\laboaratory\TestTerminals.py 5 | python -m unittest .\Skoarcery\laboaratory\TestNonTerminals.py 6 | python -m unittest .\Skoarcery\laboaratory\TestParseTable.py 7 | 8 | sc_lexer: test_grammar 9 | python -m unittest .\Skoarcery\factoary\Code_Lexer_Sc.py 10 | 11 | sc_parser: sc_lexer 12 | python -m unittest .\Skoarcery\factoary\Code_Parser_Sc.py 13 | 14 | sc_sanity: 15 | python -m unittest .\Skoarcery\laboaratory\Test_Sclang.py 16 | 17 | sc_clean: 18 | rm SuperCollider\Skoar\lex.sc 19 | rm SuperCollider\Skoar\rdpp.sc 20 | 21 | clean: sc_clean 22 | 23 | all: sc_parser sc_sanity 24 | -------------------------------------------------------------------------------- /Project.ede: -------------------------------------------------------------------------------- 1 | ;; Object Skoarcery 2 | ;; EDE Project Files are auto generated: Do Not Edit 3 | (ede-proj-project "Skoarcery" 4 | :file "Project.ede" 5 | :name "Skoarcery" 6 | :targets nil) 7 | -------------------------------------------------------------------------------- /SkoarPyon/apparatus.py: -------------------------------------------------------------------------------- 1 | from collections import UserDict 2 | from Skoarcery.SkoarPyon import toke_inspector, skoarmantics 3 | from Skoarcery.SkoarPyon.lex import Toke_Whitespace, Toke_EOF, SkoarToke 4 | 5 | 6 | class Toker: 7 | 8 | def __init__(I, code): 9 | I.skoarse = code 10 | I.am_here = 0 11 | I.saw = None 12 | 13 | def see(I, want): 14 | 15 | if I.saw: 16 | if isinstance(I.saw, want): 17 | return I.saw 18 | else: 19 | I.saw = want.match(I.skoarse, I.am_here) 20 | return I.saw 21 | 22 | return None 23 | 24 | def sees(I, wants): 25 | 26 | I.am_here += Toke_Whitespace.burn(I.skoarse, I.am_here) 27 | 28 | for want in wants: 29 | X = I.see(want) 30 | if X: 31 | return X 32 | 33 | return None 34 | 35 | def burn(I, want): 36 | 37 | toke = I.saw 38 | 39 | if toke is None: 40 | toke = I.see(want) 41 | 42 | if isinstance(toke, want): 43 | I.saw = None 44 | I.am_here += toke.burn() 45 | I.am_here += Toke_Whitespace.burn(I.skoarse, I.am_here) 46 | return toke 47 | 48 | raise Exception("I tried to burn " + want.__name__ + ", but what I saw is " + toke.__class__.__name__) 49 | 50 | def eof(I): 51 | try: 52 | Toke_EOF.burn(I.skoarse, I.am_here) 53 | except: 54 | I.dump() 55 | raise 56 | 57 | def dump(I): 58 | print("\nToker Dump") 59 | print("here : " + str(I.am_here)) 60 | print("saw : " + str(I.saw)) 61 | print("skoarse: " + I.skoarse[0:I.am_here] + "_$_" + I.skoarse[I.am_here:-1]) 62 | 63 | 64 | # -------------- 65 | # The Parse Tree 66 | # -------------- 67 | class SkoarNoad: 68 | 69 | def __init__(self, name, parent, i=0): 70 | self.performer = lambda x: None 71 | self.j = 0 72 | self.parent = parent 73 | self.i = i # position in parent 74 | self.n = 0 # number of children 75 | self.name = name 76 | self.children = [] 77 | self.is_beat = False 78 | self.next_jmp = None 79 | self.toke = None 80 | 81 | # if isinstance(toke, SkoarToke): 82 | # self.inspectable = toke.__class__.inspectable 83 | # else: 84 | # self.inspectable = False 85 | 86 | # ------------------ 87 | # shrinking the tree 88 | # ------------------ 89 | def replace_children(self, children): 90 | self.children = children 91 | self.recount_children() 92 | 93 | def recount_children(self): 94 | i = 0 95 | n = 0 96 | 97 | for x in self.children: 98 | if isinstance(x, SkoarNoad): 99 | x.i = i 100 | i += 1 101 | n += 1 102 | 103 | self.n = n 104 | 105 | # ---------------- 106 | # growing the tree 107 | # ---------------- 108 | def add_noad(self, noad): 109 | self.children.append(noad) 110 | noad.i = self.n 111 | self.n += 1 112 | 113 | def add_toke(self, name, toke): 114 | noad = SkoarNoad(name, self, self.n) 115 | noad.toke = toke 116 | self.children.append(noad) 117 | self.n += 1 118 | 119 | def absorb_toke(self): 120 | if self.n == 1: 121 | 122 | x = self.children.pop() 123 | self.n = 0 124 | 125 | if isinstance(x, SkoarNoad) and x.toke: 126 | self.toke = x.toke 127 | else: 128 | self.toke = x 129 | 130 | return self.toke 131 | 132 | # ---------------- 133 | # showing the tree 134 | # ---------------- 135 | def draw_tree(self, tab=1): 136 | s = ("{:>" + str(tab) + "}{}\n").format(" ", self.name) 137 | for x in self.children: 138 | if x: 139 | s += x.draw_tree(tab + 1) 140 | 141 | return s 142 | 143 | # ----------------- 144 | # Climbing the Tree 145 | # ----------------- 146 | def depth_visit(self, f): 147 | 148 | for x in self.children: 149 | if x: 150 | x.depth_visit(f) 151 | 152 | f(self) 153 | 154 | def next_item(self): 155 | 156 | if self.next_jmp: 157 | return self.next_jmp 158 | 159 | if self.j == self.n: 160 | if self.parent is None: 161 | raise StopIteration 162 | 163 | return self.parent.next_item() 164 | 165 | n = self.children[self.j] 166 | self.j += 1 167 | return n 168 | 169 | def go_here_next(self, noad): 170 | self.next_jmp = noad 171 | noad.parent.j = noad.i 172 | 173 | # ------------------- 174 | # performing the tree 175 | # ------------------- 176 | def on_enter(self): 177 | self.j = 0 178 | 179 | def action(self): 180 | self.performer() 181 | 182 | 183 | class SkoarIterator: 184 | 185 | def __init__(self, skoar): 186 | self.noad = skoar.tree 187 | 188 | def __iter__(self): 189 | return self 190 | 191 | def __next__(self): 192 | x = self.noad.next_item() 193 | 194 | if isinstance(x, SkoarNoad): 195 | self.noad = x 196 | x.on_enter() 197 | 198 | return x 199 | 200 | 201 | class Skoar: 202 | 203 | def __init__(self, skoarse): 204 | from ..SkoarPyon import rdpp 205 | self.skoarse = skoarse 206 | self.tree = None 207 | self.toker = Toker(self.skoarse) 208 | self.parser = rdpp.SkoarParser(self) 209 | self.markers = [] 210 | 211 | self.control_stack = [] 212 | 213 | self.cur_noat = None 214 | self.noat_direction = 1 215 | 216 | def parse(self): 217 | self.tree = self.parser.skoar(None) 218 | self.tree.draw_tree() 219 | self.toker.eof() 220 | 221 | def decorate(self, loud=False): 222 | 223 | debug = (lambda x: print(x)) if loud else (lambda x: x) 224 | 225 | def inspect(x): 226 | 227 | # tokens* 228 | if x.toke: 229 | try: 230 | # run the function x.name, pass the token 231 | toke_inspector.__dict__[x.name](x.toke) 232 | 233 | debug("decorated toke " + x.name + ":") 234 | for k, v in x.toke.__dict__.items(): 235 | debug(" " + k + ": " + str(v)) 236 | debug("") 237 | except KeyError: 238 | pass 239 | 240 | # nonterminals* 241 | else: 242 | try: 243 | # run the function, pass the noad (not the nonterminal) 244 | y = skoarmantics.__dict__[x.name] 245 | y(self, x) 246 | 247 | debug("decorated noad " + x.name + ":") 248 | for k, v in x.__dict__.items(): 249 | if k not in ["children", "parent", "toke", "inspectable"]: 250 | debug(" " + k + ": " + repr(v)) 251 | debug("") 252 | except KeyError: 253 | pass 254 | 255 | self.tree.depth_visit(inspect) 256 | 257 | def get_pattern_gen(self): 258 | for x in SkoarIterator(self): 259 | if isinstance(x, SkoarNoad): 260 | 261 | # run performance handler 262 | x.performer(self) 263 | 264 | if x.is_beat: 265 | yield [self.cur_noat.lexeme, x.beat.val] 266 | 267 | # ---- 268 | # misc 269 | # ---- 270 | def noat_go(self, noat): 271 | 272 | self.cur_noat = noat 273 | 274 | # # find direction and if we're moving 275 | # move = True 276 | # if noat.up: 277 | # self.noat_direction = 1 278 | # 279 | # elif noat.down: 280 | # self.noat_direction = -1 281 | # 282 | # elif noat == self.cur_noat: 283 | # move = False 284 | # 285 | # # move if we do 286 | # if move and self.noat_direction > 0: 287 | # print("up to ", end="") 288 | # 289 | # elif move and self.noat_direction < 0: 290 | # print("down to ", end="") 291 | # 292 | # print(noat.letter, end="") 293 | # 294 | # for i in range(0, noat.sharps): 295 | # print("#", end="") 296 | # 297 | # for i in range(0, noat.flats): 298 | # print("b", end="") 299 | 300 | # save these in a list for jumping around in 301 | def add_marker(self, marker_noad): 302 | self.markers.append(marker_noad) 303 | 304 | def jmp_colon(self, noad): 305 | from Skoarcery.SkoarPyon.lex import Toke_Bars 306 | toke = noad.toke 307 | 308 | if toke.unspent: 309 | # spend it 310 | toke.unspent = False 311 | print("here") 312 | # find where we are in self.markers 313 | j = 0 314 | n = len(self.markers) 315 | for i in range(0, n): 316 | t = self.markers[i] 317 | if noad == t: 318 | j = i 319 | break 320 | else: 321 | raise AssertionError("couldn't find where we are in markers") 322 | 323 | # go backwards in list and find either a 324 | # post_repeat or the start 325 | for i in range(j - 1, 0, -1): 326 | x = self.markers[i] 327 | t = x.toke 328 | 329 | if isinstance(t, Toke_Bars) and t.post_repeat: 330 | noad.go_here_next(x) 331 | break 332 | else: 333 | noad.go_here_next(self.markers[0]) 334 | 335 | 336 | def parse(src): 337 | 338 | skoar = Skoar(src) 339 | skoar.parse() 340 | 341 | return skoar 342 | 343 | -------------------------------------------------------------------------------- /SkoarPyon/skoarmantics.py: -------------------------------------------------------------------------------- 1 | # ============ 2 | # Skoarmantics 3 | # ============ 4 | 5 | # 6 | # We went depth first so our children should be defined 7 | # 8 | 9 | 10 | def msg_chain_node(skoar, noad): 11 | pass 12 | 13 | 14 | def beat(skoar, noad): 15 | noad.absorb_toke() 16 | noad.beat = noad.toke 17 | noad.is_beat = True 18 | 19 | 20 | def meter_beat(skoar, noad): 21 | noad.absorb_toke() 22 | noad.beat = noad.toke 23 | 24 | 25 | def listy(skoar, noad): 26 | from Skoarcery.SkoarPyon.lex import Toke_ListSep 27 | 28 | X = [] 29 | 30 | for x in noad.children[1:-1]: 31 | if x.toke and isinstance(x.toke, Toke_ListSep): 32 | continue 33 | X.append(x) 34 | 35 | noad.replace_children(X) 36 | 37 | 38 | def clef(skoar, noad): 39 | pass 40 | 41 | 42 | def meter_symbolic(skoar, noad): 43 | pass 44 | 45 | 46 | def stmt(skoar, noad): 47 | pass 48 | 49 | 50 | def musical_keyword_misc(skoar, noad): 51 | pass 52 | 53 | 54 | def coda(skoar, noad): 55 | pass 56 | 57 | 58 | def meter_ass(skoar, noad): 59 | pass 60 | 61 | 62 | def assignment(skoar, noad): 63 | pass 64 | 65 | 66 | def accidentally(skoar, noad): 67 | pass 68 | 69 | 70 | def boolean(skoar, noad): 71 | pass 72 | 73 | 74 | def ottavas(skoar, noad): 75 | pass 76 | 77 | 78 | def skoaroid(skoar, noad): 79 | pass 80 | 81 | 82 | def msg(skoar, noad): 83 | pass 84 | 85 | 86 | def dal_goto(skoar, noad): 87 | pass 88 | 89 | 90 | def cthulhu(skoar, noad): 91 | pass 92 | 93 | 94 | def dynamic(skoar, noad): 95 | pass 96 | 97 | 98 | def optional_carrots(skoar, noad): 99 | pass 100 | 101 | 102 | def meter_sig_prime(skoar, noad): 103 | pass 104 | 105 | 106 | def meter(skoar, noad): 107 | 108 | # trim start and end tokens 109 | noad.replace_children(noad.children[1:-1]) 110 | 111 | 112 | def marker(skoar, noad): 113 | from Skoarcery.SkoarPyon.lex import Toke_Bars 114 | 115 | noad.absorb_toke() 116 | skoar.add_marker(noad) 117 | 118 | toke = noad.toke 119 | if isinstance(toke, Toke_Bars): 120 | if toke.pre_repeat > 0: 121 | noad.performer = (lambda x: x.jmp_colon(noad)) 122 | 123 | 124 | def noaty(skoar, noad): 125 | pass 126 | 127 | 128 | def noat_literal(skoar, noad): 129 | from Skoarcery.SkoarPyon.lex import Toke_NamedNoat 130 | 131 | noat = noad.absorb_toke() 132 | noad.noat = noat 133 | 134 | if isinstance(noat, Toke_NamedNoat): 135 | noad.performer = (lambda x: x.noat_go(noat)) 136 | 137 | 138 | def noat_reference(skoar, noad): 139 | 140 | # TODO Symbol | CurNoat | listy 141 | pass 142 | 143 | 144 | 145 | def pedally(skoar, noad): 146 | pass 147 | 148 | 149 | -------------------------------------------------------------------------------- /SkoarPyon/skoarmantics_template.py: -------------------------------------------------------------------------------- 1 | # ======================================================================================== 2 | # Skoarmantics - Generated by Code_Skoarmantics_Py on 2014-05-05 21:29:46 for Python 3.3.2 3 | # ======================================================================================== 4 | 5 | 6 | 7 | 8 | # - 9 | # 10 | # - 11 | def musical_keyword_misc(skoar, noad): 12 | pass 13 | 14 | 15 | def meter_sig_prime(skoar, noad): 16 | pass 17 | 18 | 19 | def optional_carrots(skoar, noad): 20 | pass 21 | 22 | 23 | def meter(skoar, noad): 24 | pass 25 | 26 | 27 | def ottavas(skoar, noad): 28 | pass 29 | 30 | 31 | def msg(skoar, noad): 32 | pass 33 | 34 | 35 | def pedally(skoar, noad): 36 | pass 37 | 38 | 39 | def dynamic(skoar, noad): 40 | pass 41 | 42 | 43 | def meter_beat(skoar, noad): 44 | pass 45 | 46 | 47 | def coda(skoar, noad): 48 | pass 49 | 50 | 51 | def markers(skoar, noad): 52 | pass 53 | 54 | 55 | def cthulhu(skoar, noad): 56 | pass 57 | 58 | 59 | def dal_goto(skoar, noad): 60 | pass 61 | 62 | 63 | def accidentally(skoar, noad): 64 | pass 65 | 66 | 67 | def listy(skoar, noad): 68 | pass 69 | 70 | 71 | def skoaroid(skoar, noad): 72 | pass 73 | 74 | 75 | def assignment(skoar, noad): 76 | pass 77 | 78 | 79 | def beat(skoar, noad): 80 | pass 81 | 82 | 83 | def boolean(skoar, noad): 84 | pass 85 | 86 | 87 | def stmt(skoar, noad): 88 | pass 89 | 90 | 91 | def meter_symbolic(skoar, noad): 92 | pass 93 | 94 | 95 | def msg_chain_node(skoar, noad): 96 | pass 97 | 98 | 99 | def meter_ass(skoar, noad): 100 | pass 101 | 102 | 103 | def clef(skoar, noad): 104 | pass 105 | 106 | 107 | -------------------------------------------------------------------------------- /SkoarPyon/toke_inspector.py: -------------------------------------------------------------------------------- 1 | # ============== 2 | # toke_inspector 3 | # ============== 4 | # 5 | # Here we pick the vals out of the tokens 6 | # and set its attributes appropriately 7 | from math import ldexp 8 | 9 | import re 10 | 11 | 12 | def Toke_Int(toke): 13 | toke.val = int(toke.lexeme) 14 | 15 | 16 | def Toke_Float(toke): 17 | toke.val = float(toke.lexeme) 18 | 19 | 20 | def Toke_Carrots(toke): 21 | toke.val = len(toke.lexeme) 22 | 23 | 24 | def Toke_Tuplet(toke): 25 | toke.val = 0 26 | 27 | 28 | def Toke_Crotchets(toke): 29 | toke.is_rest = True 30 | toke.val = 2 ** len(toke.lexeme) 31 | 32 | 33 | def Toke_Quavers(toke): 34 | toke.is_rest = True 35 | # len("oo/") 36 | toke.val = ldexp(1, -(len(toke.lexeme) - 1)) 37 | 38 | 39 | def Toke_DynPiano(toke): 40 | toke.val = 0 41 | 42 | 43 | def Toke_DynForte(toke): 44 | toke.val = 0 45 | 46 | 47 | def Toke_Quarters(toke): 48 | toke.is_rest = False 49 | toke.val = 2 ** (len(toke.lexeme) - 1) 50 | 51 | 52 | def Toke_Eighths(toke): 53 | toke.is_rest = False 54 | toke.val = ldexp(1, -len(toke.lexeme)) 55 | 56 | 57 | vector_noat_regex = re.compile(r"(~?)([a-g])(?:(#*)|(b*))(~?)") 58 | 59 | 60 | def Toke_NamedNoat(toke): 61 | s = toke.lexeme 62 | 63 | r = vector_noat_regex.search(s) 64 | 65 | if r.group(1): 66 | toke.up = True 67 | 68 | toke.letter = r.group(2) 69 | 70 | sharps = r.group(3) 71 | if sharps: 72 | toke.sharps = len(sharps) 73 | 74 | flats = r.group(4) 75 | if flats: 76 | toke.flats = len(flats) 77 | 78 | if r.group(5): 79 | if toke.up: 80 | raise AssertionError("Can't noat up and down: " + s) 81 | toke.down = True 82 | 83 | 84 | def Toke_BooleanOp(toke): 85 | toke.val = toke.lexeme 86 | 87 | 88 | def Toke_Choard(toke): 89 | toke.val = toke.lexeme 90 | 91 | 92 | def Toke_MsgName(toke): 93 | toke.val = toke.lexeme 94 | 95 | 96 | def Toke_MsgNameWithArgs(toke): 97 | toke.val = toke.lexeme.rstrip("<") 98 | 99 | 100 | def Toke_Volta(toke): 101 | toke.val = int(toke.lexeme.strip("[.]")) 102 | 103 | 104 | def Toke_Symbol(toke): 105 | toke.val = toke.lexeme[1:] 106 | 107 | 108 | def Toke_Segno(toke): 109 | a = toke.lexeme.split("_") 110 | if len(a) > 1: 111 | toke.label = a[1] 112 | else: 113 | toke.label = "" 114 | 115 | 116 | def Toke_String(toke): 117 | toke.val = toke.lexeme[1:-1] 118 | 119 | 120 | def Toke_Bars(toke): 121 | toke.pre_repeat = toke.lexeme.startswith(":") 122 | toke.post_repeat = toke.lexeme.endswith(":") 123 | toke.unspent = True 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /SkoarPyon/toke_inspector_template.py: -------------------------------------------------------------------------------- 1 | # ============================================================================================= 2 | # toke_inspector - Generated by Code_Lexer_Inspector_Py on 2014-05-10 14:13:48 for Python 3.3.2 3 | # ============================================================================================= 4 | 5 | import re 6 | import abc 7 | 8 | 9 | # ----------- 10 | # Value Tokes 11 | # ----------- 12 | def Toke_Comment(toke): 13 | toke.val = 0 14 | 15 | 16 | def Toke_Int(toke): 17 | toke.val = 0 18 | 19 | 20 | def Toke_Float(toke): 21 | toke.val = 0 22 | 23 | 24 | def Toke_Carrots(toke): 25 | toke.val = 0 26 | 27 | 28 | def Toke_Tuplet(toke): 29 | toke.val = 0 30 | 31 | 32 | def Toke_Crotchets(toke): 33 | toke.val = 0 34 | 35 | 36 | def Toke_Quavers(toke): 37 | toke.val = 0 38 | 39 | 40 | def Toke_DynPiano(toke): 41 | toke.val = 0 42 | 43 | 44 | def Toke_DynForte(toke): 45 | toke.val = 0 46 | 47 | 48 | def Toke_Quarters(toke): 49 | toke.val = 0 50 | 51 | 52 | def Toke_Eighths(toke): 53 | toke.val = 0 54 | 55 | 56 | def Toke_NamedNoat(toke): 57 | toke.val = 0 58 | 59 | 60 | def Toke_BooleanOp(toke): 61 | toke.val = 0 62 | 63 | 64 | def Toke_Choard(toke): 65 | toke.val = 0 66 | 67 | 68 | def Toke_MsgName(toke): 69 | toke.val = 0 70 | 71 | 72 | def Toke_MsgNameWithArgs(toke): 73 | toke.val = 0 74 | 75 | 76 | def Toke_Segno(toke): 77 | toke.val = 0 78 | 79 | 80 | def Toke_Volta(toke): 81 | toke.val = 0 82 | 83 | 84 | def Toke_Symbol(toke): 85 | toke.val = 0 86 | 87 | 88 | def Toke_String(toke): 89 | toke.val = 0 90 | 91 | 92 | def Toke_Bars(toke): 93 | toke.val = 0 94 | 95 | 96 | -------------------------------------------------------------------------------- /Skoar_SC.testsettings: -------------------------------------------------------------------------------- 1 |  2 | 3 | build skoar for supercollider 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Skoarcery/SkoarPyon/.gitignore: -------------------------------------------------------------------------------- 1 | lex.py 2 | rdpp.py 3 | -------------------------------------------------------------------------------- /Skoarcery/dragonsets.py: -------------------------------------------------------------------------------- 1 | # ========================================== 2 | # FIRST and FOLLOW sets from the dragon book 3 | # ========================================== 4 | from Skoarcery.langoids import Nonterminal, Production, Langoid 5 | 6 | FIRST = None 7 | FOLLOW = None 8 | 9 | 10 | def init(compute=True): 11 | global FIRST, FOLLOW 12 | 13 | FIRST = DragonSet("FIRST") 14 | FOLLOW = DragonSet("FOLLOW") 15 | 16 | print("Dragon sets initialized.") 17 | 18 | if compute: 19 | compute_sets() 20 | 21 | 22 | def compute_sets(): 23 | compute_firsts() 24 | compute_follows() 25 | 26 | print("Dragon sets computed") 27 | 28 | 29 | class DragonSet: 30 | 31 | def __init__(self, name): 32 | self.name = name 33 | self.D = dict() 34 | 35 | def __call__(self, *args): 36 | 37 | key = "" 38 | X = args[0] 39 | 40 | if not X: 41 | print("EH? " + repr(args)) 42 | raise AssertionError 43 | 44 | if isinstance(X, str): 45 | key = X 46 | 47 | if isinstance(X, Langoid): 48 | key = X.name 49 | 50 | if isinstance(X, Production): 51 | X = X.production 52 | 53 | if isinstance(X, list): 54 | if self.name == "FIRST": 55 | return FIRST_SEQ(X) 56 | raise NotImplementedError 57 | 58 | #print("Key: " + key + " < " + str(X) + " < " + repr(args[0])) 59 | try: 60 | S = self.D[key] 61 | except KeyError: 62 | S = set() 63 | self.D[key] = S 64 | 65 | return S 66 | 67 | def __len__(self): 68 | i = 0 69 | 70 | for S in self.D.values(): 71 | i += len(S) 72 | 73 | return i 74 | 75 | def add_element(self, key, element): 76 | 77 | #print("add-Elemetn: " + repr(key) + str(key.__class__)) 78 | 79 | try: 80 | S = self.D[key.name] 81 | except KeyError: 82 | S = set() 83 | 84 | S.add(element) 85 | self.D[key.name] = S 86 | 87 | def __str__(self): 88 | s = "" 89 | 90 | for k, v in self.D.items(): 91 | s += self.name + "(" + str(k) + "): " + str(v) + "\n" 92 | 93 | return s 94 | 95 | 96 | def compute_firsts(): 97 | 98 | from Skoarcery.terminals import Empty, tokens as T 99 | from Skoarcery.nonterminals import nonterminals as N 100 | 101 | global FIRST 102 | 103 | # do terminals first 104 | for X in T.values(): 105 | FIRST(X).add(X) 106 | 107 | last = 0 108 | first_len = len(FIRST) 109 | while first_len > last: 110 | 111 | last = first_len 112 | 113 | for X in N.values(): 114 | if X.derives_empty: 115 | FIRST(X).add(Empty) 116 | 117 | for R in X.production_rules: 118 | 119 | i = -1 120 | n = len(R.production) 121 | 122 | # figure out FIRST(X) first 123 | for Yi in R.production: 124 | i += 1 125 | 126 | Yi_to_end = R.production[i:] 127 | 128 | if len(Yi_to_end) > 0: 129 | S = FIRST(Yi_to_end) 130 | 131 | S.update( 132 | everything_but_e(FIRST(Yi)) 133 | ) 134 | 135 | FIRST(X).update(S) 136 | FIRST(Yi_to_end).update(S) 137 | 138 | if not Yi.derives_empty: 139 | break 140 | 141 | # if we got to the end of the loop without breaking, add Empty 142 | else: 143 | FIRST(X).add(Empty) 144 | 145 | first_len = len(FIRST) 146 | 147 | 148 | def everything_but_e(S): 149 | from Skoarcery.terminals import Empty 150 | 151 | return {el for el in S if el != Empty} 152 | 153 | 154 | #noinspection PyPep8Naming 155 | def FIRST_SEQ(list_of_langoids): 156 | from Skoarcery.terminals import Empty 157 | 158 | global FIRST 159 | 160 | OUT = set() 161 | 162 | for Yi in list_of_langoids: 163 | 164 | S = FIRST(Yi) 165 | 166 | OUT.update(everything_but_e(S)) 167 | 168 | if Empty not in S: 169 | break 170 | 171 | # if we got to the end of the loop without breaking, add Empty 172 | else: 173 | OUT.add(Empty) 174 | 175 | return OUT 176 | 177 | 178 | #noinspection PyPep8Naming 179 | def compute_follows(): 180 | from Skoarcery.terminals import EOF, Empty 181 | from Skoarcery.nonterminals import nonterminals as N, SKOAR 182 | 183 | global FIRST, FOLLOW 184 | 185 | # start symbol gets end symbol 186 | FOLLOW(SKOAR).add(EOF) 187 | 188 | # repeat until nothing can be added to any follow set 189 | last = 0 190 | follow_len = len(FOLLOW) 191 | while follow_len > last: 192 | 193 | last = follow_len 194 | 195 | for X in N.values(): 196 | 197 | for R in X.production_rules: 198 | 199 | A = R.production 200 | 201 | # If there is a production [ A -> alpha B beta]: 202 | # everything except in FIRST(beta) is in FOLLOW(B) 203 | 204 | # examine each suffix (except last) 205 | n = len(A) 206 | 207 | for i in range(0, n - 1): 208 | 209 | B = A[i] 210 | if not isinstance(B, Nonterminal): 211 | continue 212 | 213 | beta = A[i + 1:] 214 | 215 | #print("n: " + str(n) + " i: " + str(i) + " A: " + repr(A) + " beta: " + repr(beta)) 216 | 217 | S = FIRST(beta) 218 | FOLLOW(B).update(everything_but_e(S)) 219 | 220 | for i in reversed(range(0, n)): 221 | 222 | B = A[i] 223 | if not isinstance(B, Nonterminal): 224 | continue 225 | 226 | # we are at the end of the list 227 | if i == n - 1: 228 | FOLLOW(B).update(FOLLOW(X)) 229 | continue 230 | 231 | beta = A[i + 1:] 232 | 233 | S = FIRST(beta) 234 | 235 | #print(": FIRST(" + repr(beta) + ") = " + repr(S)) 236 | 237 | if Empty in S: 238 | FOLLOW(B).update(FOLLOW(X)) 239 | else: 240 | break 241 | 242 | follow_len = len(FOLLOW) 243 | 244 | 245 | -------------------------------------------------------------------------------- /Skoarcery/factoary/Build_Py.py: -------------------------------------------------------------------------------- 1 | from imp import reload 2 | import unittest 3 | from Skoarcery.factoary.Buildoar import Buildoar 4 | from Skoarcery.factoary.Code_Lexer_Py import Code_Lexer_Py 5 | from Skoarcery.factoary.Code_Parser_Py import Code_Parser_Py 6 | from Skoarcery.laboaratoary.TestDragonSpells import DragonTests 7 | from Skoarcery.laboaratoary.ExamineParseTree import ExamineParseTree 8 | from Skoarcery.laboaratoary.TestParseTable import Verify_LL_1 9 | from Skoarcery.laboaratoary.TestNonterminals import TestNonterminals 10 | from Skoarcery.laboaratoary.TestPerformer import Test_Performer 11 | from Skoarcery.laboaratoary.TestTerminals import TestTokens 12 | from Skoarcery.laboaratoary.TestApparatus import Test_Apparatus 13 | 14 | 15 | class Build_Pymp(Buildoar): 16 | 17 | def tes_Build_Skoar_Python(self): 18 | 19 | # 20 | # Grammar 21 | self.step("Test Grammar", 22 | [TestTokens, TestNonterminals, Verify_LL_1, DragonTests]) 23 | 24 | # 25 | # Lexer 26 | self.step("Build Lexer", Code_Lexer_Py) 27 | 28 | from Skoarcery.SkoarPyon import lex 29 | reload(lex) 30 | 31 | # # 32 | # # Toke Inspector 33 | # self.step(Code_Lexer_Inspector_Py) 34 | # 35 | # from Skoarcery.pymp import toke_inspector 36 | # reload(toke_inspector) 37 | 38 | # 39 | # Parser 40 | self.step("Build Parser", Code_Parser_Py) 41 | 42 | from Skoarcery.SkoarPyon import rdpp 43 | reload(rdpp) 44 | 45 | # 46 | # Apparatus 47 | self.step("Sanity", 48 | [Test_Apparatus, ExamineParseTree, Test_Performer]) 49 | 50 | if __name__ == '__main__': 51 | unittest.main() 52 | -------------------------------------------------------------------------------- /Skoarcery/factoary/Build_Sc.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from Skoarcery.factoary.Buildoar import Buildoar 3 | from Skoarcery.factoary.Code_Lexer_Sc import Code_Lexer_Sc 4 | from Skoarcery.factoary.Code_Parser_Sc import Code_Parser_Sc 5 | from Skoarcery.laboaratoary.TestDragonSpells import DragonTests 6 | from Skoarcery.laboaratoary.TestParseTable import Verify_LL_1 7 | from Skoarcery.laboaratoary.TestNonterminals import TestNonterminals 8 | from Skoarcery.laboaratoary.TestTerminals import TestTokens 9 | from Skoarcery.laboaratoary.Test_Sclang import Test_Sclang, Test_Sclang_Sanity, Test_Sclang_Dev 10 | 11 | 12 | class Build_Sc(Buildoar): 13 | 14 | def build(self): 15 | 16 | # 17 | # Grammar 18 | self.step("Test Grammar", 19 | [TestTokens, TestNonterminals, Verify_LL_1, DragonTests]) 20 | 21 | # 22 | # Lexer 23 | self.step("Build Lexer", Code_Lexer_Sc) 24 | 25 | # # 26 | # # Toke Inspector 27 | # 28 | # self.run_tests("Build toke inspector", Code_Lexer_Inspector_Sc)) 29 | 30 | # 31 | # Parser 32 | self.step("Build Parser", Code_Parser_Sc) 33 | 34 | # 35 | # SuperCollider should compile class lib 36 | 37 | def sanity(self): 38 | self.step("Sanity Tests", Test_Sclang_Sanity) 39 | 40 | # 41 | # Apparatus 42 | #self.step("Sanity", [Test_Apparatus, ExamineParseTree, Test_Performer]) 43 | 44 | def dev(self): 45 | self.step("Dev Tests", Test_Sclang_Dev) 46 | 47 | 48 | #if __name__ == '__main__': 49 | # b = Build_Sc() 50 | # b.build() 51 | 52 | -------------------------------------------------------------------------------- /Skoarcery/factoary/Buildoar.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | 4 | class Buildoar(unittest.TestCase): 5 | 6 | def step(self, msg, list_of_steps, assert_success=True): 7 | from unittest import TestSuite as TS, makeSuite as sweeten, TextTestRunner as Runner 8 | 9 | sweet = TS() 10 | 11 | if not isinstance(list_of_steps, list): 12 | list_of_steps = [list_of_steps] 13 | 14 | for test in list_of_steps: 15 | sweet.addTest(sweeten(test)) 16 | 17 | result = Runner().run(sweet) 18 | 19 | if assert_success: 20 | self.assertTrue(result.wasSuccessful(), msg) 21 | print(msg + ": [ OK ]") 22 | 23 | 24 | if __name__ == '__main__': 25 | unittest.main() 26 | -------------------------------------------------------------------------------- /Skoarcery/factoary/Code_Lexer_Py.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from Skoarcery import terminals, emissions, underskoar 4 | 5 | 6 | class Code_Lexer_Py(unittest.TestCase): 7 | 8 | def setUp(self): 9 | terminals.init() 10 | emissions.init() 11 | underskoar.init(emissions.PY) 12 | 13 | def imports(self): 14 | emissions.PY.raw( 15 | """ 16 | import re 17 | import abc 18 | 19 | 20 | class SubclassResponsibilityError(NotImplementedError): 21 | pass 22 | 23 | 24 | class SkoarError(AssertionError): 25 | pass 26 | 27 | 28 | """ 29 | ) 30 | 31 | def base_token(self): 32 | underskoar.skoarToke() 33 | 34 | def EOF_token(self): 35 | underskoar.EOF_token() 36 | 37 | def whitespace_token(self): 38 | underskoar.whitespace_token() 39 | 40 | def typical_token(self, token): 41 | underskoar.typical_token(token) 42 | 43 | def test_PY_lexer(self): 44 | 45 | fd = open("SkoarPyon/lex.py", mode="w") 46 | 47 | emissions.PY.fd = fd 48 | emissions.PY.file_header("lex", "Code_Py_Lexer") 49 | 50 | self.imports() 51 | self.base_token() 52 | self.whitespace_token() 53 | self.EOF_token() 54 | 55 | emissions.PY.cmt_hdr("Everyday Tokes") 56 | for token in terminals.tokens.values(): 57 | if token not in terminals.odd_balls: 58 | self.typical_token(token) 59 | 60 | fd.close() 61 | -------------------------------------------------------------------------------- /Skoarcery/factoary/Code_Lexer_Sc.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import os 3 | 4 | from Skoarcery import terminals, emissions, underskoar 5 | 6 | 7 | bs = "{" 8 | be = "}" 9 | 10 | 11 | class Code_Lexer_Sc(unittest.TestCase): 12 | 13 | def setUp(self): 14 | terminals.init() 15 | emissions.init() 16 | underskoar.init(emissions.SC) 17 | 18 | def exceptions(self): 19 | 20 | SC = emissions.SC 21 | SC.cmt_hdr("SkoarException") 22 | SC.class_("SkoarError", "Exception") 23 | 24 | SC.static_method("new", "msg") 25 | SC.return_("super.new(msg)") 26 | SC.end() 27 | 28 | SC.static_method("errorString") 29 | SC.return_('"SKOAR" ++ super.errorString') 30 | SC.end() 31 | 32 | SC.end() 33 | 34 | def base_token(self): 35 | underskoar.skoarToke() 36 | 37 | def EOF_token(self): 38 | underskoar.EOF_token() 39 | 40 | def whitespace_token(self): 41 | underskoar.whitespace_token() 42 | 43 | def typical_token(self, token): 44 | underskoar.typical_token(token) 45 | 46 | def test_SC_lexer(self): 47 | 48 | print(os.getcwd()) 49 | fd = open("SuperCollider/Skoar/lex.sc", mode="w") 50 | 51 | emissions.SC.fd = fd 52 | emissions.SC.file_header("lex", "Code_Sc_Lexer") 53 | 54 | self.exceptions() 55 | self.base_token() 56 | self.whitespace_token() 57 | self.EOF_token() 58 | 59 | emissions.SC.cmt_hdr("Everyday Tokes") 60 | for token in terminals.tokens.values(): 61 | if token not in terminals.odd_balls: 62 | self.typical_token(token) 63 | 64 | fd.close() -------------------------------------------------------------------------------- /Skoarcery/factoary/Code_Parser_Py.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from Skoarcery import langoids, terminals, nonterminals, dragonsets, parsetable, emissions 3 | from Skoarcery.langoids import Terminal, Nonterminal 4 | 5 | 6 | class Code_Parser_Py(unittest.TestCase): 7 | 8 | def setUp(self): 9 | terminals.init() 10 | nonterminals.init() 11 | langoids.init() 12 | dragonsets.init() 13 | parsetable.init() 14 | emissions.init() 15 | 16 | def test_PY_rdpp(self): 17 | from Skoarcery.dragonsets import FIRST, FOLLOW 18 | from Skoarcery.terminals import Empty 19 | 20 | fd = open("SkoarPyon/rdpp.py", "w") 21 | PY = emissions.PY 22 | PY.fd = fd 23 | 24 | # Header 25 | # Imports 26 | # class SkoarParseException 27 | # class SkoarParser: 28 | # __init__ 29 | # fail 30 | self.code_start() 31 | 32 | PY.tab += 1 33 | N = nonterminals.nonterminals.values() 34 | 35 | # precompute desirables 36 | PY.method("init_desirables") 37 | for A in N: 38 | 39 | R = A.production_rules 40 | 41 | PY.nl() 42 | PY.cmt(str(A)) 43 | 44 | # each production 45 | for P in R: 46 | 47 | if P.derives_empty: 48 | continue 49 | 50 | # A -> alpha 51 | alpha = P.production 52 | 53 | desires = FIRST(alpha) 54 | 55 | if Empty in desires: 56 | desires.discard(Empty) 57 | desires.update(FOLLOW(A)) 58 | 59 | i = 0 60 | 61 | n = len(desires) 62 | PY.dict_set("self.desirables", str(P), "[", end="") 63 | for toke in desires: 64 | PY.raw(toke.toker_name) 65 | i += 1 66 | if i != n: 67 | if i % 5 == 0: 68 | PY.raw(",\n") 69 | PY.stmt(" ", end="") 70 | else: 71 | PY.raw(", ") 72 | 73 | else: 74 | PY.raw("]\n") 75 | 76 | PY.end() 77 | 78 | # write each nonterminal as a function 79 | for A in N: 80 | 81 | R = A.production_rules 82 | 83 | #PY.cmt(str(A)) 84 | PY.stmt("def " + A.name + "(self, parent):") 85 | PY.tab += 1 86 | PY.stmt("self.tab += 1") 87 | 88 | if A.intermediate: 89 | PY.var("noad", "parent") 90 | else: 91 | PY.var("noad", PY.v_new("SkoarNoad", PY.v_sym(A.name), "parent")) 92 | 93 | PY.nl() 94 | 95 | #PY.code_line("print('" + A.name + "')") 96 | 97 | for P in R: 98 | 99 | if P.derives_empty: 100 | continue 101 | 102 | # A -> alpha 103 | alpha = P.production 104 | 105 | PY.stmt("desires = " + PY.v_dict_get("self.desirables", str(P))) 106 | 107 | PY.if_("self.toker.sees(desires)") 108 | 109 | #PY.print(str(P)) 110 | 111 | for x in alpha: 112 | if isinstance(x, Terminal): 113 | PY.stmt("noad.add_toke('" + x.toker_name + "', self.toker.burn(" + x.toker_name + "))") 114 | 115 | #PY.print("burning: " + x.name) 116 | else: 117 | if x.intermediate: 118 | PY.stmt("self." + x.name + "(noad)") 119 | else: 120 | PY.stmt("noad.add_noad(self." + x.name + "(noad))") 121 | else: 122 | PY.return_("noad") 123 | PY.tab -= 1 124 | PY.nl() 125 | 126 | if A.derives_empty: 127 | PY.cmt("") 128 | #PY.print("burning empty") 129 | PY.return_("noad") 130 | 131 | else: 132 | PY.cmt("Error State") 133 | PY.stmt("self.fail()") 134 | 135 | PY.tab -= 1 136 | PY.nl() 137 | 138 | PY.tab -= 1 139 | 140 | fd.close() 141 | 142 | def code_start(self): 143 | from Skoarcery.terminals import Empty 144 | 145 | PY = emissions.PY 146 | 147 | PY.file_header("rdpp", "PyRDPP - Create Recursive Descent Predictive Parser") 148 | s = "from Skoarcery.SkoarPyon.apparatus import SkoarNoad\n"\ 149 | "from Skoarcery.SkoarPyon.lex import " 150 | T = terminals.tokens.values() 151 | n = len(T) 152 | i = 0 153 | for t in T: 154 | if t == Empty: 155 | n -= 1 156 | continue 157 | s += t.toker_name 158 | i += 1 159 | if i < n: 160 | if i % 5 == 0: 161 | s += ", \\\n " 162 | else: 163 | s += ", " 164 | 165 | PY.raw(s + """ 166 | 167 | 168 | class SkoarParseException(Exception): 169 | pass 170 | 171 | 172 | class SkoarParser: 173 | 174 | def __init__(self, runtime): 175 | self.runtime = runtime 176 | self.toker = runtime.toker 177 | self.tab = 0 178 | self.desirables = dict() 179 | self.init_desirables() 180 | 181 | def fail(self): 182 | self.toker.dump() 183 | raise SkoarParseException 184 | 185 | @property 186 | def tabby(self): 187 | if self.tab == 0: 188 | return "" 189 | 190 | return ("{:>" + str(self.tab * 2) + "}").format(" ") 191 | 192 | def print(self, line, end): 193 | print(self.tabby + line, end=end) 194 | 195 | 196 | """) 197 | -------------------------------------------------------------------------------- /Skoarcery/factoary/Code_Parser_Sc.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from Skoarcery import langoids, terminals, nonterminals, dragonsets, parsetable, emissions 3 | from Skoarcery.langoids import Terminal, Nonterminal 4 | 5 | 6 | class Code_Parser_Sc(unittest.TestCase): 7 | 8 | def setUp(self): 9 | terminals.init() 10 | nonterminals.init() 11 | langoids.init() 12 | dragonsets.init() 13 | parsetable.init() 14 | emissions.init() 15 | 16 | def test_SC_rdpp(self): 17 | from Skoarcery.dragonsets import FIRST, FOLLOW 18 | from Skoarcery.terminals import Empty 19 | 20 | fd = open("SuperCollider/Skoar/rdpp.sc", "w") 21 | ____SC = SC = emissions.SC 22 | SC.fd = fd 23 | 24 | # Header 25 | # Imports 26 | # class SkoarParseException 27 | # class SkoarParser: 28 | # init 29 | # fail 30 | self.code_start() 31 | 32 | SC.tab += 1 33 | N = nonterminals.nonterminals.values() 34 | 35 | # precompute desirables 36 | SC.method("init_desirables") 37 | for A in N: 38 | 39 | R = A.production_rules 40 | 41 | SC.nl() 42 | SC.cmt(str(A)) 43 | 44 | # each production 45 | for P in R: 46 | 47 | if P.derives_empty: 48 | continue 49 | 50 | # A -> alpha 51 | alpha = P.production 52 | 53 | desires = FIRST(alpha) 54 | 55 | if Empty in desires: 56 | desires.discard(Empty) 57 | desires.update(FOLLOW(A)) 58 | 59 | i = 0 60 | 61 | n = len(desires) 62 | SC.dict_set("desirables", str(P), "[", end="") 63 | for toke in desires: 64 | SC.raw(toke.toker_name) 65 | i += 1 66 | if i != n: 67 | if i % 5 == 0: 68 | SC.raw(",\n") 69 | SC.stmt(" ", end="") 70 | else: 71 | SC.raw(", ") 72 | 73 | else: 74 | SC.raw("]);\n") 75 | 76 | SC.end() 77 | 78 | # write each nonterminal as a function 79 | for A in N: 80 | 81 | R = A.production_rules 82 | 83 | #SC.cmt(str(A)) 84 | SC.method(A.name, "parent") 85 | 86 | if A.intermediate: 87 | SC.var("noad", "parent") 88 | else: 89 | SC.var("noad", SC.v_new("SkoarNoad", SC.v_sym(A.name), "parent")) 90 | 91 | SC.var("desires", SC.null) 92 | SC.nl() 93 | 94 | SC.stmt("deep = deep + 1") 95 | SC.if_("deep > 100") 96 | ____SC.stmt("this.fail_too_deep") 97 | SC.end_if() 98 | 99 | # each production 100 | for P in R: 101 | 102 | if P.derives_empty: 103 | continue 104 | 105 | # A -> alpha 106 | alpha = P.production 107 | 108 | SC.stmt("desires = " + SC.v_dict_get("desirables", str(P))) 109 | 110 | SC.cmt(str(P)) 111 | 112 | SC.if_("toker.sees(desires).notNil") 113 | 114 | # debugging 115 | #SC.print(str(P)) 116 | 117 | for x in alpha: 118 | if isinstance(x, Terminal): 119 | SC.stmt('noad.add_toke(' + SC.v_sym(x.toker_name) + ', toker.burn(' + x.toker_name + '))') 120 | 121 | # debugging 122 | #SC.print("burning: " + x.name) 123 | else: 124 | if x.intermediate: 125 | SC.stmt(SC.this + "." + x.name + "(noad)") 126 | else: 127 | SC.stmt("noad.add_noad(this." + x.name + "(noad))") 128 | else: 129 | SC.stmt("deep = deep - 1") 130 | SC.return_("noad") 131 | 132 | SC.end_if() 133 | 134 | if A.derives_empty: 135 | SC.cmt("") 136 | 137 | # debugging 138 | #SC.print("burning empty") 139 | 140 | SC.stmt("deep = deep - 1") 141 | SC.return_("noad") 142 | 143 | else: 144 | SC.cmt("Error State") 145 | SC.stmt("this.fail") 146 | 147 | SC.end() 148 | 149 | SC.end() 150 | 151 | fd.close() 152 | 153 | def code_start(self): 154 | SC = emissions.SC 155 | SC.file_header("rdpp", "Code_Parser_Sc - Create Recursive Descent Predictive Parser") 156 | SC.raw(""" 157 | SkoarParseException : Exception { 158 | 159 | } 160 | 161 | SkoarParser { 162 | 163 | var 50} {}".format(str(N), str(X))) 36 | 37 | def test_follow(self): 38 | 39 | print("\n\n ==========--------( FOLLOW sets )--------------------------------------------------------========\n\n") 40 | 41 | dragonsets.compute_follows() 42 | 43 | X = list() 44 | for K in dragonsets.FOLLOW.D.keys(): 45 | X.append(K) 46 | 47 | X.sort() 48 | 49 | for K in X: 50 | FK = dragonsets.FOLLOW(K) 51 | 52 | self.assertGreater(len(FK), 0) 53 | 54 | print("{:>50} {}".format(str(K), str(FK))) 55 | 56 | -------------------------------------------------------------------------------- /Skoarcery/laboaratoary/TestNonterminals.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from Skoarcery import dragonsets, terminals, nonterminals 3 | 4 | 5 | class TestNonterminals(unittest.TestCase): 6 | 7 | def setUp(self): 8 | terminals.init() 9 | nonterminals.init() 10 | 11 | def tearDown(self): 12 | pass 13 | 14 | 15 | def test_unused(self): 16 | T = terminals.tokens 17 | N = nonterminals.nonterminals 18 | 19 | unused = [] 20 | 21 | skip = [N["skoar"]] 22 | 23 | for x in N.values(): 24 | 25 | if x in skip: 26 | continue 27 | 28 | # should be on the right side of some production 29 | uses = False 30 | for n in N.values(): 31 | uses |= 0 < len([p for p in n.production_rules if x in p.production]) 32 | 33 | if not uses: 34 | unused.append(x.name) 35 | 36 | if unused: 37 | print("-------( Unused Nonterminals ) ------------\n") 38 | for untoked in unused: 39 | print(untoked) 40 | print("") 41 | 42 | self.fail("Unused Nonterminals: " + str(len(unused))) 43 | 44 | 45 | 46 | def test_undefined(self): 47 | T = terminals.tokens 48 | N = nonterminals.nonterminals 49 | 50 | undefined = set() 51 | 52 | # verify everything on the right side is defined 53 | for x in N.values(): 54 | 55 | for p in x.production_rules: 56 | 57 | for y in p.production: 58 | 59 | if not (y in N.values() or y in T.values()): 60 | 61 | undefined.add(y) 62 | 63 | if len(undefined) > 0: 64 | print("-------( Undefined langoids in productions ) ------------\n") 65 | for x in undefined: 66 | print(x.name) 67 | print("") 68 | 69 | self.fail("Unused Nonterminals: " + str(len(undefined))) 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Skoarcery/laboaratoary/TestParseTable.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from Skoarcery import langoids, terminals, nonterminals, dragonsets 3 | from Skoarcery.langoids import Terminal 4 | 5 | 6 | class Verify_LL_1(unittest.TestCase): 7 | 8 | def setUp(self): 9 | terminals.init() 10 | nonterminals.init() 11 | langoids.init() 12 | dragonsets.init() 13 | pass 14 | 15 | def tearDown(self): 16 | pass 17 | 18 | # Dragon Spell: 4.4 Construction of a predictive parsing table 19 | def test_make_table(self): 20 | from collections import defaultdict 21 | from Skoarcery.dragonsets import FIRST, FOLLOW 22 | from Skoarcery.terminals import Empty, EOF 23 | 24 | # M[ Nonterm, Term ] = Production 25 | M = defaultdict(dict) 26 | 27 | duplicates = 0 28 | # (1) For each production A -> alpha 29 | # 30 | print("for each production P = A -> alpha:") 31 | for A in nonterminals.nonterminals.values(): 32 | M[A] = [] 33 | for P in A.production_rules: 34 | 35 | alpha = P.production 36 | print("\n P = " + str(P)) 37 | 38 | # 39 | # (2) 40 | # 41 | print(" for a in FIRST(alpha):") 42 | for a in FIRST(alpha): 43 | 44 | if a != Empty: 45 | X = M[A, a] 46 | 47 | if X: 48 | print("") 49 | print(" #### Grammar is not LL(1). Whoopsiedaisies. ####-----------------------") 50 | print("") 51 | print(" M[{}, {}]:".format(A.name, a.name)) 52 | print(" " + str(X)) 53 | print(" " + str(P)) 54 | print("") 55 | 56 | #print("X = {}\nP = {}\nA = {}\na = {}".format(str(X), str(P), str(A), str(a))) 57 | duplicates += 1 58 | 59 | print(" M[A,a] = M[{}, {}] = P".format(A.name, a.name)) 60 | M[A, a] = P 61 | 62 | # (3) 63 | else: 64 | 65 | print(" , so for b in FOLLOW(A):") 66 | for b in FOLLOW(A): 67 | X = M[A, b] 68 | 69 | if X: 70 | 71 | print("") 72 | print(" #### Grammar is not LL(1). Whoopsiedaisies. ####-----------------------") 73 | print("") 74 | print(" M[{}, {}]:".format(A.name, b.name)) 75 | print(" " + str(X)) 76 | print(" " + str(P)) 77 | print("") 78 | 79 | #print("X = {}\nP = {}\nA = {}\nb = {}".format(str(X), str(P), str(A), str(b))) 80 | #raise AssertionError("3) Grammar is not LL(1). Fuck.") 81 | duplicates += 1 82 | 83 | print(" M[A,b] = M[{}, {}] = P".format(A.name, b.name)) 84 | M[A, b] = P 85 | 86 | self.assertTrue(duplicates is 0, str(duplicates) + " duplicate entries: Grammar is not LL(1).") 87 | -------------------------------------------------------------------------------- /Skoarcery/laboaratoary/TestTerminals.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from Skoarcery import dragonsets, terminals, nonterminals 3 | 4 | 5 | class TestTokens(unittest.TestCase): 6 | 7 | def setUp(self): 8 | terminals.init() 9 | nonterminals.init() 10 | 11 | def tearDown(self): 12 | pass 13 | 14 | def tes_input(self): 15 | print("\n\n ==========--------( Tokens: Input )--------------------------------------------------========\n\n") 16 | print(terminals.src) 17 | 18 | def test_sorted(self): 19 | print("\n\n ==========--------( Tokens: Created )--------------------------------------------------========\n\n") 20 | L = terminals.list_of_names 21 | 22 | L.sort() 23 | 24 | i = 0 25 | for T in L: 26 | i += 1 27 | print("{:>16}".format(T), end=('\n' if ((i % 7) == 0) else ' ')) 28 | 29 | print("\n") 30 | 31 | def test_untoked(self): 32 | T = terminals.tokens 33 | N = nonterminals.nonterminals 34 | 35 | unused = [] 36 | 37 | skip = [terminals.Empty, terminals.EOF, terminals.Whitespace] 38 | 39 | for t in T.values(): 40 | 41 | if t in skip: 42 | continue 43 | 44 | uses = [] 45 | for n in N.values(): 46 | uses.extend([p for p in n.production_rules if t in p.production]) 47 | 48 | if len(uses) is 0: 49 | unused.append(t.name) 50 | 51 | if unused: 52 | print("-------( Untoked ) ------------\n") 53 | for untoked in unused: 54 | print(untoked) 55 | print("") 56 | 57 | self.fail("Untoked tokens: " + str(len(unused))) 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /Skoarcery/laboaratoary/Test_Sclang.py: -------------------------------------------------------------------------------- 1 | 2 | import unittest 3 | from subprocess import Popen, PIPE 4 | import subprocess 5 | import json 6 | 7 | 8 | class Test_Sclang(unittest.TestCase): 9 | 10 | #home = "/p/supercollider/build/Install/SuperCollider/SuperCollider.app/Contents/Resources/" 11 | #home = "C:\\supercollider\\SuperCollider\\" 12 | #home = "C:\\Users\\lucas\\Documents\\GitHub\\supercollider\\build\\x64\\Release\\SuperCollider\\" 13 | home = "C:\\Users\\lucas\\Documents\\GitHub\\bagong.supercollider\\build_pa\\Install\\SuperCollider\\" 14 | 15 | #sclang = home + "sclang" 16 | sclang = home + "sclang.exe" 17 | 18 | def print(self, msg): 19 | print("sclang: " + msg, end="") 20 | 21 | def exec(self, scd_code_file=None): 22 | 23 | class_lib_compiled = False 24 | class_lib_inited = False 25 | error_seen = False 26 | 27 | a_cmd = [Test_Sclang.sclang, "-D"] 28 | 29 | if scd_code_file: 30 | a_cmd.append(scd_code_file) 31 | 32 | 33 | proc = Popen(a_cmd, stdout=PIPE, stderr=subprocess.STDOUT) 34 | while proc.poll() is None: 35 | b = proc.stdout.readline() 36 | line = str(b, encoding="utf-8") 37 | self.print(line) 38 | 39 | # 40 | # yay 41 | if line.startswith("Class tree inited in"): 42 | class_lib_inited = True 43 | 44 | if line.startswith("compile done"): 45 | class_lib_compiled = True 46 | 47 | # 48 | # nay 49 | if line.startswith("-----------------------------------"): 50 | error_seen = True 51 | break 52 | 53 | # 54 | # complete 55 | if line.find("Welcome to SuperCollider") != -1: 56 | break 57 | 58 | self.assertFalse(error_seen, "Errors compiling class library.") 59 | self.assertTrue(class_lib_compiled, "Class library didn't compile.") 60 | self.assertTrue(class_lib_inited, "Class libarary did initialize.") 61 | 62 | failures = [] 63 | tests_passed = False 64 | while proc.poll() is None: 65 | b = proc.stdout.readline() 66 | line = str(b, encoding="utf-8") 67 | self.print(line) 68 | 69 | # 70 | # yay 71 | if line.startswith("SKOAR PASS"): 72 | tests_passed = True 73 | break 74 | 75 | # 76 | # nay 77 | if line.startswith("SKOAR FAIL"): 78 | tests_passed = False 79 | failures.append(line) 80 | break 81 | 82 | if line.startswith("FAIL"): 83 | #tests_passed = False 84 | failures.append(line) 85 | break 86 | # 87 | # nay 88 | if line.startswith("^^ The preceding error dump"): 89 | tests_passed = False 90 | break 91 | 92 | try: 93 | proc.terminate() 94 | finally: 95 | proc.stdout.close() 96 | 97 | if not tests_passed: 98 | print("JSON: " + json.dumps({"test": scd_code_file, "failures": failures}, separators=(',', ': '))) 99 | #print(str(a_cmd)) 100 | #for line in failures: 101 | # self.print(line) 102 | 103 | self.assertTrue(tests_passed, "scland unit tests failed.") 104 | 105 | 106 | class Test_Sclang_Sanity(Test_Sclang): 107 | 108 | def test_SC_sanity(self): 109 | self.exec("SuperCollider/testing/sanity.scd") 110 | 111 | def test_SC_cats(self): 112 | self.exec("SuperCollider/testing/cats.scd") 113 | 114 | def test_SC_ops(self): 115 | self.exec("SuperCollider/testing/ops.scd") 116 | 117 | def test_SC_noaty(self): 118 | self.exec("SuperCollider/testing/noaty.scd") 119 | 120 | def test_SC_levels(self): 121 | self.exec("SuperCollider/testing/levels.scd") 122 | 123 | 124 | class Test_Sclang_Dev(Test_Sclang): 125 | def test_SC_ops_dev(self): 126 | self.exec("SuperCollider/testing/ops_dev.scd") 127 | 128 | def test_SC_dev(self): 129 | self.exec("SuperCollider/testing/dev.scd") 130 | 131 | def test_SC_increments(self): 132 | self.exec("SuperCollider/testing/increments.scd") 133 | -------------------------------------------------------------------------------- /Skoarcery/langoids.py: -------------------------------------------------------------------------------- 1 | 2 | def init(): 3 | print("langoids initialized.") 4 | 5 | 6 | class Production: 7 | 8 | def __init__(self, name, list_of_langoids): 9 | from Skoarcery.terminals import Empty 10 | 11 | self.name = name 12 | self.production = list_of_langoids 13 | self.derives_empty = self.first == Empty 14 | 15 | def __str__(self): 16 | s = self.name + " ->" 17 | 18 | for alpha in self.production: 19 | s += " " + alpha.name 20 | 21 | return s 22 | 23 | @property 24 | def first(self): 25 | return self.production[0] 26 | 27 | 28 | class Langoid: 29 | 30 | def __init__(self, name): 31 | self.name = name 32 | self.derives_empty = False 33 | 34 | def __hash__(self): 35 | return hash(self.name) 36 | 37 | def __eq__(self, other): 38 | return self.name == other.name 39 | 40 | def __str__(self): 41 | return self.name 42 | 43 | def __repr__(self): 44 | return self.name 45 | 46 | def __index__(self): 47 | return self.name 48 | 49 | 50 | class Terminal(Langoid): 51 | 52 | def __init__(self, name, regex): 53 | super().__init__(name) 54 | 55 | self.regex = regex 56 | 57 | if name == "": 58 | self.derives_empty = True 59 | 60 | def __str__(self): 61 | return "T_" + self.name 62 | 63 | @property 64 | def toker_name(self): 65 | return "Toke_" + self.name 66 | 67 | 68 | class Nonterminal(Langoid): 69 | 70 | def __init__(self, name): 71 | super().__init__(name) 72 | 73 | # list of productions 74 | self.production_rules = [] 75 | self.first = set() 76 | self.follow = set() 77 | self.derives_empty = False 78 | self.intermediate = False 79 | self.has_semantics = False 80 | 81 | def add_production(self, p): 82 | 83 | o = Production(self.name, p) 84 | 85 | if o.derives_empty: 86 | self.derives_empty = True 87 | 88 | self.production_rules.append(o) 89 | 90 | def __repr__(self): 91 | return "N_" + self.name 92 | 93 | 94 | -------------------------------------------------------------------------------- /Skoarcery/nonterminals.py: -------------------------------------------------------------------------------- 1 | src = """ 2 | # 3 | # Skoar Nonterminals 4 | # 5 | # like_this for nonterminals, LikeThis for terminals 6 | # 7 | # is the empty string 8 | # 9 | # + before a nonterminal indicates this is an intermediate step that can be 10 | # skipped in the constructed parse tree, it will not create a new skoarnode, 11 | # instead appending its noads to its parent's children list. 12 | 13 | 14 | skoar : branches 15 | +branches : branch branches | 16 | branch : optional_voice phrases Newline 17 | +optional_voice : Voice | 18 | 19 | +phrases : phrasey phrases | 20 | +phrasey : Comment | marker | Meter | expr | dal_goto | beat 21 | 22 | skoarpion : SkoarpionStart skrp_sig skrp_suffix 23 | skrp_sig : ArgSpec SkoarpionSep | SymbolName opt_arg_spec SkoarpionSep | 24 | opt_arg_spec : ArgSpec | 25 | skrp_suffix : skrp_lines SkoarpionEnd 26 | 27 | +skrp_lines : optional_voice phrases skrp_moar_lines 28 | +skrp_moar_lines : Newline skrp_lines | 29 | 30 | listy : ListS listy_suffix 31 | +listy_suffix : listy_entries ListE | ListE 32 | +listy_entries : expr moar_listy_entries 33 | +moar_listy_entries: ListSep listy_entries | Newline | 34 | 35 | marker : Segno | Fine | coda | Volta | Bars 36 | coda : Coda optional_al_coda 37 | optional_al_coda : AlCoda | 38 | dal_goto : DaCapo al_x | DalSegno al_x 39 | al_x : AlCoda | AlSegno | AlFine | 40 | 41 | beat : Crotchets | Quavers | Quarters | Eighths | Slash 42 | 43 | musical_keyword : dynamic | ottavas | musical_keyword_misc 44 | musical_keyword_misc : Rep | Portamento | Carrot 45 | ottavas : OctaveShift | OttavaA | OttavaB | QuindicesimaA | QuindicesimaB | Loco 46 | dynamic : DynPiano | DynForte | DynSFZ | DynFP 47 | 48 | nouny : cthulhu | cuts | conditional | loop | nouny_literal | musical_keyword | listy | deref | skoarpion 49 | +nouny_literal : UGen | Tuplet | Caesura | Freq | Int | Float | String | Choard | NamedNoat | Symbol | Fairy | HashLevel | False | True | Cat 50 | 51 | deref : Deref deref_prime 52 | +deref_prime : MsgNameWithArgs listy_suffix | MsgName 53 | 54 | expr : SymbolColon expr | msgable expr_prime 55 | expr_prime : assignment expr_prime | math expr_prime | boolean | times | 56 | 57 | times : Times 58 | boolean : BooleanOp expr 59 | boolean_expr : expr 60 | math* : MathOp msgable 61 | assignment : AssOp settable 62 | +settable : Caesura | Symbol | listy | Quarters | Eighths | Fairy 63 | 64 | msgable : nouny msg_chain_node 65 | +msg_chain_node : MsgOp msg msg_chain_node | 66 | msg : MsgNameWithArgs listy_suffix | MsgName | listy | loop 67 | 68 | cthulhu : LWing Semicolon cthulhu_prime 69 | +cthulhu_prime : boolean_expr Semicolon RWing | Nosey Semicolon RWing 70 | 71 | conditional : CondS cond_ifs CondE 72 | +cond_ifs : cond_if cond_ifs_suffix 73 | +cond_ifs_suffix : Newline cond_ifs | 74 | cond_if : optional_voice boolean_expr CondIf if_body cond_else 75 | +cond_else : CondIf if_body | 76 | 77 | if_body : phrases 78 | 79 | loop : LoopS loop_body loop_condition LoopE 80 | loop_body : phrases 81 | loop_condition : LoopSep boolean_expr | 82 | 83 | cuts : CutsS phrases CutsE 84 | 85 | """ 86 | 87 | 88 | SKOAR = None 89 | nonterminals = None 90 | 91 | 92 | def init(): 93 | global nonterminals, SKOAR 94 | nonterminals = dict() 95 | 96 | from Skoarcery import terminals 97 | from Skoarcery.langoids import Nonterminal 98 | 99 | # create and track as they appear 100 | def hello(name): 101 | 102 | try: 103 | xoid = nonterminals[name] 104 | except KeyError: 105 | xoid = Nonterminal(name) 106 | nonterminals[name] = xoid 107 | 108 | return xoid 109 | 110 | for bnf_line in src.split("\n"): 111 | if len(bnf_line) == 0 or bnf_line.lstrip().startswith("#"): 112 | continue 113 | 114 | #print(bnf_line) 115 | a = bnf_line.split(":") 116 | 117 | name = a[0].strip() 118 | 119 | if name.startswith("+"): 120 | name = name.lstrip("+") 121 | intermediate = True 122 | else: 123 | intermediate = False 124 | 125 | # i'm not using this, but feel like i ought to be 126 | if name.endswith("*"): 127 | name = name.rstrip("*") 128 | has_semantics = True 129 | else: 130 | has_semantics = False 131 | 132 | for production in a[1].split("|"): 133 | 134 | p = [] 135 | for langoid in production.split(): 136 | 137 | if len(langoid) == 0: 138 | continue 139 | 140 | toke = terminals.tokens.get(langoid) 141 | 142 | if toke: 143 | p.append(toke) 144 | else: 145 | 146 | if langoid[0].isupper(): 147 | raise Exception("Unknown token " + langoid) 148 | 149 | X = hello(langoid) 150 | 151 | p.append(X) 152 | 153 | X = hello(name) 154 | X.intermediate = intermediate 155 | X.has_semantics = has_semantics 156 | X.add_production(p) 157 | 158 | SKOAR = nonterminals["skoar"] 159 | 160 | print("nonterminals initialized.") 161 | -------------------------------------------------------------------------------- /Skoarcery/parsetable.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | from Skoarcery import langoids, terminals, nonterminals, dragonsets 3 | from Skoarcery.langoids import Terminal 4 | 5 | 6 | class Not_LL_1(Exception): 7 | pass 8 | 9 | M = None 10 | 11 | 12 | # 13 | # Dragon Spell: 4.4 Construction of a predictive parsing table 14 | # 15 | def init(): 16 | from collections import defaultdict 17 | from Skoarcery.dragonsets import FIRST, FOLLOW 18 | from Skoarcery.terminals import Empty, EOF 19 | 20 | global M 21 | 22 | # M[ Nonterm, Term ] = Production 23 | M = defaultdict(dict) 24 | 25 | # (1) For each production A -> alpha 26 | # 27 | for A in nonterminals.nonterminals.values(): 28 | 29 | for P in A.production_rules: 30 | 31 | alpha = P.production 32 | 33 | # (2) 34 | for a in FIRST(alpha): 35 | if a != Empty: 36 | X = M[A, a] 37 | 38 | if X: 39 | raise Not_LL_1 40 | 41 | M[A, a] = P 42 | 43 | # (3) 44 | else: 45 | for b in FOLLOW(A): 46 | 47 | X = M[A, b] 48 | 49 | if X: 50 | raise Not_LL_1 51 | 52 | M[A, b] = P 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /Skoarcery/terminals.py: -------------------------------------------------------------------------------- 1 | src = """ 2 | # 3 | # Skoar Tokes 4 | # 5 | # format (at very start of line): TokeName: regex 6 | # 7 | # If token carries information: TokeName*: regex 8 | # - be sure an inspector for TokeName exists 9 | # 10 | 11 | : unused 12 | EOF: unused 13 | Whitespace: [ \\t]* 14 | Newline: [\\n\\r][\\n\\r \\t]* 15 | 16 | True: yes|true 17 | False: no|false 18 | Cat: =\\^\\.\\^= 19 | 20 | Voice*: \\.(([a-zA-Z_][a-zA-Z0-9_]*)?|\\.+) 21 | 22 | Comment: <[?](.|[\\n\\r])*?[?]> 23 | 24 | # careful not to match ottavas ending in (ma,mb,va,vb), or steal from floats 25 | Int*: (-)?(0|[1-9][0-9]*)(?![0-9]*Hz|[mv][ab]|\\.[0-9]|/) 26 | Float*: (-)?(0|[1-9][0-9]*)\\.[0-9]+(?!Hz) 27 | 28 | Freq*: (0|[1-9][0-9]*)(\\.[0-9]+)?Hz 29 | 30 | Meter*: [1-9][0-9]*/[1-9][0-9]* 31 | 32 | ArgSpec: <[a-zA-Z]+(,[a-zA-Z]+)*> 33 | 34 | ListS: <(?![=?])|<(?=[=]\\^\\.) 35 | ListE: >(?![=]) 36 | ListSep: , 37 | 38 | # one ^ but don't eat ^^( which is cthulhu's left wing 39 | Carrot*: \\^(?!\\^[(]) 40 | LWing: \\^\\^[(] 41 | RWing: [)]\\^\\^ 42 | 43 | Tuplet*: /\\d+(:\\d+)?|(du|tri|quadru)plets?|(quin|sex|sep|oc)tuplets? 44 | Crotchets*: [}]+\\.? 45 | Quavers*: o+/\\.? 46 | 47 | Quarters*: \\.?[)]+(?:__?)?\\.? 48 | Eighths*: \\.?\\]+(?:__?)?\\.? 49 | 50 | Caesura: // 51 | Slash: /(?![/0-9]) 52 | 53 | HashLevel: \\[#*[ ]*\\] 54 | 55 | 56 | # we can't allow f for forte as f is a noat, so we allow 57 | # 58 | # forte fforte ffforte ff fff, but not f 59 | # 60 | # for consisentecy, piano, ppiano, pppiano work too. 61 | # 62 | # default velocity: 63 | # ppp (16), pp (32), p (48), mp (64), mf (80), f (96), ff (112), fff (127) 64 | 65 | DynPiano*: (m(ezzo)?p|p+)(iano)? 66 | DynForte*: m(ezzo)?f(orte)?|f+orte|ff+ 67 | DynSFZ: sfz 68 | DynFP: fp 69 | 70 | AssOp: =>|[+]>|->|[*]> 71 | MsgOp: \\.(?![)\\]]) 72 | MathOp: [+*\\-](?!>) 73 | 74 | NamedNoat*: (?:_?)(?:[a-g](?![ac-zA-Z_]))(#|b)? 75 | Choard*: ~*[ABCDEFG](?![.ce-ln-rt-zA-LN-Z]|a[l ])(#|b)?([Mm0-9]|sus|dim|aug|dom)*(/[A-G][#b]?)?~* 76 | 77 | BooleanOp*: ==|!=|<=|>=|and|or|xor 78 | CondS: [{][?][\\n]* 79 | CondIf: [?][?](?![}]) 80 | CondE: [?][}] 81 | Semicolon: ; 82 | 83 | CutsS: [{]=[\\n]* 84 | CutsE: =[}] 85 | 86 | LoopS: [{]:[\\n]* 87 | LoopE: :[}] 88 | LoopSep: ::[\\n]*(?![|]) 89 | 90 | Fairy: [$] 91 | 92 | # we do this, because skoaroids can follow skoaroids. 93 | MsgName*: [a-zA-Z_][a-zA-Z0-9_]*(?!<) 94 | MsgNameWithArgs*: [a-zA-Z_][a-zA-Z0-9_]*< 95 | 96 | Symbol*: [\\\\@][a-zA-Z0-9_][a-zA-Z0-9_]* 97 | SymbolName*: [a-zA-Z0-9_][a-zA-Z0-9_]* 98 | SymbolColon*: [a-zA-Z0-9_][a-zA-Z0-9_]*[ \\t]*:(?![:|}]) 99 | 100 | 101 | SkoarpionStart: [{]! 102 | SkoarpionEnd: ![}] 103 | SkoarpionSep: !! 104 | Deref: !(?![!}]|=) 105 | 106 | Nosey: , 107 | 108 | DaCapo: D\\.C\\.|Da Capo 109 | DalSegno: D\\.S\\.|Dal Segno 110 | Fine: fine 111 | Segno*: ,[Ss](?:egno)?`(?:[a-zA-Z_][a-zA-Z0-9_]*`)* 112 | Coda: \\([+]\\)(?:`(?:[a-zA-Z_][a-zA-Z0-9_]*`)*)? 113 | Rep*: %+ 114 | AlCoda: al(la)? coda 115 | AlSegno: al segno 116 | AlFine: al fine 117 | 118 | UGen: u[A-Z][A-Za-z0-9_]* 119 | OctaveShift*: ~+o|o~+ 120 | 121 | OttavaA: 8va|ottava (alta|sopra)|all' ottava 122 | OttavaB: 8vb|ottava (bassa|sotto) 123 | 124 | QuindicesimaA: 15ma|alla quindicesima 125 | QuindicesimaB: 15mb 126 | 127 | Portamento: port\\.? 128 | Loco: loco 129 | Volta*: \\[\\d+\\.\\] 130 | 131 | # TODO: deal with \" 132 | String*: \'[^']*\' 133 | 134 | Bars*: :?\\|+:? 135 | 136 | Times: [Tt]imes 137 | """ 138 | 139 | # 140 | # 141 | # 142 | 143 | list_of_names = None 144 | inspectables = None 145 | tokens = None 146 | Empty = None 147 | EOF = None 148 | Whitespace = None 149 | 150 | odd_balls = None 151 | 152 | 153 | def init(): 154 | from Skoarcery.langoids import Terminal 155 | global src, list_of_names, tokens, EOF, Empty, Whitespace, odd_balls, inspectables 156 | 157 | list_of_names = [] 158 | inspectables = [] 159 | tokens = dict() 160 | 161 | for token_line in src.split("\n"): 162 | 163 | token_line = token_line.strip() 164 | if len(token_line) > 0 and not token_line.startswith("#"): 165 | 166 | (token, v, regex) = token_line.partition(":") 167 | 168 | token = token.strip() 169 | regex = regex.strip() 170 | 171 | if token.endswith("*"): 172 | token = token.rstrip("*") 173 | inspectables.append(token) 174 | 175 | list_of_names.append(token) 176 | 177 | tokens[token] = Terminal(token, regex) 178 | 179 | #print("# tokens initialized.") 180 | 181 | Empty = Terminal("", None) 182 | EOF = Terminal("EOF", None) 183 | Whitespace = tokens["Whitespace"] 184 | 185 | odd_balls = {Empty, EOF, Whitespace} 186 | 187 | 188 | -------------------------------------------------------------------------------- /Skoarcery/underskoar.py: -------------------------------------------------------------------------------- 1 | from Skoarcery import terminals, emissions 2 | 3 | # underskoarcery :P 4 | _ = _____ = _________ = _____________ = _________________ = _____________________ = None 5 | 6 | # ------- 7 | # Symbols 8 | # ------- 9 | SkoarToke_ = "SkoarToke" 10 | lexeme_ = "lexeme" 11 | regex_ = "regex" 12 | size_ = "size" 13 | inspectable_ = "inspectable" 14 | burn_ = "burn" 15 | match_ = "match" 16 | buf_ = "buf" 17 | offs_ = "offs" 18 | toke_class_ = "toke_class" 19 | match_toke_ = "match_toke" 20 | s_ = "s" 21 | n_ = "n" 22 | SkoarError_ = "SkoarError" 23 | SubclassResponsibilityError_ = "SubclassResponsibilityError" 24 | 25 | 26 | # 27 | # configure schematics to output a language 28 | # implemented by one of the tongues in emissions 29 | def init(tongue): 30 | global _, _____, _________, _____________, _________________, _____________________ 31 | assert tongue in emissions.tongues 32 | _ = _____ = _________ = _____________ = _________________ = _____________________ = tongue 33 | 34 | 35 | def skoarToke(): 36 | 37 | regex = toke_class_ + "." + regex_ 38 | 39 | _.cmt_hdr("Abstract Token") 40 | 41 | _.abstract_class(SkoarToke_) 42 | 43 | _____.attrvar("<", lexeme_) 44 | _____.attrvar("", size_) 45 | 46 | _____.classvar("<", regex_, _.null) 47 | _____.nl() 48 | 49 | _____.constructor(s_, n_) 50 | _________.stmt(_.v_ass(_.v_attr(lexeme_), s_)) 51 | _________.stmt(_.v_ass(_.v_attr(size_), n_)) 52 | _____.end() 53 | 54 | _____.cmt("how many characters to burn from the buffer") 55 | _____.method(burn_) 56 | _________.return_(size_) 57 | _____.end() 58 | 59 | _____.cmt("override and return " + _.null + " for no match, new toke otherwise") 60 | _____.abstract_static_method(match_, buf_, offs_) 61 | _________.throw(SubclassResponsibilityError_, _.v_str("What are you doing human?")) 62 | _____.end() 63 | 64 | _____.cmt("match requested toke") 65 | _____.static_method(match_toke_, buf_, offs_, toke_class_) 66 | _________.var(match_) 67 | 68 | if isinstance(_, emissions.ScTongue): 69 | _________.find_regex(match_, regex, buf_, offs_) 70 | 71 | _________.if_(match_ + ".isNil") 72 | _____________.return_(_.null) 73 | _________.end_if() 74 | 75 | _________.return_(_.v_new(toke_class_, "match[0]", "match[1]")) 76 | 77 | else: 78 | _____.try_() 79 | _________.find_regex(match_, regex, buf_, offs_) 80 | 81 | _________.return_(_.v_new(toke_class_, _.v_regex_group_zero(match_))) 82 | 83 | _____.except_any() 84 | _________.nop() 85 | _____.end() 86 | 87 | _____.return_(_.null) 88 | 89 | _____.end() 90 | _.end() 91 | 92 | 93 | def whitespace_token(): 94 | 95 | Whitespace = terminals.Whitespace 96 | regex = _.v_def_regex(Whitespace.regex) 97 | 98 | _.cmt_hdr("Whitespace is special") 99 | _.class_(Whitespace.toker_name, SkoarToke_) 100 | _____.classvar("<", regex_, regex) 101 | _____.nl() 102 | _____.static_method(burn_, buf_, offs_) 103 | _________.var(match_) 104 | 105 | if isinstance(_, emissions.ScTongue): 106 | _________.find_regex(match_, Whitespace.toker_name + "." + regex_, buf_, offs_) 107 | _________.if_(match_ + " != " + _.null) 108 | _____________.return_("match[1]") 109 | _________.end_if() 110 | 111 | else: 112 | _____.try_() 113 | _________.find_regex(match_, Whitespace.toker_name + "." + regex_, buf_, offs_) 114 | _________.return_(_.v_length(_.v_regex_group_zero(match_))) 115 | _____.except_any() 116 | _________.nop() 117 | _____.end() 118 | 119 | _________.return_("0") 120 | _____.end() 121 | _.end() 122 | 123 | 124 | def EOF_token(): 125 | 126 | EOF = terminals.EOF 127 | 128 | _.cmt_hdr("EOF is special") 129 | _.class_(EOF.toker_name, SkoarToke_) 130 | _____.static_method(burn_, buf_, offs_) 131 | _________.if_(_.v_length(buf_) + " > " + offs_) 132 | _____________.throw(SkoarError_, _.v_str("Tried to burn EOF when there's more input.")) 133 | _________.end_if() 134 | _________.return_("0") 135 | _____.end() 136 | _____.static_method(match_, buf_, offs_) 137 | _________.if_(_.v_length(buf_) + " < " + offs_) 138 | _____________.throw(SkoarError_, _.v_str("Tried to burn EOF when there's more input.")) 139 | _________.end_if() 140 | _________.if_(_.v_length(buf_) + " == " + offs_) 141 | _____________.return_(_.v_new(EOF.toker_name, "")) 142 | _________.end_if() 143 | _________.return_(_.null) 144 | _____.end() 145 | _.end() 146 | 147 | 148 | def typical_token(token): 149 | 150 | #inspectable = _.true if token.name in terminals.inspectables else _.false 151 | 152 | _.class_(token.toker_name, SkoarToke_) 153 | _____.classvar("<", regex_, _.v_def_regex(token.regex)) 154 | #_____.classvar("<", inspectable_, inspectable) 155 | _____.nl() 156 | _____.static_method(match_, buf_, offs_) 157 | _________.return_(SkoarToke_ + "." + match_toke_ + "(" + buf_ + ", " + offs_ + ", " + token.toker_name + ")") 158 | _____.end() 159 | _.end() 160 | 161 | -------------------------------------------------------------------------------- /SuperCollider/Skoar/apparatus.sc: -------------------------------------------------------------------------------- 1 | // ========================== 2 | // The Parse Tree - SkoarNoad 3 | // ========================== 4 | SkoarNoad { 5 | 6 | var address; // a list code to find the noad quickly 7 | var <>parent; // the parent noad 8 | var <>children; // a list of child noads 9 | 10 | var <>name; // name of the nonterminal (a \symbol) 11 | var <>skoarpuscle; // skoarpuscle types go here 12 | var <>toke; 13 | 14 | var <>on_enter; 15 | var <>one_shots; // function to set for stuff that appFalse for one beat. 16 | 17 | var <>voice; // what voice to use 18 | var <>skoap; // what skoap are we in 19 | 20 | *new { 21 | | name, parent=nil | 22 | ^super.new.init(name, parent); 23 | } 24 | 25 | init { 26 | | nameArg, parentArg | 27 | 28 | parent = parentArg; 29 | name = nameArg; 30 | 31 | children = List[]; 32 | address = []; 33 | } 34 | 35 | asString { 36 | var ns = name.asString; 37 | 38 | if (skoarpuscle.notNil) { 39 | ns = ns ++ ": " ++ skoarpuscle.asString 40 | }; 41 | ^ns; 42 | } 43 | 44 | // here we return a copy, as whomever uses it is likely going to start 45 | // popping numbers off of it. 46 | address { 47 | ^Array.newFrom(address); 48 | } 49 | 50 | // ------------------- 51 | // decorating the tree 52 | // ------------------- 53 | decorate_zero { 54 | | v, s, parent_address, i=0 | 55 | 56 | if (voice.isNil) { 57 | voice = v; 58 | } { 59 | // the voice has changed, this is what the children get 60 | v = voice; 61 | }; 62 | 63 | address = []; 64 | skoap = s; 65 | 66 | i = 0; 67 | children.do { 68 | | y | 69 | y.decorate(v, s, address, i); 70 | i = i + 1; 71 | }; 72 | 73 | } 74 | 75 | decorate { 76 | | v, s, parent_address, i=0 | 77 | 78 | if (voice.isNil) { 79 | voice = v; 80 | } { 81 | // the voice has changed, this is what the children get 82 | v = voice; 83 | }; 84 | 85 | address = [i] ++ parent_address; 86 | skoap = s; 87 | 88 | i = 0; 89 | children.do { 90 | | y | 91 | y.decorate(v, s, address, i); 92 | i = i + 1; 93 | }; 94 | 95 | } 96 | 97 | // ---------------- 98 | // growing the tree 99 | // ---------------- 100 | add_noad { 101 | | noad | 102 | children = children.add(noad); 103 | } 104 | 105 | add_toke { 106 | | name, t | 107 | var x = SkoarNoad(t.class.name, this); 108 | x.toke = t; 109 | children = children.add(x); 110 | } 111 | 112 | // ---------------- 113 | // showing the tree 114 | // ---------------- 115 | draw_tree { 116 | | tab = 1 | 117 | var n = 16; 118 | var s; 119 | var sa = skoap.asString ++ ":"; 120 | var sv; 121 | 122 | address.reverseDo { 123 | | x | 124 | sa = sa ++ x.asString ++ ";"; 125 | }; 126 | 127 | sv = if (voice.notNil) { 128 | voice.name.asString.padLeft(n) ++ ":" 129 | } { 130 | ":".padLeft(n+1) 131 | }; 132 | 133 | s = sa.padRight(n) ++ sv ++ " ".padLeft(tab) ++ name; 134 | 135 | if (skoarpuscle.notNil) { 136 | s = s ++ ": " ++ skoarpuscle.val; 137 | }; 138 | 139 | s = s ++ "\n"; 140 | children.do { 141 | | x | 142 | s = if (x.isKindOf(SkoarNoad)) { 143 | s ++ x.draw_tree(tab + 1) 144 | } { 145 | s ++ " ".padLeft(tab + 1) ++ x.class.asString ++ "\n" 146 | }; 147 | }; 148 | 149 | ^s; 150 | } 151 | 152 | // ----------------- 153 | // climbing the Tree 154 | // ----------------- 155 | 156 | // depth-first, find the leaves, run handler, working towards trunk 157 | // 158 | // if it's crashing during the decorating stage, here's a good place to 159 | // start debugging 160 | depth_visit { 161 | | f | 162 | //var s = " " ++ if (toke.notNil) {toke.lexeme} {""}; 163 | //debug(">>> depth_visit: " ++ name ++ s); 164 | 165 | children.do { 166 | | y | 167 | y.depth_visit(f); 168 | }; 169 | 170 | //debug("--- depth_visit: " ++ name ++ s); 171 | 172 | // note: leaves first 173 | f.(this); 174 | 175 | //debug("<<< depth_visit: " ++ name ++ s); 176 | } 177 | 178 | inorder { 179 | | f | 180 | 181 | //debug(">>> inorder: " ++ name); 182 | 183 | f.(this); 184 | 185 | children.do { 186 | | y | 187 | y.inorder(f); 188 | }; 189 | 190 | //debug("<<< inorder: " ++ name); 191 | } 192 | 193 | // debug here if it's crashing while performing the skoar 194 | inorder_from_here { 195 | | here, f | 196 | var j = here.pop; 197 | var n = children.size - 1; 198 | 199 | //debug("inorder_from_here: j:" ++ j ++ " " ++ name); 200 | 201 | if (j.isNil) { 202 | this.inorder(f); 203 | } { 204 | children[j].inorder_from_here(here, f); 205 | 206 | j = j + 1; 207 | if (j <= n) { 208 | for (j, n, { 209 | | k | 210 | children[k].inorder(f); 211 | }); 212 | }; 213 | }; 214 | } 215 | 216 | // expect skoarpuscle 217 | next_skoarpuscle { 218 | var x; 219 | 220 | if (skoarpuscle.notNil) { 221 | ^skoarpuscle; 222 | }; 223 | 224 | x = children[0]; 225 | 226 | if (x.notNil) { 227 | ^x.next_skoarpuscle; 228 | }; 229 | 230 | ^nil; 231 | } 232 | 233 | next_toke { 234 | var x; 235 | 236 | if (toke.notNil) { 237 | ^toke; 238 | }; 239 | 240 | x = children[0]; 241 | 242 | if (x.notNil) { 243 | ^x.next_toke; 244 | }; 245 | 246 | ^nil; 247 | } 248 | 249 | // ------------------- 250 | // performing the tree 251 | // ------------------- 252 | enter_noad { 253 | | minstrel, nav | 254 | 255 | if (on_enter.notNil) { 256 | on_enter.(minstrel, nav); 257 | }; 258 | 259 | if (skoarpuscle.notNil and: skoarpuscle.respondsTo(\on_enter)) { 260 | skoarpuscle.on_enter(minstrel, nav); 261 | }; 262 | } 263 | 264 | // ------------------ 265 | // searching the tree 266 | // ------------------ 267 | 268 | // desires - array of names of noads as symbol, or SkoarToke implementation classes 269 | // writer - a function that will do something with the matches 270 | match { 271 | | desires, writer | 272 | 273 | desires.do { 274 | | item | 275 | 276 | if (item == name) { 277 | writer.(this); 278 | }; 279 | }; 280 | } 281 | 282 | collect { 283 | | desires | 284 | 285 | var results = List.new; 286 | 287 | this.depth_visit({ 288 | | x | 289 | x.match(desires, { 290 | | y | 291 | results.add(y); 292 | }); 293 | }); 294 | 295 | ^results.asArray; 296 | } 297 | 298 | collect_skoarpuscles { 299 | | j=0 | 300 | 301 | var results = List.new; 302 | while {j < children.size} { 303 | 304 | children[j].inorder({ 305 | | x | 306 | if (x.skoarpuscle.notNil) { 307 | //debug("found skoarpuscle: " ++ x.skoarpuscle.asString); 308 | results.add(x.skoarpuscle); 309 | }; 310 | }); 311 | 312 | j = j + 1; 313 | }; 314 | ^results.asArray; 315 | 316 | } 317 | 318 | } 319 | 320 | 321 | 322 | -------------------------------------------------------------------------------- /SuperCollider/Skoar/beaty.sc: -------------------------------------------------------------------------------- 1 | 2 | SkoarpuscleBeat : Skoarpuscle { 3 | 4 | var " 30 | 31 | all_voice = skr.all_voice; 32 | 33 | skoarpion = skoar.tree.next_skoarpuscle.val; 34 | 35 | event_stream = Routine({ 36 | var running = true; 37 | var nav_result = nil; 38 | 39 | while {running} { 40 | 41 | nav_result = block { 42 | | nav | 43 | koar.do_skoarpion(skoarpion, this, nav, nil, nil); 44 | nav.(\nav_done); 45 | }; 46 | 47 | switch (nav_result) 48 | 49 | {\nav_done} { running = false; } 50 | {\nav_fine} { running = false; } 51 | 52 | {\nav_da_capo} { 53 | //"Da Capo time.".postln; 54 | // do nothing, will enter skoarpion again 55 | } 56 | 57 | {\nav_colon} { 58 | // do nothing, will enter skoarpion again 59 | } 60 | 61 | { 62 | SkoarError("Unhandled nav: " ++ nav_result).throw; 63 | }; 64 | 65 | }; 66 | 67 | //("Minstrel " ++ koar.name ++ " done.").postln; 68 | }); 69 | 70 | } 71 | 72 | nextEvent { 73 | ^event_stream.next; 74 | } 75 | 76 | pfunk { 77 | ^Pfunc({this.nextEvent;}); 78 | } 79 | 80 | reset_colons { 81 | fairy.forget_that_you_have_seen(SkoarpuscleBars); 82 | koar.state_put(\colons_burned, Dictionary.new;); 83 | } 84 | 85 | } 86 | 87 | // ---------------------------------- 88 | // Skoarchestra - A band of minstrels 89 | // ---------------------------------- 90 | Skoarchestra { 91 | 92 | var minstrels; 93 | 94 | *new { 95 | | skoar | 96 | ^super.new.init(skoar); 97 | } 98 | 99 | init { 100 | | skoar | 101 | minstrels = List.new; 102 | 103 | if (skoar.voices.size == 1) { 104 | minstrels.add(SkoarMinstrel.new(\all, skoar.all_voice, skoar)); 105 | } { 106 | skoar.voices.do { 107 | | v | 108 | if (v != skoar.all_voice) { 109 | minstrels.add(SkoarMinstrel.new(v.name, v, skoar)); 110 | }; 111 | }; 112 | }; 113 | } 114 | 115 | eventStream { 116 | var funkStreams = List.new; 117 | 118 | minstrels.do { 119 | | m | 120 | funkStreams.add(m.pfunk); 121 | }; 122 | 123 | ^Ppar.new(funkStreams).asStream; 124 | } 125 | 126 | pfunk { 127 | var x = this.eventStream; 128 | 129 | ^Pfunc({x.next;}); 130 | } 131 | 132 | } 133 | -------------------------------------------------------------------------------- /SuperCollider/Skoar/pitchy.sc: -------------------------------------------------------------------------------- 1 | // ------------------- 2 | // Pitchy Skoarpuscles 3 | // ------------------- 4 | SkoarpuscleKey : Skoarpuscle { 5 | 6 | var 0) { 19 | var x = a[0]; 20 | 21 | if (x.isKindOf(SkoarpuscleChoard)) { 22 | choard = x; 23 | }; 24 | 25 | if (a.size > 1) { 26 | var y = a[1]; 27 | if (y.isKindOf(SkoarpuscleSymbol)) { 28 | scale_name = y.val; 29 | }; 30 | }; 31 | 32 | }; 33 | 34 | 35 | }; 36 | 37 | if (choard.isKindOf(SkoarpuscleChoard)) { 38 | var minor; 39 | 40 | root = switch (choard.letter) 41 | {"C"} {0} 42 | {"D"} {2} 43 | {"E"} {4} 44 | {"F"} {5} 45 | {"G"} {7} 46 | {"A"} {-1} 47 | {"B"} {-3} + choard.sharps; 48 | 49 | minor = choard.lexeme.findRegexp("m")[0]; 50 | 51 | if (minor.notNil and: scale_name.isNil) { 52 | scale_name = \minor; 53 | }; 54 | 55 | }; 56 | 57 | if (scale_name.isNil) { 58 | scale_name = \major; 59 | }; 60 | scale = Scale.all[scale_name]; 61 | } 62 | 63 | apply { 64 | | event | 65 | 66 | event[\scale] = scale; 67 | event[\root] = root; 68 | 69 | ^event; 70 | } 71 | } 72 | 73 | SkoarpuscleNoat : Skoarpuscle { 74 | 75 | var " 84 | var s = lex; 85 | var r = s.findRegexp(noat_regex); 86 | var x = -1; 87 | var letter; 88 | 89 | lexeme = lex; 90 | 91 | low = r[1][1] != ""; 92 | letter = r[2][1]; 93 | 94 | r = s.findRegexp(sharps_regex); 95 | s = r[1][1]; 96 | 97 | if (s.beginsWith("#")) { 98 | x = 1; 99 | }; 100 | 101 | sharps = s.size * x; 102 | 103 | x = switch (letter) 104 | {"c"} {0} 105 | {"d"} {2} 106 | {"e"} {4} 107 | {"f"} {5} 108 | {"g"} {7} 109 | {"a"} {9} 110 | {"b"} {11}; 111 | 112 | case {sharps > 0} { 113 | x = x + 1; 114 | } {sharps < 0} { 115 | x = x - 1; 116 | }; 117 | 118 | if (low == false) { 119 | x = x + 12; 120 | }; 121 | 122 | val = x; 123 | } 124 | 125 | flatten {^val;} 126 | 127 | isNoatworthy { ^true; } 128 | 129 | asNoat { 130 | ^SkoarNoat_Note(val); 131 | } 132 | 133 | asString { 134 | ^lexeme; 135 | } 136 | 137 | asSymbol { 138 | ^lexeme.asSymbol; 139 | } 140 | 141 | raiseBy { 142 | | x | 143 | ("should raise " ++ lexeme ++ " by " ++ x).postln; 144 | } 145 | 146 | on_enter { 147 | | m, nav | 148 | m.fairy.impress(this); 149 | } 150 | 151 | } 152 | 153 | 154 | SkoarpuscleChoard : Skoarpuscle { 155 | 156 | var 0} { 193 | x = sharps + x; 194 | } {sharps < 0} { 195 | x = x - sharps; 196 | }; 197 | 198 | first = x; 199 | third = x + 4; 200 | fifth = x + 7; 201 | 202 | if (lex.findRegexp("[^i]m").size != 0) { 203 | third = third - 1; 204 | }; 205 | 206 | if (lex.findRegexp("sus2").size != 0) { 207 | third = third - 2; 208 | }; 209 | 210 | if (lex.findRegexp("sus4").size != 0) { 211 | third = third + 1; 212 | }; 213 | 214 | if (lex.findRegexp("dim").size != 0) { 215 | third = third - 1; 216 | fifth = fifth - 1; 217 | }; 218 | 219 | if (lex.findRegexp("aug").size != 0) { 220 | fifth = fifth + 1 221 | }; 222 | 223 | val = [first, third, fifth]; 224 | 225 | if (lex.findRegexp("M7").size != 0) { 226 | val = val.add(first + 11); 227 | } { 228 | if (lex.findRegexp("7").size != 0) { 229 | val = val.add(first + 10); 230 | } 231 | }; 232 | 233 | if (lex.findRegexp("aug6").size != 0) { 234 | val = val.add(fifth + 1); // fifth has already been incremented 235 | }; 236 | 237 | } 238 | 239 | asString { 240 | ^lexeme; 241 | } 242 | 243 | asSymbol { 244 | ^lexeme.asSymbol; 245 | } 246 | 247 | raiseBy { 248 | | x | 249 | ("should raise " ++ lexeme ++ " by " ++ x).postln; 250 | } 251 | 252 | flatten {^lexeme;} 253 | 254 | on_enter { 255 | | m, nav | 256 | m.fairy.impress(this); 257 | } 258 | 259 | isNoatworthy { ^true; } 260 | 261 | asNoat { 262 | ^this; 263 | } 264 | 265 | execute { 266 | | minstrel | 267 | //"SkoarNoat.execute: ".post; key.post; val.postln; 268 | minstrel.koar[\choard] = val; 269 | } 270 | } 271 | 272 | SkoarNoat { 273 | var >> parsing skoar...".postln; 47 | tree = parser.skoar(nil); 48 | 49 | try { 50 | toker.eof; 51 | } { 52 | | e | 53 | e.postln; 54 | toker.dump; 55 | e.throw; 56 | }; 57 | 58 | parse_time = (Process.elapsedTime - start_time).round(0.01); 59 | 60 | //"---< Undecorated Skoar Tree >---".postln; tree.draw_tree.postln; 61 | //"<<< tree created, now decorating...".postln; 62 | 63 | this.decorate; 64 | decorate_time = (Process.elapsedTime - start_time - parse_time).round(0.01); 65 | 66 | //this.draw_skoarpions; 67 | 68 | debug("Skoar parsed in " ++ parse_time ++ " seconds, decorated in " 69 | ++ decorate_time ++ ". Total: " ++ (parse_time + decorate_time) ++ " sec."); 70 | 71 | 72 | } 73 | 74 | decorate { 75 | 76 | var inspector = SkoarTokeInspector.new; 77 | var skoarmantics = Skoarmantics.new; 78 | 79 | var f = { 80 | | noad | 81 | var t = noad.toke; 82 | 83 | if (t.notNil) { 84 | var g = inspector[t.class.asSymbol]; 85 | 86 | if (g.isKindOf(Function)) { 87 | g.(this, noad, t); 88 | }; 89 | } { 90 | var g = skoarmantics[noad.name]; 91 | 92 | if (g.isKindOf(Function)) { 93 | g.(this, noad); 94 | }; 95 | }; 96 | }; 97 | 98 | tree.depth_visit(f); 99 | } 100 | 101 | // ---- 102 | // misc 103 | // ---- 104 | 105 | // creates a new one if needed 106 | get_voice { 107 | | k | 108 | 109 | var voice = nil; 110 | 111 | if (voices.includesKey(k)) { 112 | voice = voices[k]; 113 | } { 114 | voice = SkoarKoar(this, k); 115 | voices[k] = voice; 116 | }; 117 | 118 | ^voice; 119 | 120 | } 121 | 122 | cthulhu { 123 | | noad | 124 | 125 | // TODO more 126 | "^^(;,;)^^".postln; 127 | 128 | this.dump; 129 | 130 | "".postln; 131 | SkoarError("^^(;,;)^^").throw; 132 | 133 | } 134 | 135 | play { 136 | this.pskoar.play; 137 | } 138 | 139 | pskoar { 140 | ^Skoarchestra.new(this).pfunk; 141 | } 142 | 143 | pvoice { 144 | | voice_name | 145 | ^SkoarMinstrel.new(this.tree, voices[voice_name], this).pfunk; 146 | } 147 | 148 | json { 149 | var pf = Skoarchestra.new(this).pfunk; 150 | 151 | "[".postln; 152 | pf.do({ 153 | | event | 154 | " { ".post; 155 | //event.play; 156 | 157 | event.keysValuesDo({ 158 | | key, value | 159 | ("'" ++ key ++ "':'").post; 160 | value.printOn(Post,2000); 161 | "', ".post; 162 | }); 163 | "}, ".postln; 164 | }); 165 | "]".postln; 166 | 167 | } 168 | 169 | draw_skoarpions { 170 | skoarpions.do { 171 | | x | 172 | x.post_tree; 173 | 174 | "Projections: ".postln; 175 | voices.keysDo { 176 | | koar_name | 177 | var projection = x.projection(koar_name); 178 | 179 | projection.block.draw_tree.postln; 180 | }; 181 | }; 182 | } 183 | } 184 | 185 | 186 | +String { 187 | skoar { 188 | ^Skoar(this); 189 | } 190 | 191 | pskoar { 192 | ^this.skoar.pskoar; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /SuperCollider/Skoar/skoarpions.sc: -------------------------------------------------------------------------------- 1 | Skoarpion { 2 | 3 | var skoar; 4 | var ---"); 172 | 173 | if (arg_spec.notNil) { 174 | "arg_spec: ".post; arg_spec.postln; 175 | 176 | arg_spec.val.do { 177 | | x | 178 | if (x.isKindOf(Skoarpuscle)) { 179 | x.val.post; " ".post; 180 | } { 181 | x.post; " ".post; 182 | }; 183 | }; 184 | "".postln; 185 | }; 186 | 187 | if (body.notNil) { 188 | "body:".postln; 189 | body.draw_tree.post; 190 | }; 191 | 192 | "".postln; 193 | } 194 | } 195 | 196 | SkoarIteratoar { 197 | var arr; 198 | var <>i; 199 | var <>n; 200 | 201 | init_iter { 202 | | a | 203 | arr = a; 204 | n = a.size; 205 | i = -1; 206 | } 207 | 208 | // this is returning noads 209 | selector { 210 | | f | 211 | i = f.value % n; 212 | ^arr[i]; 213 | } 214 | 215 | at { 216 | | j | 217 | ^this.selector({j}); 218 | } 219 | 220 | choose { 221 | ^this.selector({n.rand}); 222 | } 223 | 224 | wchoose { 225 | | weights | 226 | ^this.selector({weights.val.windex}); 227 | } 228 | 229 | next { 230 | ^this.selector({1 + i}); 231 | } 232 | 233 | last { 234 | ^this.selector({i - 1}); 235 | } 236 | } 237 | 238 | SkoarpionProjection : SkoarIteratoar { 239 | 240 | var body; 241 | var proj; 242 | var 0) { 266 | skip_to[addr[m-1]] = i; 267 | }; 268 | 269 | // don't use add_noad, it corrupts noad. 270 | proj.children.add(x); 271 | proj.skoap = x.skoap; 272 | }; 273 | }; 274 | 275 | this.init_iter(proj.children); 276 | } 277 | 278 | block { 279 | ^proj; 280 | } 281 | 282 | inline { 283 | ^proj; 284 | } 285 | 286 | map_dst { 287 | | dst | 288 | var addr = dst.address.copyToEnd(0); 289 | var j = addr.pop; 290 | 291 | if (j.isNil) { 292 | ^addr; 293 | }; 294 | 295 | ^(addr ++ skip_to[j]); 296 | } 297 | 298 | } 299 | -------------------------------------------------------------------------------- /SuperCollider/Skoar/toker.sc: -------------------------------------------------------------------------------- 1 | 2 | // ========= 3 | // The Toker 4 | // ========= 5 | 6 | Toker { 7 | var skoarse; 8 | var i_am_here; 9 | var i_saw; 10 | 11 | *new { 12 | | code | 13 | ^super.new.init( code ); 14 | } 15 | 16 | init { 17 | | code | 18 | skoarse = code; 19 | i_am_here = 0; 20 | i_saw = nil; 21 | } 22 | 23 | see { 24 | | want | 25 | 26 | if (i_saw.notNil) { 27 | if (i_saw.isKindOf(want)) { 28 | ^i_saw 29 | } 30 | } { 31 | i_saw = want.match(skoarse, i_am_here); 32 | ^i_saw; 33 | } 34 | 35 | ^nil; 36 | } 37 | 38 | sees { 39 | | wants | 40 | 41 | i_am_here = i_am_here + Toke_Whitespace.burn(skoarse, i_am_here); 42 | 43 | wants.do { 44 | | want | 45 | var x = this.see(want); 46 | 47 | if (x.notNil) { 48 | ^x; 49 | }; 50 | }; 51 | 52 | ^nil; 53 | } 54 | 55 | burn { 56 | | want | 57 | 58 | var toke = i_saw; 59 | var msg; 60 | 61 | if (toke.isNil) { 62 | toke = this.see(want); 63 | }; 64 | 65 | toke.isKindOf(want) and: { 66 | i_saw = nil; 67 | i_am_here = i_am_here + toke.burn; 68 | i_am_here = i_am_here + Toke_Whitespace.burn(skoarse, i_am_here); 69 | ^toke; 70 | }; 71 | 72 | msg = "Tried to burn " ++ want.asString ++ ", but saw " ++ toke.asString; 73 | 74 | "Toker Fail.".postln; 75 | msg.postln; 76 | this.dump; 77 | 78 | SkoarParseException(msg).throw; 79 | } 80 | 81 | eof { 82 | Toke_EOF.burn(skoarse, i_am_here); 83 | } 84 | 85 | dump { 86 | ("\nToker Dump" ++ 87 | "\nhere : " ++ i_am_here.asString ++ 88 | "\nsaw : " ++ i_saw.asString ++ 89 | "\nskoarse: " ++ skoarse.copyRange(0,i_am_here) 90 | ++ "_$_" ++ skoarse.copyRange(i_am_here, skoarse.size)).postln; 91 | } 92 | 93 | } 94 | -------------------------------------------------------------------------------- /SuperCollider/Testing/cats.scd: -------------------------------------------------------------------------------- 1 | 2 | var qrt = (\dur:1); 3 | var eth = (\dur:1/2); 4 | var sxt = (\dur:1/4); 5 | 6 | SkoarTestRunner(( 7 | 8 | cats_eat_values: [ 9 | "2 => @two ) =^.^= => @two ) < =^.^= > => @two )", 10 | [(\two:2),(\two:inf),(\two:[nil])] 11 | ], 12 | 13 | cats_regex_ambiguity: [ 14 | "<=^.^=,=^.^=> => @foo )", 15 | [(\foo:[nil,nil])] 16 | ], 17 | 18 | cats_are_cats: [ 19 | "{? =^.^= == =^.^= ?? 3 ?? 2 ?} => @foo )", 20 | [(\foo:3)] 21 | ], 22 | 23 | cats_are_false: [ 24 | "{? =^.^= ?? 3 ?? 2 ?} => @foo )", 25 | [(\foo:2)] 26 | ], 27 | 28 | cats_nonexistant_variable: [ 29 | "{? !x == =^.^= ?? 3 ?? 2 ?} => @foo )", 30 | [(\foo:3)] 31 | ], 32 | 33 | cats_nonexistant_variable_two: [ 34 | "{? !x ?? 3 ?? 2 ?} => @foo )", 35 | [(\foo:2)] 36 | ], 37 | 38 | cats_missing_args: [ 39 | "{! bar !! {? !x ?? 3 ?? 2 ?} !} !bar => @foo )", 40 | [(\foo:2)] 41 | ], 42 | 43 | )); 44 | -------------------------------------------------------------------------------- /SuperCollider/Testing/dev.scd: -------------------------------------------------------------------------------- 1 | 2 | var qrt = (\dur:1); 3 | var eth = (\dur:1/2); 4 | 5 | SkoarTestRunner(( 6 | 7 | da_capo_a: [ 8 | ") ) ) fine ] ] D.C. al fine", 9 | [ 10 | qrt, qrt, qrt, eth, eth, 11 | qrt, qrt, qrt 12 | ] 13 | ], 14 | 15 | da_capo_b: [ 16 | ") ) ) |: ] ] :| fine D.C. al fine", 17 | [ 18 | qrt, qrt, qrt, eth, eth, eth, eth, 19 | qrt, qrt, qrt, eth, eth, eth, eth 20 | ] 21 | ], 22 | 23 | // next is unimplemented 24 | listy_f: [ 25 | "<3,4> => @x <0, !x.next, !x.next, 2> => @food )", 26 | [( 'dur': 1.0, 'food': [ 0, 3, 4, 2 ], 'x':[3, 4] )] 27 | ], 28 | 29 | // right now it's popping the skoar off, and forgetting that it has seen the colon 30 | colons_unbalanced: [ 31 | "| ) ) ) :| ] ] :|", 32 | [ 33 | qrt, qrt, qrt, 34 | qrt, qrt, qrt, eth, eth, 35 | qrt, qrt, qrt, eth, eth, 36 | ] 37 | ], 38 | 39 | argspec_ambiguity: [ 40 | "{! ) !}", 41 | [qrt] 42 | ], 43 | 44 | )); 45 | -------------------------------------------------------------------------------- /SuperCollider/Testing/increments.scd: -------------------------------------------------------------------------------- 1 | 2 | var qrt = (\dur:1); 3 | var eth = (\dur:1/2); 4 | 5 | SkoarTestRunner(( 6 | 7 | incr_int: [ 8 | "1 => @x ) 1 +> @x ) 2 +> @x ) 5 +> @x )", 9 | [(x: 1), (x: 2), (x: 4), (x: 9)] 10 | ], 11 | 12 | decr_int: [ 13 | "1 => @x ) 1 -> @x ) 2 -> @x ) 5 -> @x )", 14 | [(x: 1), (x: 0), (x: -2), (x: -7)] 15 | ], 16 | 17 | multr_int: [ 18 | "2 => @x ) 3 x> @x ) 1 x> @x ) 0 x> @x )", 19 | [(x: 2), (x: 6), (x: 6), (x: 0)] 20 | ] 21 | 22 | )); 23 | -------------------------------------------------------------------------------- /SuperCollider/Testing/levels.scd: -------------------------------------------------------------------------------- 1 | 2 | var qrt = (\dur:1); 3 | var eth = (\dur:1/2); 4 | 5 | SkoarTestRunner(( 6 | 7 | ppp: [ 8 | "ppp ) pp ) p ) mp )", 9 | [(amp: 1/8), (amp: 2/8), (amp: 3/8), (amp: 4/8)] 10 | ], 11 | 12 | pppiano: [ 13 | "pppiano ) ppiano ) piano ) mezzopiano ) mpiano )", 14 | [(amp: 1/8), (amp: 2/8), (amp: 3/8), (amp: 4/8), (amp: 4/8)] 15 | ], 16 | 17 | fff: [ 18 | "fff ) ff ) forte ) mf )", 19 | [(amp: 1), (amp: 7/8), (amp: 6/8), (amp: 5/8)] 20 | ], 21 | 22 | ffforte: [ 23 | "ffforte ) fforte ) forte ) mforte ) mezzoforte )", 24 | [(amp: 1), (amp: 7/8), (amp: 6/8), (amp: 5/8), (amp: 5/8)] 25 | ], 26 | 27 | hashbars_short: [ 28 | "[] =>@x) [ ] =>@x) [#] =>@x) [ ] =>@x) [# ] =>@x) [##] =>@x) [# ] =>@x) [## ] =>@x) [###] =>@x) ", 29 | [(x: 0), (x: 0), (x: 1), (x: 0), (x: 1/2), (x: 1), (x: 1/3), (x: 2/3), (x: 1), ] 30 | ], 31 | 32 | hashbars_longer: [ 33 | "[##### ] =>@x) [############################## ] =>@x) [############################################################ ] =>@x)", 34 | [(x: 5/11), (x: 30/31), (x: 60/61), ] 35 | ], 36 | 37 | )); 38 | -------------------------------------------------------------------------------- /SuperCollider/Testing/noaty.scd: -------------------------------------------------------------------------------- 1 | 2 | var qrt = (\dur:1); 3 | var eth = (\dur:1/2); 4 | 5 | SkoarTestRunner(( 6 | 7 | low: [ 8 | "_c) _d) _e) _f) _g) _a) _b)", 9 | [(note: 0), (note: 2), (note: 4), (note: 5), (note: 7), (note: 9), (note: 11)] 10 | ], 11 | 12 | high: [ 13 | "c) d) e) f) g) a) b)", 14 | [(note: 12), (note: 14), (note: 16), (note: 17), (note: 19), (note: 21), (note: 23)] 15 | ], 16 | 17 | flats_low: [ 18 | "_cb) _db) _eb) _fb) _gb) _ab) _bb ) _b )", 19 | [(note: -1), (note: 1), (note: 3), (note: 4), (note: 6), (note: 8), (note: 10), (note: 11)] 20 | ], 21 | 22 | flats_high: [ 23 | "cb) db) eb) fb) gb) ab) bb ) b )", 24 | [(note: 11), (note: 13), (note: 15), (note: 16), (note: 18), (note: 20), (note: 22), (note: 23)] 25 | ], 26 | 27 | sharps_low: [ 28 | "_c#) _d#) _e#) _f#) _g#) _a#) _b# ) _b )", 29 | [(note: 1), (note: 3), (note: 5), (note: 6), (note: 8), (note: 10), (note: 12), (note: 11)] 30 | ], 31 | 32 | sharps_high: [ 33 | "c#) d#) e#) f#) g#) a#) b#) b)", 34 | [(note: 13), (note: 15), (note: 17), (note: 18), (note: 20), (note: 22), (note: 24), (note: 23)] 35 | ], 36 | 37 | choards_basic: [ 38 | "C) D) E) F) G) A) B)", 39 | [ (note: [0,4,7]), (note: [2,6,9]), 40 | (note: [4,8,11]), (note: [5,9,12]), 41 | (note: [7,11,14]), (note: [9,13,16]), 42 | (note: [11,15,18])] 43 | ], 44 | 45 | choards_moar: [ 46 | "Cm) C7) Cm7) CM7) CmM7) Cdim) Csus2) Csus4M7) Caug) Caug6)", 47 | [ (note: [0, 3, 7]), 48 | (note: [0, 4, 7, 10]), 49 | (note: [0, 3, 7, 10]), 50 | (note: [0, 4, 7, 11]), 51 | (note: [0, 3, 7, 11]), 52 | 53 | (note: [0, 3, 6]), 54 | 55 | (note: [0, 2, 7]), 56 | (note: [0, 5, 7, 11]), // c f g b 57 | 58 | (note: [0, 4, 8]), 59 | (note: [0, 4, 8, 9]), 60 | ] 61 | ], 62 | 63 | )); 64 | -------------------------------------------------------------------------------- /SuperCollider/Testing/ops.scd: -------------------------------------------------------------------------------- 1 | 2 | var qrt = (\dur:1); 3 | var eth = (\dur:1/2); 4 | 5 | SkoarTestRunner(( 6 | 7 | math_add_a: [ 8 | "1 + 2 ) 3 + 4 + 5 )", 9 | [(\degree:3),(\degree:12)] 10 | ], 11 | 12 | math_add_b: [ 13 | "1 + 2 ) 3 + 4 + 5 ) $ + 3 )", 14 | [(\degree:3),(\degree:12),(\degree:15)] 15 | ], 16 | 17 | math_add_c: [ 18 | "0 + 0 ) 1 + 1 + 1 => @x )", 19 | [(\degree:0),(\degree:3)] 20 | ], 21 | 22 | math_mul_a: [ 23 | "1 * 2 ) 3 * 4 * 5 )", 24 | [(\degree:2),(\degree:60)] 25 | ], 26 | 27 | math_mul_b: [ 28 | "1 + 2 * 5 ) 3 + 4 * 5 ) $ * 2 + 1 )", 29 | [(\degree:15),(\degree:35),(\degree:71)] 30 | ], 31 | 32 | 33 | // --------------------------------------------------- 34 | // --------------------------------------------------- 35 | // Addition 36 | // --------------------------------------------------- 37 | // --------------------------------------------------- 38 | 39 | op_add_Symbol_Symbol: [ 40 | "@abc + @def => @x )", 41 | [(x:'abcdef')] 42 | ], 43 | 44 | op_add_Symbol_Int: [ 45 | "@abc + 7 => @x )", 46 | [(x:'abc7')] 47 | ], 48 | 49 | op_add_Symbol_Noat: [ 50 | "@abc + c# => @x )", 51 | [(x: 'abcc#')] 52 | ], 53 | 54 | op_add_Symbol_Choard: [ 55 | "@abc + A# => @x )", 56 | [(x: 'abcA#')] 57 | ], 58 | 59 | 60 | op_add_Symbol_List: [ 61 | "@abc + <0,1> => @x )", 62 | [(x: ['abc', 0, 1])] 63 | ], 64 | 65 | op_add_Symbol_Freq: [ 66 | "@abc + 2600Hz => @x )", 67 | [(x: 'abc2600Hz')] 68 | ], 69 | 70 | op_add_Symbol_String: [ 71 | "@abc + 'ABC' => @x )", 72 | [(x: 'abcABC')] 73 | ], 74 | 75 | op_add_Symbol_Float: [ 76 | "@abc + 2.18 => @x )", 77 | [(x: 'abc2.18')] 78 | ], 79 | 80 | op_add_Int_Symbol: [ 81 | "7 + @abc => @x )", 82 | [(x: '7abc')] 83 | ], 84 | 85 | op_add_Int_Int: [ 86 | "7 + 7 => @x )", 87 | [(x: 14)] 88 | ], 89 | 90 | 91 | op_add_Int_List: [ 92 | "7 + <0,1> => @x )", 93 | [(x: [7,0,1])] 94 | ], 95 | 96 | op_add_Int_Freq: [ 97 | "7 + 2600Hz )", 98 | [(freq: 2607)] 99 | ], 100 | 101 | 102 | 103 | op_add_Int_String: [ 104 | "7 + 'ABC' => @x )", 105 | [(x: "7ABC")] 106 | ], 107 | 108 | op_add_Int_Float: [ 109 | "7 + 2.18 => @x )", 110 | [(x: 9.18)] 111 | ], 112 | 113 | 114 | op_add_List_Symbol: [ 115 | "<0,1> + @abc => @x )", 116 | [(x: [0,1,\abc])] 117 | ], 118 | 119 | op_add_List_Int: [ 120 | "<0,1> + 7 => @x )", 121 | [(x: [0,1,7])] 122 | ], 123 | 124 | op_add_List_List: [ 125 | "<0,1> + <0,1> => @x )", 126 | [(x: [0,1,0,1])] 127 | ], 128 | 129 | op_add_List_Freq: [ 130 | "<0,1> + 2600Hz => @x )", 131 | [(x: [0,1,2600])] 132 | ], 133 | 134 | op_add_List_String: [ 135 | "<0,1> + 'ABC' => @x )", 136 | [(x: [0,1,"ABC"] )] 137 | ], 138 | 139 | op_add_List_Float: [ 140 | "<0,1> + 2.18 => @x )", 141 | [(x: [0,1,2.18])] 142 | ], 143 | 144 | 145 | op_add_Noat_Symbol: [ 146 | "c# + @abc=> @x )", 147 | [(x: 'c#abc')] 148 | ], 149 | 150 | 151 | 152 | op_add_Noat_String: [ 153 | "c# + 'ABC' => @x )", 154 | [(x: "c#ABC")] 155 | ], 156 | 157 | 158 | op_add_Choard_Symbol: [ 159 | "A# + @abc=> @x )", 160 | [(x: 'A#abc')] 161 | ], 162 | 163 | 164 | 165 | op_add_Choard_String: [ 166 | "A# + 'ABC' => @x )", 167 | [(x: "A#ABC" )] 168 | ], 169 | 170 | 171 | 172 | op_add_String_Symbol: [ 173 | "'ABC' + @abc => @x )", 174 | [(x: "ABCabc" )] 175 | ], 176 | 177 | op_add_String_Int: [ 178 | "'ABC' + 7 => @x )", 179 | [(x: "ABC7" )] 180 | ], 181 | 182 | op_add_String_Noat: [ 183 | "'ABC' + c# => @x )", 184 | [(x: "ABCc#" )] 185 | ], 186 | 187 | op_add_String_Choard: [ 188 | "'ABC' + A# => @x )", 189 | [(x: "ABCA#")] 190 | ], 191 | 192 | op_add_String_List: [ 193 | "'ABC' + <0,1> => @x )", 194 | [(x: ["ABC",0,1])] 195 | ], 196 | 197 | op_add_String_Freq: [ 198 | "'ABC' + 2600Hz => @x )", 199 | [(x: "ABC2600Hz" )] 200 | ], 201 | 202 | 203 | 204 | op_add_String_String: [ 205 | "'ABC' + 'ABC' => @x )", 206 | [(x: "ABCABC" )] 207 | ], 208 | 209 | op_add_String_Float: [ 210 | "'ABC' + 2.18 => @x )", 211 | [(x: "ABC2.18" )] 212 | ], 213 | 214 | op_add_Freq_Symbol: [ 215 | "2600Hz + @abc=> @x )", 216 | [(x:'2600Hzabc')] 217 | ], 218 | 219 | op_add_Freq_Int: [ 220 | "2600Hz + 7 => @x )", 221 | [(x:2607)] 222 | ], 223 | 224 | 225 | op_add_Freq_List: [ 226 | "2600Hz + <0,1> => @x )", 227 | [(x: [2600,0,1])] 228 | ], 229 | 230 | op_add_Freq_Freq: [ 231 | "2600Hz + 2600Hz => @x )", 232 | [(x: 5200)] 233 | ], 234 | 235 | op_add_Freq_String: [ 236 | "2600Hz + 'ABC' => @x )", 237 | [(x: "2600HzABC" )] 238 | ], 239 | 240 | op_add_Freq_Float: [ 241 | "2600Hz + 2.18 => @x )", 242 | [(x: 2602.18 )] 243 | ], 244 | 245 | 246 | op_add_Float_Symbol: [ 247 | "2.18 + @abc=> @x )", 248 | [(x: '2.18abc')] 249 | ], 250 | 251 | op_add_Float_Int: [ 252 | "2.18 + 7 => @x )", 253 | [(x: 9.18)] 254 | ], 255 | 256 | 257 | 258 | op_add_Float_Float: [ 259 | "2.18 + 2.18 => @x )", 260 | [(x: 4.36)] 261 | ], 262 | 263 | op_add_Hash_Int: [ 264 | "[### ] + 7 => @x )", 265 | [(x: 7.6)] 266 | ], 267 | 268 | op_add_Int_Hash: [ 269 | "7 + [### ]=> @x )", 270 | [(x: 7.6)] 271 | ], 272 | 273 | op_add_Hash_Hash: [ 274 | "[### ] + [#### ] => @x )", 275 | [(x: 0.7)] 276 | ], 277 | 278 | // --------------------------------------------------- 279 | // --------------------------------------------------- 280 | // Subtraction 281 | // --------------------------------------------------- 282 | // --------------------------------------------------- 283 | 284 | op_sub_Int_Int: [ 285 | "7 - 7 => @x )", 286 | [(x: 0)] 287 | ], 288 | 289 | op_sub_Int_Freq: [ 290 | "7 - 2600Hz => @x )", 291 | [(x: -2593)] 292 | ], 293 | 294 | op_sub_Int_Float: [ 295 | "7 - 2.18 => @x )", 296 | [(x: 4.82)] 297 | ], 298 | 299 | op_sub_Freq_Freq: [ 300 | "2600Hz - 2600Hz => @x )", 301 | [(x: 0)] 302 | ], 303 | 304 | op_sub_Freq_Float: [ 305 | "2600Hz - 2.18 )", 306 | [(freq: 2597.82 )] 307 | ], 308 | 309 | op_sub_Float_Int: [ 310 | "2.18 - 7 => @x )", 311 | [(x: -4.82)] 312 | ], 313 | 314 | op_sub_Float_Float: [ 315 | "2.18 - 2.18 => @x )", 316 | [(x: 0)] 317 | ], 318 | 319 | op_sub_Hash_Int: [ 320 | "[### ] - 7 => @x )", 321 | [(x: -6.4)] 322 | ], 323 | 324 | op_sub_Int_Hash: [ 325 | "7 - [### ]=> @x )", 326 | [(x: 6.4)] 327 | ], 328 | 329 | op_sub_Hash_Hash: [ 330 | "[### ] - [#### ] => @x )", 331 | [(x: -0.1)] 332 | ], 333 | 334 | 335 | op_add_Float_String: [ 336 | "2.18 + 'ABC' => @x )", 337 | [(x: "2.18ABC")] 338 | ], 339 | 340 | // False 341 | op_add_Float_False: [ 342 | "2.18 + no => @x )", 343 | [(x: false)] 344 | ], 345 | 346 | op_add_Symbol_False: [ 347 | "@abc + no => @x )", 348 | [(x: false)] 349 | ], 350 | 351 | op_add_Int_False: [ 352 | "7 + no => @x )", 353 | [(x: false)] 354 | ], 355 | 356 | op_add_List_False: [ 357 | "<0,1> + no => @x )", 358 | [(x: false)] 359 | ], 360 | 361 | op_add_Noat_False: [ 362 | "c# + no => @x )", 363 | [(x: false )] 364 | ], 365 | 366 | op_add_Choard_False: [ 367 | "A# + no => @x )", 368 | [(x: false)] 369 | ], 370 | 371 | op_add_False_Symbol: [ 372 | "no + @abc=> @x )", 373 | [(x: false)] 374 | ], 375 | 376 | op_add_False_Choard: [ 377 | "no + A# => @x )", 378 | [(x: false)] 379 | ], 380 | 381 | op_add_False_Freq: [ 382 | "no + 2600Hz => @x )", 383 | [(x: false)] 384 | ], 385 | 386 | op_add_False_List: [ 387 | "no + <0,1> => @x )", 388 | [(x: false)] 389 | ], 390 | 391 | op_add_False_Noat: [ 392 | "no + c# => @x )", 393 | [(x: false)] 394 | ], 395 | 396 | op_add_False_String: [ 397 | "no + 'ABC' => @x )", 398 | [(x: false)] 399 | ], 400 | 401 | op_add_False_False: [ 402 | "no + no => @x )", 403 | [(x: false)] 404 | ], 405 | 406 | op_add_False_Int: [ 407 | "no + 7 => @x )", 408 | [(x: false)] 409 | ], 410 | 411 | op_add_False_Float: [ 412 | "no + 2.18 => @x )", 413 | [(x: false)] 414 | ], 415 | 416 | op_add_String_False: [ 417 | "'ABC' + no => @x )", 418 | [(x: false)] 419 | ], 420 | 421 | // True 422 | op_add_Float_True: [ 423 | "2.18 + yes => @x )", 424 | [(x: 2.18)] 425 | ], 426 | 427 | op_add_Symbol_True: [ 428 | "@abc + yes => @x )", 429 | [(x: \abc)] 430 | ], 431 | 432 | op_add_Int_True: [ 433 | "7 + yes => @x )", 434 | [(x: 7)] 435 | ], 436 | 437 | op_add_List_True: [ 438 | "<0,1> + yes => @x )", 439 | [(x: [0,1])] 440 | ], 441 | 442 | op_add_Noat_True: [ 443 | "c# + yes => @x )", 444 | [(x: nil )] 445 | ], 446 | 447 | op_add_Choard_True: [ 448 | "A# + yes => @x )", 449 | [(x: nil)] 450 | ], 451 | 452 | op_add_True_Symbol: [ 453 | "yes + @abc=> @x )", 454 | [(x: 'abc')] 455 | ], 456 | 457 | op_add_True_Choard: [ 458 | "yes + A# => @x )", 459 | [(x: nil)] 460 | ], 461 | 462 | op_add_True_Freq: [ 463 | "yes + 2600Hz => @x )", 464 | [(x: 2600)] 465 | ], 466 | 467 | op_add_True_List: [ 468 | "yes + <0,1> => @x )", 469 | [(x: [0,1])] 470 | ], 471 | 472 | op_add_True_Noat: [ 473 | "yes + c# => @x )", 474 | [(x: nil)] 475 | ], 476 | 477 | op_add_True_String: [ 478 | "yes + 'ABC' => @x )", 479 | [(x: "ABC")] 480 | ], 481 | 482 | op_add_True_True: [ 483 | "yes + yes => @x )", 484 | [(x: true)] 485 | ], 486 | 487 | op_add_True_Int: [ 488 | "yes + 7 => @x )", 489 | [(x: 7)] 490 | ], 491 | 492 | op_add_True_Float: [ 493 | "yes + 2.18 => @x )", 494 | [(x: 2.18)] 495 | ], 496 | 497 | op_add_String_True: [ 498 | "'ABC' + yes => @x )", 499 | [(x: "ABC")] 500 | ], 501 | 502 | // --------------------------------------------------- 503 | // --------------------------------------------------- 504 | // Multiplication 505 | // --------------------------------------------------- 506 | // --------------------------------------------------- 507 | op_mul_Int_Int: [ 508 | "7 * 7 => @x )", 509 | [(x: 49)] 510 | ], 511 | 512 | op_mul_Int_Freq: [ 513 | "7 * 2600Hz )", 514 | [(freq: 18200)] 515 | ], 516 | 517 | op_mul_Int_Float: [ 518 | "7 * 2.18 => @x )", 519 | [(x: 15.26)] 520 | ], 521 | 522 | op_mul_Freq_Int: [ 523 | "2600Hz * 7 => @x )", 524 | [(x:18200)] 525 | ], 526 | 527 | op_mul_Freq_Freq: [ 528 | "2600Hz * 2600Hz )", 529 | [(freq:6760000)] 530 | ], 531 | 532 | op_mul_Freq_Float: [ 533 | "2600Hz * 2.18 => @x )", 534 | [(x: 5668 )] 535 | ], 536 | 537 | op_mul_Float_Int: [ 538 | "2.18 * 7 => @x )", 539 | [(x: 15.26)] 540 | ], 541 | 542 | op_mul_Float_Float: [ 543 | "2.18 * 2.18 => @x )", 544 | [(x: 4.7524)] 545 | ], 546 | 547 | op_mul_Hash_Int: [ 548 | "[### ] * 7 => @x )", 549 | [(x: 4.2)] 550 | ], 551 | 552 | op_mul_Int_Hash: [ 553 | "7 * [### ]=> @x )", 554 | [(x: 4.2)] 555 | ], 556 | 557 | op_mul_Hash_Hash: [ 558 | "[### ] * [#### ] => @x )", 559 | [(x: 0.12)] 560 | ], 561 | )); 562 | -------------------------------------------------------------------------------- /SuperCollider/Testing/regex.scd: -------------------------------------------------------------------------------- 1 | 2 | // These tests check for regex ambiguities 3 | 4 | var qrt = (\dur:1); 5 | var eth = (\dur:1/2); 6 | 7 | SkoarTestRunner(( 8 | 9 | // i'm not sure how to test this stuff. 10 | forte: [ 11 | "forte", 12 | [()] 13 | ], 14 | 15 | )); 16 | -------------------------------------------------------------------------------- /SuperCollider/Testing/sanity.scd: -------------------------------------------------------------------------------- 1 | 2 | var qrt = (\dur:1); 3 | var eth = (\dur:1/2); 4 | var sxt = (\dur:1/4); 5 | 6 | SkoarTestRunner(( 7 | 8 | long_beats: [ 9 | ") ). )) )). ))) )))) .))))) )))))) )))))))", 10 | [(\dur:1),(\dur:1.5),(\dur:2),(\dur:3),(\dur:4),(\dur:8),(\dur:16),(\dur:32),(\dur:64)] 11 | ], 12 | 13 | short_beats: [ 14 | "] ]] ]]] ]]]] ]]. ]]]. ]]]]] .]]]]]] ]]]]]]]", 15 | [(\dur:1/2), (\dur:1/4),(\dur:1/8), 16 | (\dur:1/16),(\dur:3/8), (\dur:3/16), 17 | (\dur:1/32),(\dur:1/64),(\dur:1/128)] 18 | ], 19 | 20 | long_rests: [ 21 | "} }} }}} }}}} }. }}.", 22 | [(\dur:1,\isRest:true),(\dur:2,\isRest:true), 23 | (\dur:4,\isRest:true),(\dur:8,\isRest:true), 24 | (\dur:1.5,\isRest:true),(\dur:3,\isRest:true)] 25 | ], 26 | 27 | short_rests: [ 28 | "o/ oo/ ooo/ oooo/ ooooo/ o/. oo/. ooo/.", 29 | [(\dur:1/2,\isRest:true),(\dur:1/4,\isRest:true), 30 | (\dur:1/8,\isRest:true), (\dur:1/16,\isRest:true), 31 | (\dur:1/32,\isRest:true),(\dur:3/4,\isRest:true), 32 | (\dur:3/8,\isRest:true),(\dur:3/16,\isRest:true)] 33 | ], 34 | 35 | fancy_beats: [ 36 | ".] .]]. ]. .)__ .)__. ]__.", 37 | [(\dur:1/2),(\dur:3/8),(\dur:3/4),(\dur:1),(\dur:1.5),(\dur:3/4)] 38 | ], 39 | 40 | fancy_beats: [ 41 | ".] .]]. ]. .)__ .)__. ]__.", 42 | [(\dur:1/2),(\dur:3/8),(\dur:3/4),(\dur:1),(\dur:1.5),(\dur:3/4)] 43 | ], 44 | 45 | listy_a: [ 46 | "<0,1,2> => @food )", 47 | [( 'dur': 1.0, 'food': [ 0, 1, 2 ] )] 48 | 49 | ], 50 | 51 | listy_b: [ 52 | "<0.0, -1, 2.2> => @food )", 53 | [( 'dur': 1.0, 'food': [ 0.0, -1, 2.2 ] )] 54 | 55 | ], 56 | 57 | listy_c: [ 58 | "<<0,3>,1,2> => @food )", 59 | [( 'dur': 1.0, 'food': [ [0,3], 1, 2 ] )] 60 | 61 | ], 62 | 63 | listy_d: [ 64 | "3 => @x <0,!x,2> => @food )", 65 | [( 'dur': 1.0, 'food': [ 0, 3, 2 ], 'x': 3 )] 66 | 67 | ], 68 | 69 | listy_e: [ 70 | "<3,4> => @x <0,!x,2> => @food )", 71 | [( 'dur': 1.0, 'food': [ 0, [3,4], 2 ], 'x':[3, 4] )] 72 | 73 | ], 74 | 75 | numbers: [ 76 | "-1 ) 0 ) 1 ) 2 ) 20 ] 0.1 ] 1.0 ] ", 77 | [(\degree:-1),(\degree:0),(\degree:1),(\degree:2), 78 | (\degree:20),(\degree:0.1),(\degree:1.0)] 79 | ], 80 | 81 | colons_simple: [ 82 | "|: ) ) ) :| ] ] :|", 83 | [ 84 | qrt,qrt,qrt, 85 | qrt,qrt,qrt, eth,eth, 86 | qrt,qrt,qrt, eth,eth 87 | ] 88 | ], 89 | 90 | colons_middle: [ 91 | "|: ) ) ) |: ] ] :|", 92 | [ 93 | qrt,qrt,qrt, 94 | eth,eth,eth,eth 95 | ] 96 | ], 97 | 98 | dal_segno_a: [ 99 | ",segno` ) ) ) |: ] ] :| fine D.S. al fine", 100 | [ 101 | qrt, qrt, qrt, eth, eth, eth, eth, 102 | qrt, qrt, qrt, eth, eth, eth, eth 103 | ] 104 | ], 105 | 106 | dal_segno_b: [ 107 | ",segno` ) ,segno` ) ) |: ] ] :| fine Dal Segno al fine", 108 | [ 109 | qrt, qrt, qrt, eth, eth, eth, eth, 110 | qrt, qrt, eth, eth, eth, eth, 111 | ] 112 | ], 113 | 114 | skoarpion_a: [ 115 | ") {! f !! ] !} !f", 116 | [qrt, eth] 117 | ], 118 | 119 | skoarpion_b: [ 120 | ") {! f !! !x ] !} ) !f<0>", 121 | [qrt, qrt, eth] 122 | ], 123 | 124 | skoarpion_c: [ 125 | ") {! !! ] !} => @f ) !f<0>", 126 | [qrt, qrt, eth] 127 | ], 128 | 129 | skoarpion_d: [ 130 | ") {! ] !} => @f ) !f", 131 | [qrt, qrt, eth] 132 | ], 133 | 134 | one_voice_a: [ 135 | ") 136 | .a ] 137 | ) 138 | .a ] 139 | ", 140 | [qrt, eth, qrt, eth] 141 | ], 142 | 143 | one_voice_b: [ 144 | ") ) 145 | .a ] ] 146 | ", 147 | [qrt, qrt, eth, eth] 148 | ], 149 | 150 | two_voices_a: [ 151 | ") ) 152 | .a ] ] ] 153 | .b ]] ]] ) 154 | ", 155 | [[qrt,qrt], [qrt,qrt], [eth,sxt], sxt, [eth,qrt], eth] 156 | ], 157 | 158 | )); 159 | -------------------------------------------------------------------------------- /SuperCollider/Testing/spawn_skeletons.scd: -------------------------------------------------------------------------------- 1 | x = SkoarOps.new; 2 | 3 | x.addition.keysValuesDo({ 4 | | k, v | 5 | 6 | /* 7 | math_add_a: [ 8 | "1 + 2 ) 3 + 4 + 5 )", 9 | [(\degree:3),(\degree:12)] 10 | ],*/ 11 | 12 | v.keysValuesDo { 13 | | p, q | 14 | var a = k.asString; 15 | var b = p.asString; 16 | a = a[11..a.size-1]; 17 | b = b[11..b.size-1]; 18 | ("op_add_" ++ a ++ "_" ++ b ++": [\n \"" ++ a ++ " + " ++ b ++ " => @x )\",").postln; 19 | (" [(\x:inf)]\n],\n").postln; 20 | }; 21 | "".postln; 22 | 23 | }); 24 | 25 | -------------------------------------------------------------------------------- /SuperCollider/Testing/unittests.sc: -------------------------------------------------------------------------------- 1 | SkoarTest : UnitTest { 2 | 3 | var <>tests_table; 4 | 5 | *report { 6 | super.report; 7 | Post.nl; 8 | if (failures.size > 0) { 9 | "SKOAR FAIL".inform; 10 | } { 11 | "SKOAR PASS".inform; 12 | }; 13 | } 14 | 15 | setUp { 16 | // this will wait until the server is booted 17 | //this.bootServer; 18 | // if the server is already booted it will free all nodes 19 | // and create new allocators, giving you a clean slate 20 | } 21 | 22 | tearDown { 23 | // this will be called after each test 24 | } 25 | 26 | //this.assert( 6 == 6, "6 should equal 6"); 27 | //this.assertEquals( 9, 9, "9 should equal 9"); 28 | //this.assertFloatEquals( 4.0 , 1.0 * 4.0 / 4.0 * 4.0, 29 | // "floating point math should be close to equal"); 30 | 31 | // will wait until the condition is true 32 | // will be considered a failure after 10 seconds 33 | //this.wait( { p.isPlaying }, "waiting for synth to play", 10); 34 | 35 | test_do { 36 | 37 | this.assert(tests_table.notNil == true, "You didn't set up the tests right."); 38 | if (tests_table.isNil) { 39 | ^nil; 40 | }; 41 | 42 | tests_table.keysValuesDo { 43 | | test_name, test_meat | 44 | 45 | var s = test_meat[0]; 46 | var a = test_meat[1]; 47 | var msg = test_name.asString; 48 | 49 | ("Test: " ++ test_name).postln; 50 | "Test input: ".post; s.postln; 51 | "Expectations:".postln; a.do { 52 | | x | 53 | x.postln; 54 | }; 55 | 56 | Expectoar.test(s, a, this, msg); 57 | 58 | }; 59 | } 60 | } 61 | 62 | SkoarTestRunner { 63 | 64 | *new { 65 | | x | 66 | ^super.new.init(x); 67 | } 68 | 69 | init { 70 | | tests | 71 | var testoar = SkoarTest.new; 72 | testoar.tests_table = tests; 73 | testoar.run; 74 | } 75 | } 76 | 77 | Expectoar { 78 | 79 | var ").postln; 191 | 192 | testoar.assert(seen_event.isKindOf(Event), tag ++ "should be an event."); 193 | 194 | if (seen_event.notNil) { 195 | var seen_val = this.flatten(seen_event[ekey]); 196 | var x; 197 | 198 | // we send inf if we want to test that the value doesn't exist (because we can't send nil) 199 | if (eval == inf) { 200 | eval = nil; 201 | }; 202 | 203 | if (eval.isKindOf(Float)) { 204 | x = eval - seen_val; 205 | if (x < 0) { 206 | x = -1 * x; 207 | }; 208 | x = x < 0.0001; 209 | } { 210 | x = seen_val == eval; 211 | }; 212 | 213 | testoar.assert(x, tag ++ "seen_event[" ++ ekey ++ "] = " ++ seen_val ++ " == " ++ eval ++ " expected :: <" 214 | ++ seen_val.class.asString ++ ", " ++ eval.class.asString ++ ">"; 215 | ); 216 | }; 217 | 218 | }; 219 | } 220 | 221 | 222 | matches { 223 | | exp_event, seen_events | 224 | seen_events.do { 225 | | seen_event | 226 | var seen = true; 227 | 228 | exp_event.keysValuesDo { 229 | | ekey, eval | 230 | if (seen_event.notNil) { 231 | var x = this.flatten(seen_event[ekey]); 232 | 233 | seen = seen && (x == eval); 234 | }; 235 | }; 236 | 237 | if (seen == true) { 238 | ^true; 239 | }; 240 | }; 241 | 242 | ^false; 243 | } 244 | 245 | flatten { 246 | | obj | 247 | 248 | if (obj.isKindOf(Skoarpuscle)) { 249 | obj = obj.val; 250 | }; 251 | 252 | if (obj.isKindOf(Array)) { 253 | var a = []; 254 | obj.do { 255 | | x | 256 | a = a.add(this.flatten(x)); 257 | }; 258 | obj = a; 259 | }; 260 | 261 | ^obj; 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /SuperCollider/examples/brandnewshoes.scd: -------------------------------------------------------------------------------- 1 | (x = " 2 | 80 => ) 3 | 4 | => @key 5 | 5 => @transpose 6 | 7 | .melody @bass => @instrument pp o~ 8 | .bass @bass => @instrument o~~ mp 9 | .wah @sillyvoice => @instrument o~~~ mf 10 | 11 | .tom @tom => @instrument ~o pp 12 | .kik @kik => @instrument ~~o pp 13 | .snare @kraftySnr => @instrument ff 14 | 15 | 0 16 | 17 | .wah {: }}} ))) :: 2 times :} {: ))) :: 20 times :} 18 | .bass oo/ {: ] ] :: 20 times :} 19 | .tom {: ] ] :: 20 times :} {: {? 4 times ?? o/ ]] oo/ ?? ] ] ?} :: 80 times :} 20 | .snare }}}} {: {? 5 times ?? o/ ] ?? ]] fff oo/ ]] ]] ff ?} :: 60 times :} 21 | 22 | .kik }}}} {: ] ] :: 7 times :} 23 | .kik {: {? 20 times ?? ] ]] ]] ?? oo/. ]]] ] oo/. ]]] ] oo/. ]]] ] oo/. ]]] ] ?} :: 70 times :} 24 | 25 | .bass {: {? 10 times ?? <0,0,2,3>.choose ] ] ?? <<0,1,0,1,0,1,0,1>,<0,1,0,2,0,3,5,5>>.choose.{: ]]] :} ?} :: 76 times :} 26 | 27 | .melody } ] } oo/ ]] ] }}} 28 | .melody {: 2.rand <$, $+1, $+2.rand>.{: $ => @x {? 3 times ?? !x ]] ]] $+2 ]] ]] $+3 ]] ]] ?? !x ]] ]] ]] o/ ?} :} :: 3 times :} 29 | 30 | .melody {: 3.rand <$, $+1, $+2.rand>.{: $ => @x {? 3 times ?? !x ] oo/ ]] ]] oo/ ]] oo/ ?? !x ] ] ] oo/ $+1 ]] ?} :} :: 6 times :} 31 | 32 | .melody {: 3.rand <$, $+1, $+2.rand>.{: $ => @x {? 3 times ?? !x ]] ]] $+2 ]] ]] $+3 ]] ]] ?? !x ]] ]] ]] ]] ]] ]] ?} :} :: 3 times :} 33 | 34 | .melody <0,1,2,3,4,5,6,7,8>.{: ]]] :} ooo/ 35 | .melody {: 3.rand + 2 <$, $+1, $+2>.{: $ => @x {? 3 times ?? !x ]] ]] $+2 ]] ]] $+3 ]] ]] ?? !x ]] ]] ]] ]] ]] ]] ?} :} :: 3 times :} 36 | 37 | .melody {: 3.rand + 6 <$, $+1.rand+1, $+3>.{: $ => @x {? 3 times ?? !x ]]] ]]] ]] o/ ]]] ]]] ]] ?? !x ]] ]] o/ ]] ]] ?} :} :: 3 times :} 38 | 39 | .melody <0,1,2,3,4,5,6,7,8,9,10>.{: ]]] :} ooo/ ) 40 | 41 | ".skoar.play; 42 | ) 43 | -------------------------------------------------------------------------------- /SuperCollider/examples/dungeontimes.scd: -------------------------------------------------------------------------------- 1 | // first boot the server (Ctrl-B) 2 | // then load the synthdefs from synthdefs.scd (run the entire file) (if you don't want to do that remove the @instrument line) 3 | // then run this. 4 | 5 | (" 6 | 7 | 80 => ) 8 | 9 | @plucking => @instrument 10 | 11 | .high mf 12 | .low o~~ ff 13 | 14 | ,segno` 15 | 4/4 16 | 17 | .high | _g ]] _a# ]] d ]] d# ]] _g ]] _a# ]] d ]] d# ]] _g ]] _a# ]] d ]] d# ]] _g ]] _a# ]] d ]] d# ]] | 18 | .low | g )) a# ) ~o d ) | 19 | 20 | .high | _f# ]] _a# ]] d ]] d# ]] _f# ]] _a# ]] d ]] d# ]] _f# ]] _a# ]] d ]] d# ]] _f# ]] _a# ]] d ]] d# ]] | 21 | .low | c# ) o~ f# )). | 22 | 23 | .high | _f ]] _g# ]] d ]] d# ]] _f ]] _g# ]] d ]] d# ]] _f ]] _g# ]] d ]] d# ]] _f ]] _g# ]] d ]] d# ]] | 24 | .low | f )) f ]. g# ]. ~o c# ] | 25 | 26 | .high | _e ]] _g ]] d ]] d# ]] _e ]] _g ]] d ]] d# ]] _e ]] _g ]] d ]] d# ]] _e ]] _g ]] d ]] d# ]] | 27 | .low | c ) o~ e )). | 28 | 29 | .high | _d# ]] _g ]] c ]] d ]] _d# ]] _g ]] c ]] d ]] _d# ]] _g ]] c ]] d ]] _d# ]] _g ]] c ]] d ]] | 30 | .low | _d# ]] _d ]] _d# ). g ]. ~o d# ]. d ] o~ | 31 | 32 | .high | _d ]] _g ]] c ]] d ]] _d ]] _g ]] c ]] d ]] _d ]] _g ]] c ]] d ]] _d ]] _g ]] c ]] d ]] | 33 | .low | _d ]] _c# ]] _d ). g ]. ~o d ]. c# ] o~ | 34 | 35 | 5/4 36 | 37 | .low ~o 38 | 39 | .high | _c ]] _f# ]] _a ]] c ]] _f# ]] _a ]] c ]] d# ]] _a ]] c ]] d# ]] c ]] d# ]] f# ]] d# ]] f# ]] a ]] _f# ]] a ]] ~o c ]] | o~ 40 | .low | _d ]] _f# ]] _a ]] _f# ]] _a ]] c ]] _a ]] c ]] d# ]] c ]] d# ]] ~o f# ]] a ]] f# ]] d# ]] c ]] d# ]] c ]] _a ]] _f# ]] | o~~ 41 | 42 | D.S. 43 | 44 | ".skoar.play; 45 | ) 46 | 47 | -------------------------------------------------------------------------------- /SuperCollider/examples/synthdefs.scd: -------------------------------------------------------------------------------- 1 | // these are supercollider instruments. Gathered from around. 2 | // go see https://github.com/brunoruviaro/SynthDefs-for-Patterns for more. 3 | 4 | SynthDef(\blips, {arg out = 0, freq = 25, numharm = 10, att = 0.01, rel = 1, amp = 0.1, pan = 0.5; 5 | var snd, env; 6 | env = Env.perc(att, rel, amp).kr(doneAction: 2); 7 | snd = LeakDC.ar(Mix(Blip.ar([freq, freq*1.01], numharm, env))); 8 | Out.ar(out, Pan2.ar(snd, pan)); 9 | }).add; 10 | 11 | 12 | SynthDef(\sawpulse, { |out, freq = 440, gate = 0.5, plfofreq = 6, mw = 0, 13 | ffreq = 2000, rq = 0.3, freqlag = 0.05, amp = 1| 14 | var sig, plfo, fcurve; 15 | plfo = SinOsc.kr(plfofreq, mul:mw, add:1); 16 | freq = Lag.kr(freq, freqlag) * plfo; 17 | fcurve = EnvGen.kr(Env.adsr(0, 0.3, 0.1, 20), gate); 18 | fcurve = (fcurve - 1).madd(0.7, 1) * ffreq; 19 | sig = Mix.ar([Pulse.ar(freq, 0.9), Saw.ar(freq*1.007)]); 20 | sig = RLPF.ar(sig, fcurve, rq) 21 | * EnvGen.kr(Env.adsr(0.04, 0.2, 0.6, 0.1), gate, doneAction:2) 22 | * amp; 23 | Out.ar(out, sig ! 2) 24 | }).add; 25 | 26 | // kick ------- 27 | // http://www.soundonsound.com/sos/jan02/articles/synthsecrets0102.asp 28 | // increase mod_freq and mod_index for interesting electronic percussion 29 | 30 | SynthDef(\kick, 31 | { arg out = 0, freq = 50, mod_freq = 5, mod_index = 5, sustain = 0.4, amp = 0.8, beater_noise_level = 0.025; 32 | var pitch_contour, drum_osc, drum_lpf, drum_env; 33 | var beater_source, beater_hpf, beater_lpf, lpf_cutoff_contour, beater_env; 34 | var kick_mix; 35 | 36 | // hardcoding, otherwise skoar will set to the length of the noat ) ] ]]] etc 37 | sustain = 0.4; 38 | freq = 50; 39 | 40 | pitch_contour = Line.kr(freq*2, freq, 0.02); 41 | drum_osc = PMOsc.ar( pitch_contour, 42 | mod_freq, 43 | mod_index/1.3, 44 | mul: 1, 45 | add: 0); 46 | drum_lpf = LPF.ar(in: drum_osc, freq: 1000, mul: 1, add: 0); 47 | drum_env = drum_lpf * EnvGen.ar(Env.perc(0.005, sustain), 1.0, doneAction: 2); 48 | beater_source = WhiteNoise.ar(beater_noise_level); 49 | beater_hpf = HPF.ar(in: beater_source, freq: 500, mul: 1, add: 0); 50 | lpf_cutoff_contour = Line.kr(6000, 500, 0.03); 51 | beater_lpf = LPF.ar(in: beater_hpf, freq: lpf_cutoff_contour, mul: 1, add: 0); 52 | beater_env = beater_lpf * EnvGen.ar(Env.perc, 1.0, doneAction: 2); 53 | kick_mix = Mix.new([drum_env, beater_env]) * 2 * amp; 54 | Out.ar(out, [kick_mix, kick_mix]) 55 | }).add; 56 | 57 | 58 | // snare ------- 59 | // http://www.soundonsound.com/sos/Mar02/articles/synthsecrets0302.asp 60 | SynthDef(\snare, 61 | {arg out = 0, sustain = 0.1, drum_mode_level = 0.25, 62 | snare_level = 40, snare_tightness = 1000, 63 | freq = 405, amp = 0.8; 64 | var drum_mode_sin_1, drum_mode_sin_2, drum_mode_pmosc, drum_mode_mix, drum_mode_env; 65 | var snare_noise, snare_brf_1, snare_brf_2, snare_brf_3, snare_brf_4, snare_reson; 66 | var snare_env; 67 | var snare_drum_mix; 68 | 69 | sustain = 0.1; 70 | freq = 405; 71 | 72 | drum_mode_env = EnvGen.ar(Env.perc(0.005, sustain), 1.0, doneAction: 2); 73 | drum_mode_sin_1 = SinOsc.ar(freq*0.53, 0, drum_mode_env * 0.5); 74 | drum_mode_sin_2 = SinOsc.ar(freq, 0, drum_mode_env * 0.5); 75 | drum_mode_pmosc = PMOsc.ar( Saw.ar(freq*0.85), 76 | 184, 77 | 0.5/1.3, 78 | mul: drum_mode_env*5, 79 | add: 0); 80 | drum_mode_mix = Mix.new([drum_mode_sin_1, drum_mode_sin_2, drum_mode_pmosc]) * drum_mode_level; 81 | 82 | snare_noise = LFNoise0.ar(20000, 0.1); 83 | snare_env = EnvGen.ar(Env.perc(0.005, sustain), 1.0, doneAction: 2); 84 | snare_brf_1 = BRF.ar(in: snare_noise, freq: 8000, mul: 0.5, rq: 0.1); 85 | snare_brf_2 = BRF.ar(in: snare_brf_1, freq: 5000, mul: 0.5, rq: 0.1); 86 | snare_brf_3 = BRF.ar(in: snare_brf_2, freq: 3600, mul: 0.5, rq: 0.1); 87 | snare_brf_4 = BRF.ar(in: snare_brf_3, freq: 2000, mul: snare_env, rq: 0.0001); 88 | snare_reson = Resonz.ar(snare_brf_4, snare_tightness, mul: snare_level) ; 89 | snare_drum_mix = Mix.new([drum_mode_mix, snare_reson]) * 5 * amp; 90 | Out.ar(out, [snare_drum_mix, snare_drum_mix]); 91 | }).add; 92 | 93 | // hats ------- 94 | // http://www.soundonsound.com/sos/Jun02/articles/synthsecrets0602.asp 95 | SynthDef(\hats, 96 | {arg out = 0, freq = 6000, sustain = 0.1, amp = 0.8; 97 | var root_cymbal, root_cymbal_square, root_cymbal_pmosc; 98 | var initial_bpf_contour, initial_bpf, initial_env; 99 | var body_hpf, body_env; 100 | var cymbal_mix; 101 | 102 | amp = amp * 0.5; 103 | sustain = 0.1; 104 | freq = 6000; 105 | 106 | root_cymbal_square = Pulse.ar(freq, 0.5, mul: 1); 107 | root_cymbal_pmosc = PMOsc.ar(root_cymbal_square, 108 | [freq*1.34, freq*2.405, freq*3.09, freq*1.309], 109 | [310/1.3, 26/0.5, 11/3.4, 0.72772], 110 | mul: 1, 111 | add: 0); 112 | root_cymbal = Mix.new(root_cymbal_pmosc); 113 | initial_bpf_contour = Line.kr(15000, 9000, 0.1); 114 | initial_env = EnvGen.ar(Env.perc(0.005, 0.1), 1.0); 115 | initial_bpf = BPF.ar(root_cymbal, initial_bpf_contour, mul:initial_env); 116 | body_env = EnvGen.ar(Env.perc(0.005, sustain, 1, -2), 1.0, doneAction: 2); 117 | body_hpf = HPF.ar(in: root_cymbal, freq: Line.kr(9000, 12000, sustain),mul: body_env, add: 0); 118 | cymbal_mix = Mix.new([initial_bpf, body_hpf]) * amp; 119 | Out.ar(out, [cymbal_mix, cymbal_mix]) 120 | }).add; 121 | 122 | SynthDef("PMCrotale", { 123 | arg freq = 261, tone = 3, art = 1, amp = 0.8, pan = 0; 124 | var env, out, mod; 125 | 126 | env = Env.perc(0, art); 127 | mod = 5 + (1/IRand(2, 6)); 128 | 129 | out = PMOsc.ar(freq, mod*freq, 130 | pmindex: EnvGen.kr(env, timeScale: art, levelScale: tone), 131 | mul: EnvGen.kr(env, timeScale: art, levelScale: 0.3)); 132 | 133 | out = Pan2.ar(out, pan); 134 | 135 | out = out * EnvGen.kr(env, timeScale: 1.3*art, 136 | levelScale: Rand(0.1, 0.5), doneAction:2); 137 | Out.ar(0, out*amp); //Out.ar(bus, out); 138 | 139 | }).add; 140 | 141 | 142 | 143 | 144 | 145 | SynthDef("kick3", {arg punch = 1, amp = 1; 146 | var freq = EnvGen.kr(Env([400, 66], [0.08], -3)), 147 | sig = Normalizer.ar(SinOsc.ar(freq, 0.5pi, punch).distort, 1) * amp 148 | * EnvGen.kr(Env([0, 1, 0.8, 0], [0.01, 0.1, 0.2]), doneAction: 2); 149 | Out.ar(0, sig ! 2); 150 | }).add; 151 | 152 | 153 | 154 | SynthDef("ringkick", {arg freq = 40, decay = 0.25, amp = 1; 155 | var snd; 156 | snd = Ringz.ar( 157 | in: LPF.ar( 158 | in: Impulse.ar(0), 159 | freq: 1000), 160 | freq: freq, 161 | decaytime: decay, 162 | mul: 7 * amp).tanh.sin*2; 163 | Out.ar(0, snd!2); 164 | }).add; 165 | 166 | 167 | 168 | SynthDef("beating", {arg freq = 440, amp = 0.1, art = 1; 169 | var env, snd1, snd2; 170 | env = EnvGen.ar(Env.perc(0.01, art), doneAction: 2); 171 | snd1 = SinOsc.ar(freq); 172 | snd2 = SinOsc.ar(Line.kr(freq+15, freq, art)); 173 | Out.ar(0, Pan2.ar(Mix([snd1, snd2]), 0, amp*env)) 174 | }).add; 175 | 176 | SynthDef("bass", { |freq = 440, gate = 1, amp = 0.5, slideTime = 0.17, ffreq = 1100, width = 0.15, detune = 1.005, preamp = 4| 177 | var sig, env; 178 | env = Env.adsr(0.01, 0.3, 0.4, 0.1); 179 | freq = Lag.kr(freq, slideTime); 180 | sig = Mix(VarSaw.ar([freq, freq * detune], 0, width, preamp)).distort; 181 | sig = sig * amp * EnvGen.kr(env, gate, doneAction: 2); 182 | sig = LPF.ar(sig, ffreq); 183 | Out.ar(0, sig ! 2) 184 | }).add; 185 | 186 | SynthDef("kik", { |basefreq = 50, ratio = 7, sweeptime = 0.05, preamp = 1, amp = 1, decay1 = 0.3, decay1L = 0.8, decay2 = 0.15, out| 187 | var fcurve = EnvGen.kr(Env([basefreq * ratio, basefreq], [sweeptime], \exp)), 188 | env = EnvGen.kr(Env([1, decay1L, 0], [decay1, decay2], -4), doneAction: 2), 189 | sig = SinOsc.ar(fcurve, 0.5pi, preamp).distort * env * amp; 190 | Out.ar(out, sig ! 2) 191 | }).add; 192 | 193 | SynthDef("kraftySnr", { |amp = 1, freq = 2000, rq = 3, decay = 0.3, pan, out| 194 | var sig = PinkNoise.ar(amp), 195 | env = EnvGen.kr(Env.perc(0.01, decay), doneAction: 2); 196 | sig = BPF.ar(sig, freq, rq, env); 197 | Out.ar(out, Pan2.ar(sig, pan)) 198 | }).add; 199 | 200 | SynthDef("sillyvoice", { arg 201 | freq = 220, 202 | amp = 0.5, 203 | vibratoSpeed = 6, 204 | vibratoDepth = 4, 205 | vowel = 0, 206 | att = 0.01, 207 | rel = 0.1, 208 | lag = 1, 209 | gate = 1; 210 | 211 | var in, vibrato, env, va, ve, vi, vo, vu, snd; 212 | 213 | vibrato = SinOsc.kr(vibratoSpeed, mul: vibratoDepth); 214 | in = Saw.ar(Lag.kr(freq, lag) + vibrato); 215 | env = EnvGen.kr(Env.asr(att, 1, rel), gate, doneAction: 2); 216 | 217 | va = BBandPass.ar( 218 | in: in, 219 | freq: [ 600, 1040, 2250, 2450, 2750 ], 220 | bw: [ 0.1, 0.067307692307692, 0.048888888888889, 0.048979591836735, 0.047272727272727 ], 221 | mul: [ 1, 0.44668359215096, 0.35481338923358, 0.35481338923358, 0.1 ]); 222 | 223 | ve = BBandPass.ar( 224 | in: in, 225 | freq: [ 400, 1620, 2400, 2800, 3100 ] , 226 | bw: [ 0.1, 0.049382716049383, 0.041666666666667, 0.042857142857143, 0.038709677419355 ], 227 | mul: [ 1, 0.25118864315096, 0.35481338923358, 0.25118864315096, 0.12589254117942 ]); 228 | 229 | vi = BBandPass.ar( 230 | in: in, 231 | freq: [ 250, 1750, 2600, 3050, 3340 ] , 232 | bw: [ 0.24, 0.051428571428571, 0.038461538461538, 0.039344262295082, 0.035928143712575 ], 233 | mul: [ 1, 0.031622776601684, 0.15848931924611, 0.079432823472428, 0.03981071705535 ] ); 234 | 235 | vo = BBandPass.ar( 236 | in: in, 237 | freq:[ 400, 750, 2400, 2600, 2900 ] , 238 | bw: [ 0.1, 0.10666666666667, 0.041666666666667, 0.046153846153846, 0.041379310344828 ], 239 | mul: [ 1, 0.28183829312645, 0.089125093813375, 0.1, 0.01 ]); 240 | 241 | vu = BBandPass.ar( 242 | in: in, 243 | freq: [ 350, 600, 2400, 2675, 2950 ], 244 | bw: [ 0.11428571428571, 0.13333333333333, 0.041666666666667, 0.044859813084112, 0.040677966101695 ], 245 | mul: [ 1, 0.1, 0.025118864315096, 0.03981071705535, 0.015848931924611 ]); 246 | 247 | snd = SelectX.ar(Lag.kr(vowel, lag), [va, ve, vi, vo, vu]); 248 | snd = Mix.new(snd); 249 | Out.ar(0, snd!2 * env * amp); 250 | }).add; 251 | 252 | SynthDef("plucking", {arg amp = 0.1, freq = 440, decay = 5, coef = 0.1; 253 | var env, snd; 254 | env = EnvGen.kr(Env.linen(0, decay, 0), doneAction: 2); 255 | snd = Pluck.ar( 256 | in: WhiteNoise.ar(amp), 257 | trig: Impulse.kr(0), 258 | 259 | maxdelaytime: 0.1, 260 | delaytime: freq.reciprocal, 261 | decaytime: decay, 262 | coef: coef); 263 | Out.ar(0, [snd, snd]); 264 | }).add; 265 | 266 | SynthDef("defaultB", { arg out=0, freq=440, amp=0.1, pan=0, gate=1; 267 | var z; 268 | z = LPF.ar( 269 | Mix.new(VarSaw.ar(freq + [0, Rand(-0.4,0.0), Rand(0.0,0.4)], 0, 0.3)), 270 | XLine.kr(Rand(4000,5000), Rand(2500,3200), 1) 271 | ) * Linen.kr(gate, 0.01, 0.7, 0.3, 2); 272 | OffsetOut.ar(out, Pan2.ar(z, pan, amp)); 273 | }, [\ir]).add; 274 | 275 | SynthDef("trig_demo", { |freq = 440, gate = 1, t_trig = 1| 276 | var env, sig; 277 | env = Decay2.kr(t_trig, 0.01, 0.1); 278 | sig = SinOsc.ar(freq, 0, env); 279 | sig = sig * Linen.kr(gate, 0.01, 0.1, 0.1, doneAction: 2); 280 | Out.ar(0, sig ! 2) 281 | }).add; 282 | 283 | SynthDef("marimba1", {arg freq = 440, amp = 0.4; 284 | var snd, env; 285 | env = Env.linen(0.015, 1, 0.5, amp).kr(doneAction: 2); 286 | snd = BPF.ar(Saw.ar(0), freq, 0.02); 287 | snd = BLowShelf.ar(snd, 220, 0.81, 6); 288 | snd = snd * env; 289 | Out.ar(0, Splay.ar(snd)); 290 | }).add; 291 | 292 | SynthDef("trianglewavebells",{ 293 | arg out = 0, pan = 0.0, freq = 440, amp = 1.0, gate = 1, att = 0.01, dec = 0.1, sus = 1, rel = 0.5, lforate = 10, lfowidth = 0.0, cutoff = 100, rq = 0.5; 294 | 295 | var osc1, osc2, vibrato, filter, env; 296 | vibrato = SinOsc.ar(lforate, Rand(0, 2.0)); 297 | osc1 = Saw.ar(freq * (1.0 + (lfowidth * vibrato)), 0.75); 298 | osc2 = Mix(LFTri.ar((freq.cpsmidi + [11.9, 12.1]).midicps)); 299 | filter = RHPF.ar((osc1 + (osc2 * 0.5)) * 0.5, cutoff, rq); 300 | env = EnvGen.ar( 301 | envelope: Env.adsr(att, dec, sus, rel, amp), 302 | gate: gate, 303 | doneAction: 2); 304 | Out.ar(out, Pan2.ar(filter * env, pan)); 305 | }).add; 306 | 307 | 308 | SynthDef("organdonor",{ 309 | arg out = 0, pan = 0.0, freq = 440, amp = 0.1, gate = 1, att = 0.01, dec = 0.5, sus = 1, rel = 0.5, lforate = 10, lfowidth = 0.01, cutoff = 100, rq = 0.5; 310 | 311 | var vibrato, pulse, filter, env; 312 | vibrato = SinOsc.ar(lforate, Rand(0, 2.0)); 313 | // up octave, detune by 4 cents 314 | // 11.96.midiratio = 1.9953843530485 315 | // up octave and a half, detune up by 10 cents 316 | // 19.10.midiratio = 3.0139733629359 317 | freq = freq * [1, 1.9953843530485, 3.0139733629359]; 318 | freq = freq * (1.0 + (lfowidth * vibrato)); 319 | pulse = VarSaw.ar( 320 | freq: freq, 321 | iphase: Rand(0.0, 1.0) ! 3, 322 | width: Rand(0.3, 0.5) ! 3, 323 | mul: [1.0,0.7,0.3]); 324 | pulse = Mix(pulse); 325 | filter = RLPF.ar(pulse, cutoff, rq); 326 | env = EnvGen.ar( 327 | envelope: Env.adsr(att, dec, sus, rel, amp), 328 | gate: gate, 329 | doneAction: 2); 330 | Out.ar(out, Pan2.ar(filter * env, pan)); 331 | }).add; 332 | 333 | SynthDef(\mario, { |out, amp=0.3, freq=440, att=0.001, sustain=0.3, rel=0.03, dur=1| 334 | var snd; 335 | snd = LFPulse.ar(freq)!2; 336 | snd = snd * EnvGen.ar(Env.linen(att, sustain * 0.5, rel), doneAction:2); 337 | OffsetOut.ar(out, snd*amp*0.5); 338 | }).add; 339 | -------------------------------------------------------------------------------- /SuperCollider/examples/windwaker.scd: -------------------------------------------------------------------------------- 1 | ( 2 | 3 | //MIDIClient.init; 4 | //MIDIClient.destinations; 5 | 6 | b = " 7 | 8 | 9 | 10 | @MIDIOut.new<0> => @midiout 11 | @midi => @type 12 | 13 | 14 | 15 | -1 => @transpose 16 | 17 | 9/8 120 => ). 18 | 19 | mf 20 | 21 | .mel | ottava alta }}} o/ | }}} o/ | }}} o/ | }}} o/ | 22 | 23 | .mel | _a) d] f#) e] d) c#] | d) _b] _g) c#] _a] d] _b] | 24 | .mel | c#) _a] _g) d] _b) c#] | d) e]] ]] f#] d] e] _a) ] | 25 | .mel | _a) d]] e]] f#) e] d) c#] | d) _b] _g) c#] _a] d] _b] | 26 | .mel | c#) d] e) f#]] ]] g] e] c#] | d) oo/ e]] d). _a) ] | 27 | 28 | .mel | _a) d]] e]] f#) e] d) c#] | e]] d]. _b] _g) c#] _a] d] _b] | c#) _a] _g) d] _b) c#] | ]] d]] e]] ]] f#] d] e] _a) ] | 29 | .mel | _a) d]] e]] f#) e] d) c#] | d) _b] _g) c#] _a] d] _b] | c#) d] e) f#]] ]] g] e] c#] | d) oo/ e]] d). a) ] | 30 | 31 | .mel |: g] f#] e] f#) d] c#] d] e] | a] d] ] g] d] ] f#) ] | g] a] b] b] g] e] a) a] | g] f#] d] e] f#] e]] f#]] e) ] | 32 | .mel | d] c#] d] e) e] a] g] c#] | g] d] ] f#) ] e] c#] e] | d] b] d] g] a] b] f# d] g] | e). ] f#] e] a) ] :| 33 | 34 | .mel | <_a,_c#,d> )). }. | d )). }. | <_a,_c#,d> )). }. | <_a,_f#> )). _a ) ] | 35 | 36 | ".skoar; 37 | 38 | 39 | 40 | 41 | 42 | ) -------------------------------------------------------------------------------- /SuperCollider/examples/yay.scd: -------------------------------------------------------------------------------- 1 | (" 2 | pp 3 | 60 => ) 4 | <_c, _e, _a, c, e, a, f> => @notes 5 | 6 | .b o~ 7 | .c o~~ mf 8 | 9 | {! foo !! 10 | .a !notes.choose {: ] } } ]] :: !x times :} 11 | .b !notes.choose {: ] :: !x times :} 12 | .c !notes.choose {: ) :: !x times :} 13 | !} 14 | 15 | {: !foo<<1,2,3>.choose> :: true :} 16 | 17 | ".skoar.play; 18 | ) 19 | 20 | -------------------------------------------------------------------------------- /SuperCollider/examples/zelda.scd: -------------------------------------------------------------------------------- 1 | // First load the synthdefs from examples/synthdefs.scd" 2 | 3 | ( 4 | x = " 5 | 6 | 7 | 130 => ) 8 | 9 | .alice @default => @instrument [##### ] => @amp 10 | .bob @default => @instrument [##### ] => @amp 11 | .bass @sawpulse => @instrument [### ] => @amp o~~~~ 12 | .hats @hats => @instrument [## ] => @amp 13 | .snare @snare => @instrument [## ] => @amp 14 | .kick @kick => @instrument [### ] => @amp 15 | 16 | {! bass_end !! !x ) ) ) ] ] !} 17 | {! bass_climb !! | _e ]] _a# ]] c# ] e ]] a# ]] ~o c# ] e ) } | f ) o~ _f ]] ]] ] ) } | !} 18 | 19 | {! bassline_a !! 20 | .{: .) ]] ]] ] ) ) :} 21 | !bass_end 22 | !} 23 | 24 | {! bassline_b !! 25 | .{: ) ]] ]] ] ) ) :} 26 | 27 | !bass_climb !bass_climb 28 | 29 | .{: ) ]] ]] ] ) ) :} !bass_end 30 | !} 31 | 32 | 33 | {! intro !! 34 | 35 | .hats {: }}} :: 4 times :} 36 | .snare {: }}} :: 4 times :} 37 | .kick {: }}} :: 4 times :} 38 | 39 | .alice | _a# )) o/. ]] ]] ]] ] | ]. _g# ]] _a# ) o/. ]] ]] ]] ] | 40 | .bob | _d )) o/. ]] ]] ]] ] | _c ]. ]] ) o/. ]] ]] ]] ] | 41 | .bass | a# ) ]] ]] ] ) ]] ]] ] | g# ) ]] ]] ] ) ]] ]] ] | 42 | 43 | .alice | ]. _g# ]] _a# ) o/. ]] ]] ]] ] | ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 44 | .bob | _c# ]. ]] ) o/. ]] ]] ]] ] | ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] | 45 | .bass | f# ) ]] ]] ] ) ]] ]] ] | f ) ) ) g ] a ] | 46 | !} 47 | 48 | {! melody_a !! 49 | 50 | .bass !bassline_a 51 | 52 | .hats {: }}} :: 7 times :} | ] ] ] ] ] ] ] ] | 53 | .snare {: }}} :: 8 times :} 54 | .kick {: }}} :: 8 times :} 55 | 56 | .alice | _a# ) _f )__ o/. _a# ]] ]] c ]] d ]] d# ]] | 57 | .bob | _d ) ]] ]] _c ] _d ]. ]] ]] _d# ]] _f ]] _g ]] | 58 | 59 | .alice | f )) o/ ] f ] f# ]] g# ]] | 60 | .bob | _g# ]. _a# ]] ]] c ]] d ]] d# ]] f ) _g# ] _a# ]] c ]] | 61 | 62 | .alice | a# )) o/ a# ] ] g# ]] f# ]] | 63 | .bob | c# ]. _f# ]] ]] _g# ]] _a# ]] c ]] c# ]. ]] ] c ]] _a# ]] | 64 | 65 | .alice | g# ]. f# ]] f )) ) | 66 | .bob | c# ]. _g# ]] ]] ]] _f# ] _g# ]. ]] ]] _f# ]] _g# ] | 67 | 68 | .alice | d# ] ]] f ]] f# )) f ] d# ] | 69 | .bob | _f# ] ]] _f ]] _f# ] ]] _g# ]] _a# ) _g# ] _f# ] | 70 | 71 | .alice | c# ] ]] d# ]] f )) d# ] c# ] | 72 | .bob | _f ] ]] _d# ]] _f ] ]] _f# ]] _g# ) _f# ] _d# ] | 73 | 74 | .alice | c ] ]] d ]] e )) g ) | 75 | .bob | _e ] ]] _d ]] _e ] ]] _g ] ]] _a ]] ]] _a# ] c ] | 76 | 77 | .alice | f ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 78 | .bob | _a ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] ~o | 79 | 80 | !} 81 | 82 | 83 | {! melody_b !! 84 | 85 | .bass !bassline_b 86 | 87 | .hats {: ] ] ] ] ] ] ] ]] ]] :: 12 times :} 88 | .kick {: ) } ) } :: 12 times :} 89 | .snare {: } ) } ) :: 11 times :} | ] ]] ]] ] ]] ]] ] ] | 90 | 91 | .alice | _a# ) _f ) o/. _a# ]] ]] c ]] d ]] d# ]] | 92 | .bob | _d ) ]] ]] _c ] _d ]. ]] ]] _d# ]] _f ]] _g ]] | 93 | 94 | .alice | f )) o/ ] f ] f# ]] g# ]] | 95 | .bob | _g# ]. _a# ]] ]] c ]] d ]] d# ]] f ) _g# ] _a# ]] c ]] | 96 | 97 | .alice | a# )). ~o c# ) | c ) o~ a )) f ) | f# )). a# ) | a ) f )) ) | 98 | .bob | c# )). e ) | d# ) c )) _a ) | _b )). c# ) | c ) _a )) ) | 99 | 100 | .alice | f# )). a# ) | a ) f )) d ) | d# )). f# ) | f ) c# )) _a# ) | 101 | .bob | _b )). c# ) | c ) _a )) ) | _f# )). _b ) | _a# ) _f )) _c# ) | 102 | 103 | .alice | c ] ]] d ]] e )) g ) | 104 | .bob | _e ] ]] _d ]] _e ] ]] _f ]] _g ] ]] _a ]] _a# ] c ] | 105 | 106 | .alice | f ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 107 | .bob | _a ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] ~o | 108 | 109 | !} 110 | 111 | {! fill !! 112 | .alice | f ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 113 | .bob | _a ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] ~o | 114 | .snare | ] ]] ]] ] ]] ]] ] ]] ]] ] ] | 115 | .hats | ] ] ] ] ] ] ] ] | 116 | .kick | ) } ) ) | 117 | .bass !bass_end 118 | !} 119 | 120 | !intro 121 | !melody_a 122 | !fill 123 | !melody_b 124 | !fill 125 | 126 | ".skoar; 127 | ) 128 | 129 | x.play; 130 | -------------------------------------------------------------------------------- /SuperCollider/testing/bigskoar.scd: -------------------------------------------------------------------------------- 1 | 2 | SynthDef(\sawpulse, { |out, freq = 440, gate = 0.5, plfofreq = 6, mw = 0, 3 | ffreq = 2000, rq = 0.3, freqlag = 0.05, amp = 1| 4 | var sig, plfo, fcurve; 5 | plfo = SinOsc.kr(plfofreq, mul:mw, add:1); 6 | freq = Lag.kr(freq, freqlag) * plfo; 7 | fcurve = EnvGen.kr(Env.adsr(0, 0.3, 0.1, 20), gate); 8 | fcurve = (fcurve - 1).madd(0.7, 1) * ffreq; 9 | sig = Mix.ar([Pulse.ar(freq, 0.9), Saw.ar(freq*1.007)]); 10 | sig = RLPF.ar(sig, fcurve, rq) 11 | * EnvGen.kr(Env.adsr(0.04, 0.2, 0.6, 0.1), gate, doneAction:2) 12 | * amp; 13 | Out.ar(out, sig ! 2) 14 | }).add; 15 | 16 | // kick ------- 17 | // http://www.soundonsound.com/sos/jan02/articles/synthsecrets0102.asp 18 | // increase mod_freq and mod_index for interesting electronic percussion 19 | 20 | SynthDef(\kick, 21 | { arg out = 0, freq = 50, mod_freq = 5, mod_index = 5, sustain = 0.4, amp = 0.8, beater_noise_level = 0.025; 22 | var pitch_contour, drum_osc, drum_lpf, drum_env; 23 | var beater_source, beater_hpf, beater_lpf, lpf_cutoff_contour, beater_env; 24 | var kick_mix; 25 | 26 | // hardcoding, otherwise skoar will set to the length of the noat ) ] ]]] etc 27 | sustain = 0.4; 28 | freq = 50; 29 | 30 | pitch_contour = Line.kr(freq*2, freq, 0.02); 31 | drum_osc = PMOsc.ar( pitch_contour, 32 | mod_freq, 33 | mod_index/1.3, 34 | mul: 1, 35 | add: 0); 36 | drum_lpf = LPF.ar(in: drum_osc, freq: 1000, mul: 1, add: 0); 37 | drum_env = drum_lpf * EnvGen.ar(Env.perc(0.005, sustain), 1.0, doneAction: 2); 38 | beater_source = WhiteNoise.ar(beater_noise_level); 39 | beater_hpf = HPF.ar(in: beater_source, freq: 500, mul: 1, add: 0); 40 | lpf_cutoff_contour = Line.kr(6000, 500, 0.03); 41 | beater_lpf = LPF.ar(in: beater_hpf, freq: lpf_cutoff_contour, mul: 1, add: 0); 42 | beater_env = beater_lpf * EnvGen.ar(Env.perc, 1.0, doneAction: 2); 43 | kick_mix = Mix.new([drum_env, beater_env]) * 2 * amp; 44 | Out.ar(out, [kick_mix, kick_mix]) 45 | }).store; 46 | 47 | 48 | // snare ------- 49 | // http://www.soundonsound.com/sos/Mar02/articles/synthsecrets0302.asp 50 | SynthDef(\snare, 51 | {arg out = 0, sustain = 0.1, drum_mode_level = 0.25, 52 | snare_level = 40, snare_tightness = 1000, 53 | freq = 405, amp = 0.8; 54 | var drum_mode_sin_1, drum_mode_sin_2, drum_mode_pmosc, drum_mode_mix, drum_mode_env; 55 | var snare_noise, snare_brf_1, snare_brf_2, snare_brf_3, snare_brf_4, snare_reson; 56 | var snare_env; 57 | var snare_drum_mix; 58 | 59 | sustain = 0.1; 60 | freq = 405; 61 | 62 | drum_mode_env = EnvGen.ar(Env.perc(0.005, sustain), 1.0, doneAction: 2); 63 | drum_mode_sin_1 = SinOsc.ar(freq*0.53, 0, drum_mode_env * 0.5); 64 | drum_mode_sin_2 = SinOsc.ar(freq, 0, drum_mode_env * 0.5); 65 | drum_mode_pmosc = PMOsc.ar( Saw.ar(freq*0.85), 66 | 184, 67 | 0.5/1.3, 68 | mul: drum_mode_env*5, 69 | add: 0); 70 | drum_mode_mix = Mix.new([drum_mode_sin_1, drum_mode_sin_2, drum_mode_pmosc]) * drum_mode_level; 71 | 72 | snare_noise = LFNoise0.ar(20000, 0.1); 73 | snare_env = EnvGen.ar(Env.perc(0.005, sustain), 1.0, doneAction: 2); 74 | snare_brf_1 = BRF.ar(in: snare_noise, freq: 8000, mul: 0.5, rq: 0.1); 75 | snare_brf_2 = BRF.ar(in: snare_brf_1, freq: 5000, mul: 0.5, rq: 0.1); 76 | snare_brf_3 = BRF.ar(in: snare_brf_2, freq: 3600, mul: 0.5, rq: 0.1); 77 | snare_brf_4 = BRF.ar(in: snare_brf_3, freq: 2000, mul: snare_env, rq: 0.0001); 78 | snare_reson = Resonz.ar(snare_brf_4, snare_tightness, mul: snare_level) ; 79 | snare_drum_mix = Mix.new([drum_mode_mix, snare_reson]) * 5 * amp; 80 | Out.ar(out, [snare_drum_mix, snare_drum_mix]); 81 | }).store; 82 | 83 | // hats ------- 84 | // http://www.soundonsound.com/sos/Jun02/articles/synthsecrets0602.asp 85 | SynthDef(\hats, 86 | {arg out = 0, freq = 6000, sustain = 0.1, amp = 0.8; 87 | var root_cymbal, root_cymbal_square, root_cymbal_pmosc; 88 | var initial_bpf_contour, initial_bpf, initial_env; 89 | var body_hpf, body_env; 90 | var cymbal_mix; 91 | 92 | amp = amp * 0.5; 93 | sustain = 0.1; 94 | freq = 6000; 95 | 96 | root_cymbal_square = Pulse.ar(freq, 0.5, mul: 1); 97 | root_cymbal_pmosc = PMOsc.ar(root_cymbal_square, 98 | [freq*1.34, freq*2.405, freq*3.09, freq*1.309], 99 | [310/1.3, 26/0.5, 11/3.4, 0.72772], 100 | mul: 1, 101 | add: 0); 102 | root_cymbal = Mix.new(root_cymbal_pmosc); 103 | initial_bpf_contour = Line.kr(15000, 9000, 0.1); 104 | initial_env = EnvGen.ar(Env.perc(0.005, 0.1), 1.0); 105 | initial_bpf = BPF.ar(root_cymbal, initial_bpf_contour, mul:initial_env); 106 | body_env = EnvGen.ar(Env.perc(0.005, sustain, 1, -2), 1.0, doneAction: 2); 107 | body_hpf = HPF.ar(in: root_cymbal, freq: Line.kr(9000, 12000, sustain),mul: body_env, add: 0); 108 | cymbal_mix = Mix.new([initial_bpf, body_hpf]) * amp; 109 | Out.ar(out, [cymbal_mix, cymbal_mix]) 110 | }).store; 111 | 112 | x = " 113 | 114 | 130 => ) 115 | 116 | .alice <0,3,5> => @detune mp 117 | .bob <0,3,5> => @detune mp 118 | .bass @sawpulse => @instrument mp o~~~~ 119 | .hats @hats => @instrument pp 120 | .snare @snare => @instrument mf 121 | .kick @kick => @instrument mf 122 | 123 | {! four_bars_rest !! }}}}} !} 124 | {! eight_bars_rest !! }}}}}} !} 125 | {! twelve_bars_rest !! !four_bars_rest !eight_bars_rest !} 126 | 127 | {! bass_fun !! !x ) ]] ]] ] ) ) !} 128 | 129 | {! bass_end !! !x ) ) ) ] ] !} 130 | {! bass_climb !! | _e ]] _a# ]] c# ] e ]] a# ]] ~o c# ] e ) } | f ) o~ _f ]] ]] ] ) } | !} 131 | 132 | {! bassline_a !! 133 | !bass_fun 134 | !bass_fun 135 | !bass_fun 136 | !bass_fun 137 | 138 | !bass_fun 139 | !bass_fun 140 | !bass_fun 141 | !bass_end 142 | !} 143 | 144 | {! bassline_b !! 145 | !bass_fun 146 | !bass_fun 147 | !bass_fun 148 | !bass_fun 149 | 150 | !bass_climb 151 | !bass_climb 152 | 153 | !bass_fun 154 | !bass_fun 155 | !bass_fun 156 | !bass_end 157 | 158 | !} 159 | 160 | {! intro !! 161 | 162 | .hats !four_bars_rest 163 | .snare !four_bars_rest 164 | .kick !four_bars_rest 165 | 166 | .alice | _a# )) o/. ]] ]] ]] ] | ]. _g# ]] _a# ) o/. ]] ]] ]] ] | 167 | .bob | _d )) o/. ]] ]] ]] ] | _c ]. ]] ) o/. ]] ]] ]] ] | 168 | .bass | a# ) ]] ]] ] ) ]] ]] ] | g# ) ]] ]] ] ) ]] ]] ] | 169 | 170 | .alice | ]. _g# ]] _a# ) o/. ]] ]] ]] ] | ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 171 | .bob | _c# ]. ]] ) o/. ]] ]] ]] ] | ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] | 172 | .bass | f# ) ]] ]] ] ) ]] ]] ] | f ) ) ) g ] a ] | 173 | !} 174 | 175 | {! melody_a !! .bass !bassline_a 176 | 177 | .alice | _a# ) _f )__ o/. _a# ]] ]] c ]] d ]] d# ]] | 178 | .bob | _d ) ]] ]] _c ] _d ]. ]] ]] _d# ]] _f ]] _g ]] | 179 | 180 | .alice | f )) o/ ] f ] f# ]] g# ]] | 181 | .bob | _g# ]. _a# ]] ]] c ]] d ]] d# ]] f ) _g# ] _a# ]] c ]] | 182 | 183 | .alice | a# )) o/ a# ] ] g# ]] f# ]] | 184 | .bob | c# ]. _f# ]] ]] _g# ]] _a# ]] c ]] c# ]. ]] ] c ]] _a# ]] | 185 | 186 | .alice | g# ]. f# ]] f )) ) | 187 | .bob | c# ]. _g# ]] ]] ]] _f# ] _g# ]. ]] ]] _f# ]] _g# ] | 188 | 189 | .alice | d# ] ]] f ]] f# )) f ] d# ] | 190 | .bob | _f# ] ]] _f ]] _f# ] ]] _g# ]] _a# ) _g# ] _f# ] | 191 | 192 | .alice | c# ] ]] d# ]] f )) d# ] c# ] | 193 | .bob | _f ] ]] _d# ]] _f ] ]] _f# ]] _g# ) _f# ] _d# ] | 194 | 195 | .alice | c ] ]] d ]] e )) g ) | 196 | .bob | _e ] ]] _d ]] _e ] ]] _g ] ]] _a ]] _a# ] c ] | 197 | 198 | .alice | f ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 199 | .bob | _a ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] ~o | 200 | 201 | !} 202 | 203 | {! melody_b !! .bass !bassline_b 204 | 205 | .alice | _a# ) _f )__ o/. _a# ]] ]] c ]] d ]] d# ]] | 206 | .bob | _d ) ]] ]] _c ] _d ]. ]] ]] _d# ]] _f ]] _g ]] | 207 | 208 | .alice | f )) o/ ] f ] f# ]] g# ]] | 209 | .bob | _g# ]. _a# ]] ]] c ]] d ]] d# ]] f ) _g# ] _a# ]] c ]] | 210 | 211 | .alice | a# )). ~o c# ) | c ) o~ a )) f ) | f# )). a# ) | a ) f )) ) | 212 | .bob | c# )). e ) | d# ) c )) _a ) | _b )). c# ) | c ) _a )) ) | 213 | 214 | .alice | f# )). a# ) | a ) f )) d ) | d# )). f# ) | f ) c# )) _a# ) | 215 | .bob | _b )). c# ) | c ) _a )) ) | _f# )). _b ) | _a# ) _f )) _c# ) | 216 | 217 | .alice | c ] ]] d ]] e )) g ) | 218 | .bob | _e ] ]] _d ]] _e ] ]] _f ]] _g ] ]] _a ]] _a# ] c ] | 219 | 220 | .alice | f ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 221 | .bob | _a ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] ~o | 222 | 223 | !} 224 | 225 | {! fill !! 226 | .alice | f ] _f ]] ]] ] ]] ]] ] ]] ]] ] ] | 227 | .bob | _a ] o~ _a ]] ]] ] ]] ]] ] ]] ]] ] ] ~o | 228 | .snare | ] ]] ]] ] ]] ]] ] ]] ]] ] ] | 229 | .hats | ] ] ] ] ] ] ] ] | 230 | .kick | ) } ) } | 231 | .bass !bass_end 232 | !} 233 | 234 | {! drums !! 235 | .hats |: ] ] ] ] ] ] ] ]] ]] :| :| :| :| :| :| :| :| :| :| :| 236 | .snare |: } ) } ) :| :| :| :| :| :| :| :| :| :| ] ]] ]] ] ]] ]] ] ]] ]] ] ] | 237 | .kick |: ) } ) } :| :| :| :| :| :| :| :| :| :| :| 238 | !} 239 | 240 | !intro 241 | !melody_a 242 | 243 | .kick !eight_bars_rest 244 | .hats !four_bars_rest }}} }}} }}} ] ] ] ] ] ] ] ] 245 | .snare !eight_bars_rest 246 | !fill 247 | 248 | !melody_b 249 | !drums 250 | 251 | !fill 252 | 253 | "; 254 | 255 | for (0, 60, {x.skoar;}); 256 | 257 | -------------------------------------------------------------------------------- /SuperCollider/testing/conditionals.scd: -------------------------------------------------------------------------------- 1 | ( 2 | " 3 | {: _a, _c, c, _e, e, _a :: ]]] ooo/ :} 4 | 5 | <_a, _c, c, _e, e, _a>.{: ]]] ooo/ :} 6 | 7 | 8 | ".skoar.play; 9 | ) 10 | 11 | ( 12 | " 13 | .h @hats => @instrument ]] D.C. 14 | .s @snare => @instrument } ) D.C. 15 | .k @kick => @instrument ) D.C. 16 | 17 | .a {: _a, _c, c, _e, e, _a :: ]]] ooo/ :} 18 | 19 | .a {? 10.rand <= 5 ?? 0 ]] ]] ?? 4 ] ?} ] 20 | 21 | 22 | .a {? 10.rand == 5 ?? a ] ] ] ] ]] ] ]] ?? ] c] }} ?} 23 | 24 | .a {? 10.rand >= 5 ?? e] ] ] ] ]] ] ]] ?? }} 25 | 10.rand <= 6 ?? ] ] ] f] ]] ] ]] ?? } ) 26 | 11.rand <= 3 ?? ] c] }} ?} 27 | 28 | ".skoar.play; 29 | ) 30 | 31 | ArrayedCollection 32 | ( 33 | "{? 5 <= 10.rand ?? a] ?? c] ?}".skoar.play; 34 | ) 35 | 36 | 37 | ("{? 10.rand >= 5 ?? ] ] ] o/ ]] ] ]] ?? }} 38 | 10.rand <= 6 ?? ] ] ] ] ]] ] ]] ?? } ) 39 | 11.rand <= 3 ?? ] ] }} ?} D.C.".skoar.play; 40 | ) 41 | 42 | 43 | (" 44 | 120 => ) 45 | 46 | .hats @hats => @instrument 47 | .snare @snare => @instrument 48 | .kick @kick => @instrument 49 | 50 | .hats |: ] ] ] ] ] ] ] ]] ]] :| :| :| :| :| :| :| :| :| :| :| 51 | .snare |: } ) } ) :| :| :| :| :| :| :| :| :| :| ] ]] ]] ] ]] ]] ] ]] ]] ] ] | 52 | .kick |: ) } ) } :| :| :| :| :| :| :| :| :| :| :| 53 | 54 | ".skoar.play) 55 | 56 | 57 | 58 | ( 59 | " 60 | ,segno` 61 | {! f !! 62 | |: a ] | 63 | | c# ]] ]] 64 | | b ] | fine D.S. al fine !} 65 | 66 | !f 67 | ".skoar.draw_skoarpions.play; 68 | ) 69 | 70 | ( 71 | " 72 | {! f !! !x ] 2 ] 4 ]!} 73 | 74 | !f<4> 75 | ".skoar.draw_skoarpions.play; 76 | ) 77 | -------------------------------------------------------------------------------- /Testing/SC_tests.playlist: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Testing/Skoarcery.playlist: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /build.py: -------------------------------------------------------------------------------- 1 | from Skoarcery.factoary.Build_Sc import Build_Sc 2 | 3 | if __name__ == '__main__': 4 | b = Build_Sc() 5 | b.build() 6 | 7 | #b.sanity() 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /examples.md: -------------------------------------------------------------------------------- 1 | Skoar Examples 2 | ============== 3 | 4 | # MIDI example - [listen on soundcloud](https://soundcloud.com/lucas-cornelisse/windwaker-sv1) 5 | 6 | 7 | 8 | @midi => @type 9 | -1 => @transpose 10 | 11 | 9/8 120 => ). 12 | mp 13 | 14 | | <_a,_c#,d> )). }. | d )). }. | <_a,_c#,d> )). }. | _a )). }. | 15 | 16 | | _a) d] f#) e] d) c#] | d) _b] _g) c#] _a] d] _b] | c#) _a] _g) d] _b) c#] | d) e]] ]] f#] d] e] _a) ] | 17 | | _a) d]] e]] f#) e] d) c#] | d) _b] _g) c#] _a] d] _b] | c#) d] e) f#]] ]] g] e] c#] | d) oo/ e]] d). _a) ] | 18 | | _a) d]] e]] f#) e] d) c#] | e]] d]. _b] _g) c#] _a] d] _b] | c#) _a] _g) d] _b) c#] | ]] d]] e]] ]] f#] d] e] _a) ] | 19 | | _a) d]] e]] f#) e] d) c#] | d) _b] _g) c#] _a] d] _b] | c#) d] e) f#]] ]] g] e] c#] | d) oo/ e]] d). a) ] | 20 | 21 | |: g] f#] e] f#) d] c#] d] e] | a] d] ] g] d] ] f#) ] | g] a] b] b] g] e] a) a] | g] f#] d] e] f#] e]] f#]] e) ] | 22 | | d] c#] d] e) e] a] g] c#] | g] d] ] f#) ] e] c#] e] | d] b] d] g] a] b] f# d] g] | e). ] f#] e] a) ] :| 23 | 24 | | <_a,_c#,d> )). }. | d )). }. | <_a,_c#,d> )). }. | <_a,_f#> )). _a ) ] | 25 | 26 | This was played over MIDI to my Korg SV1. 27 | 28 | # Drumming example - [listen on soundcloud](https://soundcloud.com/lucas-cornelisse/beets) 29 | 30 | 31 | 32 | 4/4 70 => ) 33 | 34 | 35 | 36 | .h @hats => @instrument 37 | .s @snare => @instrument forte 38 | .k @kick => @instrument 39 | 40 | .h | }}} | 41 | .s | } ) } ) | 42 | .k | ) } ) } | 43 | 44 | 45 | .h |: ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] :| 46 | .s |: } ) } ) :| 47 | .k |: ) o/. ]] oo/ ]] ]] oo/ } :| 48 | 49 | .h |: ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] :| 50 | .s |: } ) } ) :| 51 | .k |: ]]. ]]. ]] o/ ]] ]] } o/ ] :| 52 | 53 | 54 | .h |: ]] ]] ]] ]] ]] ]] ]] ]]] ]]] ]] ]]] ]]] ]] ]] ]] ]] ]] ]] :| 55 | .s |: } ) } ]. ]] :| 56 | .k |: ] ]] ]] o/ ]] ]] o/ ] o/ ] :| 57 | 58 | .h |: ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]]] ]]] ]]] ]]] :| 59 | .s |: } ) } ]. ]] :| 60 | .k |: ]. ]] oo/ ]. o/ ] } :| 61 | 62 | 63 | .h |: ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] :| 64 | .s |: } ) } ]]. ]]. ]] :| 65 | .k |: ]]. ]]. ]] } ]]. ]]. ]] } :| 66 | 67 | .h |: ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] :| 68 | .s |: } ) } ) :| 69 | .k |: ]]. ]]. ]] o/. ]] ]] o/ ]] } :| 70 | 71 | 72 | .h |: ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] ]] :| 73 | .s |: } ]]. ]]. ]] } ]. ]] :| 74 | .k |: ) } ] ] } :| 75 | 76 | .h |: ]]] ]]] ]]] ]]] ]] ]] ]] ]] ]] ]]] ]]] ]] ]]] ]]] ]] ]] ]] ]] ]] ]] :| 77 | .s |: } ) } ) :| 78 | .k |: ] ] } o/ ] oo/ ]. :| 79 | 80 | 81 | .h | ))) | 82 | .s | ))) | 83 | .k | ))) | 84 | -------------------------------------------------------------------------------- /sanity.py: -------------------------------------------------------------------------------- 1 | from Skoarcery.factoary.Build_Sc import Build_Sc 2 | 3 | if __name__ == '__main__': 4 | b = Build_Sc() 5 | b.sanity() 6 | -------------------------------------------------------------------------------- /skoarcery.el: -------------------------------------------------------------------------------- 1 | (require 'json) 2 | 3 | (make-face 'skoarcery-sanity-fail) 4 | (set-face-foreground 'skoarcery-sanity-fail "black") 5 | (set-face-background 'skoarcery-sanity-fail "lightred") 6 | 7 | (make-face 'skoarcery-sanity-pass) 8 | (set-face-foreground 'skoarcery-sanity-pass "black") 9 | (set-face-background 'skoarcery-sanity-pass "lightgreen") 10 | 11 | (defun re-seq (regexp string group) 12 | "Get a list of all regexp matches in a string" 13 | (save-match-data 14 | (let ((pos 0) 15 | matches) 16 | (while (string-match regexp string pos) 17 | (push (match-string group string) matches) 18 | (setq pos (match-end 0)) 19 | ) 20 | matches) 21 | ) 22 | ) 23 | 24 | (defun skoar-build () 25 | (interactive) 26 | (let ((default-directory "~/Documents/GitHub/Skoarcery/")) 27 | (let ((result (shell-command-to-string "python build.py"))) 28 | (with-current-buffer (get-buffer-create "*skoar build*") 29 | (erase-buffer) 30 | (insert "--- skoar build ---") 31 | (insert result) 32 | ) 33 | ) 34 | ) 35 | 36 | (skoar-sanity) 37 | ) 38 | 39 | (defun skoar-sanity () 40 | (interactive) 41 | (let ((default-directory "~/Documents/GitHub/Skoarcery/")) 42 | (let ((result (shell-command-to-string "python sanity.py")) 43 | (outbuf (get-buffer-create "*skoar tests*")) 44 | ) 45 | 46 | (with-current-buffer (get-buffer-create "*skoar sanity*") 47 | (erase-buffer) 48 | (insert "\n--- skoar sanity ---\n") 49 | (insert result) 50 | ) 51 | 52 | ;; clear output buffer and turn on colours 53 | (with-current-buffer outbuf 54 | (font-lock-mode) 55 | (erase-buffer) 56 | ) 57 | 58 | (dolist (jsrc (re-seq "JSON: \\(.*\\)" result 1)) 59 | (with-current-buffer outbuf 60 | (let ((json-object-type 'plist) 61 | (json-array-type 'list)) 62 | (let ((o (json-read-from-string jsrc))) 63 | 64 | (setq test-name (nth 0 (re-seq ".*/testing/\\(.*\\)\\.scd" (plist-get o :test) 1))) 65 | (insert (propertize test-name 'font-lock-face '(:foreground "black" :background "red"))) 66 | (insert "\n") 67 | 68 | ;; make it red 69 | (dolist (failure-line (plist-get o :failures)) 70 | (setq failure (nth 0 (re-seq ".*test_do - \\(.*\\) " failure-line 1))) 71 | 72 | (insert (propertize failure 'font-lock-face '(:foreground "red" :background "black"))) 73 | (insert "\n") 74 | ) 75 | ) 76 | ) 77 | ) 78 | ) 79 | 80 | (dolist (yay (re-seq "Sanity Tests: . OK ." result 0)) 81 | (with-current-buffer outbuf 82 | (insert (propertize yay 'font-lock-face '(:foreground "black" :background "green"))) 83 | (insert "\n") 84 | ) 85 | ) 86 | 87 | ) 88 | ) 89 | ) 90 | 91 | (provide 'skoarcery) 92 | --------------------------------------------------------------------------------