takomusic 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +230 -0
- package/dist/__tests__/checker.test.d.ts +2 -0
- package/dist/__tests__/checker.test.d.ts.map +1 -0
- package/dist/__tests__/checker.test.js +316 -0
- package/dist/__tests__/checker.test.js.map +1 -0
- package/dist/__tests__/compiler.test.d.ts +2 -0
- package/dist/__tests__/compiler.test.d.ts.map +1 -0
- package/dist/__tests__/compiler.test.js +260 -0
- package/dist/__tests__/compiler.test.js.map +1 -0
- package/dist/__tests__/generators.test.d.ts +2 -0
- package/dist/__tests__/generators.test.d.ts.map +1 -0
- package/dist/__tests__/generators.test.js +283 -0
- package/dist/__tests__/generators.test.js.map +1 -0
- package/dist/__tests__/interpreter.test.d.ts +2 -0
- package/dist/__tests__/interpreter.test.d.ts.map +1 -0
- package/dist/__tests__/interpreter.test.js +298 -0
- package/dist/__tests__/interpreter.test.js.map +1 -0
- package/dist/__tests__/lexer.test.d.ts +2 -0
- package/dist/__tests__/lexer.test.d.ts.map +1 -0
- package/dist/__tests__/lexer.test.js +89 -0
- package/dist/__tests__/lexer.test.js.map +1 -0
- package/dist/__tests__/parser.test.d.ts +2 -0
- package/dist/__tests__/parser.test.d.ts.map +1 -0
- package/dist/__tests__/parser.test.js +116 -0
- package/dist/__tests__/parser.test.js.map +1 -0
- package/dist/checker/checker.d.ts +37 -0
- package/dist/checker/checker.d.ts.map +1 -0
- package/dist/checker/checker.js +428 -0
- package/dist/checker/checker.js.map +1 -0
- package/dist/checker/index.d.ts +3 -0
- package/dist/checker/index.d.ts.map +1 -0
- package/dist/checker/index.js +2 -0
- package/dist/checker/index.js.map +1 -0
- package/dist/cli/commands/build.d.ts +2 -0
- package/dist/cli/commands/build.d.ts.map +1 -0
- package/dist/cli/commands/build.js +173 -0
- package/dist/cli/commands/build.js.map +1 -0
- package/dist/cli/commands/check.d.ts +2 -0
- package/dist/cli/commands/check.d.ts.map +1 -0
- package/dist/cli/commands/check.js +79 -0
- package/dist/cli/commands/check.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +2 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +187 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/fmt.d.ts +2 -0
- package/dist/cli/commands/fmt.d.ts.map +1 -0
- package/dist/cli/commands/fmt.js +73 -0
- package/dist/cli/commands/fmt.js.map +1 -0
- package/dist/cli/commands/import.d.ts +2 -0
- package/dist/cli/commands/import.d.ts.map +1 -0
- package/dist/cli/commands/import.js +99 -0
- package/dist/cli/commands/import.js.map +1 -0
- package/dist/cli/commands/init.d.ts +2 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +514 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/play.d.ts +2 -0
- package/dist/cli/commands/play.d.ts.map +1 -0
- package/dist/cli/commands/play.js +216 -0
- package/dist/cli/commands/play.js.map +1 -0
- package/dist/cli/commands/record.d.ts +2 -0
- package/dist/cli/commands/record.d.ts.map +1 -0
- package/dist/cli/commands/record.js +393 -0
- package/dist/cli/commands/record.js.map +1 -0
- package/dist/cli/commands/render.d.ts +2 -0
- package/dist/cli/commands/render.d.ts.map +1 -0
- package/dist/cli/commands/render.js +278 -0
- package/dist/cli/commands/render.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +93 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/compiler/compiler.d.ts +12 -0
- package/dist/compiler/compiler.d.ts.map +1 -0
- package/dist/compiler/compiler.js +146 -0
- package/dist/compiler/compiler.js.map +1 -0
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.d.ts.map +1 -0
- package/dist/compiler/index.js +2 -0
- package/dist/compiler/index.js.map +1 -0
- package/dist/config/config.d.ts +43 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +200 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +2 -0
- package/dist/config/index.js.map +1 -0
- package/dist/errors.d.ts +49 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +168 -0
- package/dist/errors.js.map +1 -0
- package/dist/formatter/formatter.d.ts +13 -0
- package/dist/formatter/formatter.d.ts.map +1 -0
- package/dist/formatter/formatter.js +242 -0
- package/dist/formatter/formatter.js.map +1 -0
- package/dist/formatter/index.d.ts +2 -0
- package/dist/formatter/index.d.ts.map +1 -0
- package/dist/formatter/index.js +2 -0
- package/dist/formatter/index.js.map +1 -0
- package/dist/generators/index.d.ts +5 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +5 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/midi.d.ts +3 -0
- package/dist/generators/midi.d.ts.map +1 -0
- package/dist/generators/midi.js +360 -0
- package/dist/generators/midi.js.map +1 -0
- package/dist/generators/musicxml.d.ts +3 -0
- package/dist/generators/musicxml.d.ts.map +1 -0
- package/dist/generators/musicxml.js +332 -0
- package/dist/generators/musicxml.js.map +1 -0
- package/dist/generators/tempo-midi.d.ts +3 -0
- package/dist/generators/tempo-midi.d.ts.map +1 -0
- package/dist/generators/tempo-midi.js +123 -0
- package/dist/generators/tempo-midi.js.map +1 -0
- package/dist/generators/vsqx.d.ts +3 -0
- package/dist/generators/vsqx.d.ts.map +1 -0
- package/dist/generators/vsqx.js +354 -0
- package/dist/generators/vsqx.js.map +1 -0
- package/dist/importers/index.d.ts +2 -0
- package/dist/importers/index.d.ts.map +1 -0
- package/dist/importers/index.js +3 -0
- package/dist/importers/index.js.map +1 -0
- package/dist/importers/musicxml.d.ts +4 -0
- package/dist/importers/musicxml.d.ts.map +1 -0
- package/dist/importers/musicxml.js +392 -0
- package/dist/importers/musicxml.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/interpreter/builtins/algorithmic.d.ts +12 -0
- package/dist/interpreter/builtins/algorithmic.d.ts.map +1 -0
- package/dist/interpreter/builtins/algorithmic.js +244 -0
- package/dist/interpreter/builtins/algorithmic.js.map +1 -0
- package/dist/interpreter/builtins/audio.d.ts +10 -0
- package/dist/interpreter/builtins/audio.d.ts.map +1 -0
- package/dist/interpreter/builtins/audio.js +169 -0
- package/dist/interpreter/builtins/audio.js.map +1 -0
- package/dist/interpreter/builtins/core.d.ts +15 -0
- package/dist/interpreter/builtins/core.d.ts.map +1 -0
- package/dist/interpreter/builtins/core.js +265 -0
- package/dist/interpreter/builtins/core.js.map +1 -0
- package/dist/interpreter/builtins/dynamics.d.ts +8 -0
- package/dist/interpreter/builtins/dynamics.d.ts.map +1 -0
- package/dist/interpreter/builtins/dynamics.js +86 -0
- package/dist/interpreter/builtins/dynamics.js.map +1 -0
- package/dist/interpreter/builtins/effects.d.ts +16 -0
- package/dist/interpreter/builtins/effects.d.ts.map +1 -0
- package/dist/interpreter/builtins/effects.js +220 -0
- package/dist/interpreter/builtins/effects.js.map +1 -0
- package/dist/interpreter/builtins/index.d.ts +16 -0
- package/dist/interpreter/builtins/index.d.ts.map +1 -0
- package/dist/interpreter/builtins/index.js +17 -0
- package/dist/interpreter/builtins/index.js.map +1 -0
- package/dist/interpreter/builtins/layout.d.ts +12 -0
- package/dist/interpreter/builtins/layout.d.ts.map +1 -0
- package/dist/interpreter/builtins/layout.js +175 -0
- package/dist/interpreter/builtins/layout.js.map +1 -0
- package/dist/interpreter/builtins/live.d.ts +11 -0
- package/dist/interpreter/builtins/live.d.ts.map +1 -0
- package/dist/interpreter/builtins/live.js +125 -0
- package/dist/interpreter/builtins/live.js.map +1 -0
- package/dist/interpreter/builtins/midi.d.ts +16 -0
- package/dist/interpreter/builtins/midi.d.ts.map +1 -0
- package/dist/interpreter/builtins/midi.js +320 -0
- package/dist/interpreter/builtins/midi.js.map +1 -0
- package/dist/interpreter/builtins/mixing.d.ts +6 -0
- package/dist/interpreter/builtins/mixing.d.ts.map +1 -0
- package/dist/interpreter/builtins/mixing.js +62 -0
- package/dist/interpreter/builtins/mixing.js.map +1 -0
- package/dist/interpreter/builtins/notation.d.ts +24 -0
- package/dist/interpreter/builtins/notation.d.ts.map +1 -0
- package/dist/interpreter/builtins/notation.js +251 -0
- package/dist/interpreter/builtins/notation.js.map +1 -0
- package/dist/interpreter/builtins/ornaments.d.ts +8 -0
- package/dist/interpreter/builtins/ornaments.d.ts.map +1 -0
- package/dist/interpreter/builtins/ornaments.js +155 -0
- package/dist/interpreter/builtins/ornaments.js.map +1 -0
- package/dist/interpreter/builtins/techniques.d.ts +11 -0
- package/dist/interpreter/builtins/techniques.d.ts.map +1 -0
- package/dist/interpreter/builtins/techniques.js +234 -0
- package/dist/interpreter/builtins/techniques.js.map +1 -0
- package/dist/interpreter/builtins/tuning.d.ts +7 -0
- package/dist/interpreter/builtins/tuning.d.ts.map +1 -0
- package/dist/interpreter/builtins/tuning.js +52 -0
- package/dist/interpreter/builtins/tuning.js.map +1 -0
- package/dist/interpreter/builtins/types.d.ts +27 -0
- package/dist/interpreter/builtins/types.d.ts.map +1 -0
- package/dist/interpreter/builtins/types.js +3 -0
- package/dist/interpreter/builtins/types.js.map +1 -0
- package/dist/interpreter/builtins/vocaloid.d.ts +10 -0
- package/dist/interpreter/builtins/vocaloid.d.ts.map +1 -0
- package/dist/interpreter/builtins/vocaloid.js +165 -0
- package/dist/interpreter/builtins/vocaloid.js.map +1 -0
- package/dist/interpreter/index.d.ts +4 -0
- package/dist/interpreter/index.d.ts.map +1 -0
- package/dist/interpreter/index.js +4 -0
- package/dist/interpreter/index.js.map +1 -0
- package/dist/interpreter/interpreter.d.ts +305 -0
- package/dist/interpreter/interpreter.d.ts.map +1 -0
- package/dist/interpreter/interpreter.js +8463 -0
- package/dist/interpreter/interpreter.js.map +1 -0
- package/dist/interpreter/runtime.d.ts +67 -0
- package/dist/interpreter/runtime.d.ts.map +1 -0
- package/dist/interpreter/runtime.js +88 -0
- package/dist/interpreter/runtime.js.map +1 -0
- package/dist/interpreter/scope.d.ts +21 -0
- package/dist/interpreter/scope.d.ts.map +1 -0
- package/dist/interpreter/scope.js +60 -0
- package/dist/interpreter/scope.js.map +1 -0
- package/dist/interpreter/trackState.d.ts +205 -0
- package/dist/interpreter/trackState.d.ts.map +1 -0
- package/dist/interpreter/trackState.js +12 -0
- package/dist/interpreter/trackState.js.map +1 -0
- package/dist/lexer/index.d.ts +2 -0
- package/dist/lexer/index.d.ts.map +1 -0
- package/dist/lexer/index.js +2 -0
- package/dist/lexer/index.js.map +1 -0
- package/dist/lexer/lexer.d.ts +30 -0
- package/dist/lexer/lexer.d.ts.map +1 -0
- package/dist/lexer/lexer.js +385 -0
- package/dist/lexer/lexer.js.map +1 -0
- package/dist/parser/index.d.ts +2 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +2 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/parser.d.ts +55 -0
- package/dist/parser/parser.d.ts.map +1 -0
- package/dist/parser/parser.js +896 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/types/ast.d.ts +220 -0
- package/dist/types/ast.d.ts.map +1 -0
- package/dist/types/ast.js +3 -0
- package/dist/types/ast.js.map +1 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/ir/advanced.d.ts +491 -0
- package/dist/types/ir/advanced.d.ts.map +1 -0
- package/dist/types/ir/advanced.js +3 -0
- package/dist/types/ir/advanced.js.map +1 -0
- package/dist/types/ir/algorithmic.d.ts +48 -0
- package/dist/types/ir/algorithmic.d.ts.map +1 -0
- package/dist/types/ir/algorithmic.js +3 -0
- package/dist/types/ir/algorithmic.js.map +1 -0
- package/dist/types/ir/analysis.d.ts +34 -0
- package/dist/types/ir/analysis.d.ts.map +1 -0
- package/dist/types/ir/analysis.js +3 -0
- package/dist/types/ir/analysis.js.map +1 -0
- package/dist/types/ir/audio.d.ts +249 -0
- package/dist/types/ir/audio.d.ts.map +1 -0
- package/dist/types/ir/audio.js +3 -0
- package/dist/types/ir/audio.js.map +1 -0
- package/dist/types/ir/automation.d.ts +46 -0
- package/dist/types/ir/automation.d.ts.map +1 -0
- package/dist/types/ir/automation.js +3 -0
- package/dist/types/ir/automation.js.map +1 -0
- package/dist/types/ir/collaboration.d.ts +20 -0
- package/dist/types/ir/collaboration.d.ts.map +1 -0
- package/dist/types/ir/collaboration.js +3 -0
- package/dist/types/ir/collaboration.js.map +1 -0
- package/dist/types/ir/core.d.ts +153 -0
- package/dist/types/ir/core.d.ts.map +1 -0
- package/dist/types/ir/core.js +3 -0
- package/dist/types/ir/core.js.map +1 -0
- package/dist/types/ir/effects.d.ts +169 -0
- package/dist/types/ir/effects.d.ts.map +1 -0
- package/dist/types/ir/effects.js +3 -0
- package/dist/types/ir/effects.js.map +1 -0
- package/dist/types/ir/extended.d.ts +104 -0
- package/dist/types/ir/extended.d.ts.map +1 -0
- package/dist/types/ir/extended.js +3 -0
- package/dist/types/ir/extended.js.map +1 -0
- package/dist/types/ir/index.d.ts +16 -0
- package/dist/types/ir/index.d.ts.map +1 -0
- package/dist/types/ir/index.js +17 -0
- package/dist/types/ir/index.js.map +1 -0
- package/dist/types/ir/mastering.d.ts +86 -0
- package/dist/types/ir/mastering.d.ts.map +1 -0
- package/dist/types/ir/mastering.js +3 -0
- package/dist/types/ir/mastering.js.map +1 -0
- package/dist/types/ir/midi.d.ts +79 -0
- package/dist/types/ir/midi.d.ts.map +1 -0
- package/dist/types/ir/midi.js +3 -0
- package/dist/types/ir/midi.js.map +1 -0
- package/dist/types/ir/notation.d.ts +963 -0
- package/dist/types/ir/notation.d.ts.map +1 -0
- package/dist/types/ir/notation.js +3 -0
- package/dist/types/ir/notation.js.map +1 -0
- package/dist/types/ir/recording.d.ts +48 -0
- package/dist/types/ir/recording.d.ts.map +1 -0
- package/dist/types/ir/recording.js +3 -0
- package/dist/types/ir/recording.js.map +1 -0
- package/dist/types/ir/sampling.d.ts +59 -0
- package/dist/types/ir/sampling.d.ts.map +1 -0
- package/dist/types/ir/sampling.js +3 -0
- package/dist/types/ir/sampling.js.map +1 -0
- package/dist/types/ir/sequencing.d.ts +118 -0
- package/dist/types/ir/sequencing.d.ts.map +1 -0
- package/dist/types/ir/sequencing.js +3 -0
- package/dist/types/ir/sequencing.js.map +1 -0
- package/dist/types/ir/sync.d.ts +39 -0
- package/dist/types/ir/sync.d.ts.map +1 -0
- package/dist/types/ir/sync.js +3 -0
- package/dist/types/ir/sync.js.map +1 -0
- package/dist/types/ir.d.ts +2 -0
- package/dist/types/ir.d.ts.map +1 -0
- package/dist/types/ir.js +3 -0
- package/dist/types/ir.js.map +1 -0
- package/dist/types/token.d.ts +72 -0
- package/dist/types/token.d.ts.map +1 -0
- package/dist/types/token.js +90 -0
- package/dist/types/token.js.map +1 -0
- package/dist/utils/stdlib.d.ts +18 -0
- package/dist/utils/stdlib.d.ts.map +1 -0
- package/dist/utils/stdlib.js +51 -0
- package/dist/utils/stdlib.js.map +1 -0
- package/lib/articulation.mf +46 -0
- package/lib/composition.mf +299 -0
- package/lib/curves.mf +183 -0
- package/lib/dynamics.mf +141 -0
- package/lib/expression.mf +221 -0
- package/lib/genres.mf +348 -0
- package/lib/notation.mf +224 -0
- package/lib/ornaments.mf +98 -0
- package/lib/patterns.mf +170 -0
- package/lib/rhythm.mf +269 -0
- package/lib/theory.mf +257 -0
- package/lib/utils.mf +140 -0
- package/package.json +49 -0
package/lib/notation.mf
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// Notation helpers for TakoMusic
|
|
2
|
+
// Musical notation utilities and conversions
|
|
3
|
+
|
|
4
|
+
import { clip } from "./utils.mf";
|
|
5
|
+
|
|
6
|
+
// Convert dynamic marking to velocity
|
|
7
|
+
export proc dynamicToVel(marking) {
|
|
8
|
+
if (marking == "pppp") { return 16; }
|
|
9
|
+
if (marking == "ppp") { return 33; }
|
|
10
|
+
if (marking == "pp") { return 49; }
|
|
11
|
+
if (marking == "p") { return 64; }
|
|
12
|
+
if (marking == "mp") { return 80; }
|
|
13
|
+
if (marking == "mf") { return 96; }
|
|
14
|
+
if (marking == "f") { return 112; }
|
|
15
|
+
if (marking == "ff") { return 120; }
|
|
16
|
+
if (marking == "fff") { return 124; }
|
|
17
|
+
if (marking == "ffff") { return 127; }
|
|
18
|
+
return 96; // default mf
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Convert tempo marking to BPM
|
|
22
|
+
export proc tempoToBpm(marking) {
|
|
23
|
+
if (marking == "grave") { return 40; }
|
|
24
|
+
if (marking == "largo") { return 50; }
|
|
25
|
+
if (marking == "lento") { return 60; }
|
|
26
|
+
if (marking == "adagio") { return 70; }
|
|
27
|
+
if (marking == "andante") { return 90; }
|
|
28
|
+
if (marking == "moderato") { return 110; }
|
|
29
|
+
if (marking == "allegretto") { return 115; }
|
|
30
|
+
if (marking == "allegro") { return 130; }
|
|
31
|
+
if (marking == "vivace") { return 150; }
|
|
32
|
+
if (marking == "presto") { return 180; }
|
|
33
|
+
if (marking == "prestissimo") { return 200; }
|
|
34
|
+
return 120; // default
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Play triplet feel
|
|
38
|
+
export proc tripletFeel(notes, baseDur) {
|
|
39
|
+
const longDur = baseDur * 2/3;
|
|
40
|
+
const shortDur = baseDur * 1/3;
|
|
41
|
+
|
|
42
|
+
for (i in 0..len(notes)) {
|
|
43
|
+
if (i % 2 == 0) {
|
|
44
|
+
note(notes[i], longDur);
|
|
45
|
+
} else {
|
|
46
|
+
note(notes[i], shortDur);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Play dotted rhythm
|
|
52
|
+
export proc dottedRhythm(notes, baseDur) {
|
|
53
|
+
const longDur = baseDur * 3/4;
|
|
54
|
+
const shortDur = baseDur * 1/4;
|
|
55
|
+
|
|
56
|
+
for (i in 0..len(notes)) {
|
|
57
|
+
if (i % 2 == 0) {
|
|
58
|
+
note(notes[i], longDur);
|
|
59
|
+
} else {
|
|
60
|
+
note(notes[i], shortDur);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Generate scale in specific octave range
|
|
66
|
+
export proc scaleInRange(scaleFunc, root, octaves) {
|
|
67
|
+
let result = [];
|
|
68
|
+
for (oct in 0..octaves) {
|
|
69
|
+
const octaveRoot = transpose(root, oct * 12);
|
|
70
|
+
const scale = scaleFunc(octaveRoot);
|
|
71
|
+
for (i in 0..len(scale) - 1) {
|
|
72
|
+
push(result, scale[i]);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Create melody from scale degrees
|
|
79
|
+
export proc melodyFromDegrees(scale, degrees, dur) {
|
|
80
|
+
for (i in 0..len(degrees)) {
|
|
81
|
+
const degree = degrees[i];
|
|
82
|
+
if (degree == 0) {
|
|
83
|
+
rest(dur);
|
|
84
|
+
} else {
|
|
85
|
+
const idx = (degree - 1) % len(scale);
|
|
86
|
+
const octave = floor((degree - 1) / len(scale));
|
|
87
|
+
const pitch = transpose(scale[idx], octave * 12);
|
|
88
|
+
note(pitch, dur);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Harmonize melody with interval
|
|
94
|
+
export proc harmonize(melody, interval, dur) {
|
|
95
|
+
for (i in 0..len(melody)) {
|
|
96
|
+
const pitches = [melody[i], transpose(melody[i], interval)];
|
|
97
|
+
chord(pitches, dur);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Create countermelody (simple inversion)
|
|
102
|
+
export proc invertMelody(melody, axis) {
|
|
103
|
+
let result = [];
|
|
104
|
+
const axisMidi = pitchMidi(axis);
|
|
105
|
+
|
|
106
|
+
for (i in 0..len(melody)) {
|
|
107
|
+
const pitchMidi = pitchMidi(melody[i]);
|
|
108
|
+
const distance = pitchMidi - axisMidi;
|
|
109
|
+
const inverted = axisMidi - distance;
|
|
110
|
+
push(result, midiPitch(clip(inverted, 0, 127)));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Retrograde (reverse) melody
|
|
117
|
+
export proc retrograde(melody) {
|
|
118
|
+
let result = [];
|
|
119
|
+
for (i in 0..len(melody)) {
|
|
120
|
+
const idx = len(melody) - 1 - i;
|
|
121
|
+
push(result, melody[idx]);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Rhythmic augmentation (make durations longer)
|
|
127
|
+
export proc augment(rhythms, factor) {
|
|
128
|
+
let result = [];
|
|
129
|
+
for (i in 0..len(rhythms)) {
|
|
130
|
+
push(result, rhythms[i] * factor);
|
|
131
|
+
}
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Rhythmic diminution (make durations shorter)
|
|
136
|
+
export proc diminish(rhythms, factor) {
|
|
137
|
+
return augment(rhythms, 1 / factor);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Generate pickup notes (anacrusis)
|
|
141
|
+
export proc pickupNotes(notes, totalDur, noteDur) {
|
|
142
|
+
const pickupDur = len(notes) * noteDur;
|
|
143
|
+
const waitDur = totalDur - pickupDur;
|
|
144
|
+
|
|
145
|
+
if (waitDur > 0) {
|
|
146
|
+
rest(waitDur);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
for (i in 0..len(notes)) {
|
|
150
|
+
note(notes[i], noteDur);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Bass line from chord progression
|
|
155
|
+
export proc bassLine(chords, dur) {
|
|
156
|
+
for (i in 0..len(chords)) {
|
|
157
|
+
const root = chords[i][0];
|
|
158
|
+
const bassNote = transpose(root, -12);
|
|
159
|
+
note(bassNote, dur);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Walking bass pattern
|
|
164
|
+
export proc walkingBass(chord, nextChord, dur) {
|
|
165
|
+
const root = chord[0];
|
|
166
|
+
const third = chord[1];
|
|
167
|
+
const fifth = chord[2];
|
|
168
|
+
const nextRoot = nextChord[0];
|
|
169
|
+
|
|
170
|
+
// Basic walking pattern: root, third, fifth, approach
|
|
171
|
+
note(transpose(root, -12), dur);
|
|
172
|
+
note(transpose(third, -12), dur);
|
|
173
|
+
note(transpose(fifth, -12), dur);
|
|
174
|
+
|
|
175
|
+
// Approach note (half step below next root)
|
|
176
|
+
const approach = transpose(nextRoot, -13);
|
|
177
|
+
note(approach, dur);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Alberti bass pattern
|
|
181
|
+
export proc albertiBass(chord, repetitions, dur) {
|
|
182
|
+
const pattern = [0, 2, 1, 2]; // root, fifth, third, fifth
|
|
183
|
+
|
|
184
|
+
for (rep in 0..repetitions) {
|
|
185
|
+
for (i in 0..len(pattern)) {
|
|
186
|
+
const idx = pattern[i];
|
|
187
|
+
if (idx < len(chord)) {
|
|
188
|
+
note(transpose(chord[idx], -12), dur);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Convert note name to pitch
|
|
195
|
+
export proc noteNameToPitch(name, octave) {
|
|
196
|
+
let semitone = 0;
|
|
197
|
+
|
|
198
|
+
const noteLetter = charAt(name, 0);
|
|
199
|
+
if (noteLetter == "C") { semitone = 0; }
|
|
200
|
+
if (noteLetter == "D") { semitone = 2; }
|
|
201
|
+
if (noteLetter == "E") { semitone = 4; }
|
|
202
|
+
if (noteLetter == "F") { semitone = 5; }
|
|
203
|
+
if (noteLetter == "G") { semitone = 7; }
|
|
204
|
+
if (noteLetter == "A") { semitone = 9; }
|
|
205
|
+
if (noteLetter == "B") { semitone = 11; }
|
|
206
|
+
|
|
207
|
+
// Check for accidental
|
|
208
|
+
if (len(name) > 1) {
|
|
209
|
+
const accidental = charAt(name, 1);
|
|
210
|
+
if (accidental == "#") { semitone = semitone + 1; }
|
|
211
|
+
if (accidental == "b") { semitone = semitone - 1; }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const midiNum = 12 + octave * 12 + semitone;
|
|
215
|
+
return midiPitch(clip(midiNum, 0, 127));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Tuplet helper (generic n-tuplet)
|
|
219
|
+
export proc playTuplet(notes, totalDur, ratio) {
|
|
220
|
+
const noteDur = totalDur / len(notes) * ratio;
|
|
221
|
+
for (i in 0..len(notes)) {
|
|
222
|
+
note(notes[i], noteDur);
|
|
223
|
+
}
|
|
224
|
+
}
|
package/lib/ornaments.mf
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Ornament functions for TakoMusic
|
|
2
|
+
// Musical decorations and embellishments
|
|
3
|
+
|
|
4
|
+
// trill - rapid alternation between two adjacent notes
|
|
5
|
+
export proc trill(pitch, dur, interval) {
|
|
6
|
+
const count = 8;
|
|
7
|
+
const subDur = dur / count;
|
|
8
|
+
|
|
9
|
+
for (i in 0..count) {
|
|
10
|
+
if (i % 2 == 0) {
|
|
11
|
+
note(pitch, subDur);
|
|
12
|
+
} else {
|
|
13
|
+
note(transpose(pitch, interval), subDur);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// mordent - single alternation with adjacent note
|
|
19
|
+
export proc mordent(pitch, dur, interval) {
|
|
20
|
+
const mainDur = dur * 3/4;
|
|
21
|
+
const ornDur = dur * 1/4;
|
|
22
|
+
|
|
23
|
+
note(transpose(pitch, interval), ornDur);
|
|
24
|
+
note(pitch, mainDur);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// arpeggio - play chord notes in sequence
|
|
28
|
+
export proc arpeggio(pitches, dur) {
|
|
29
|
+
const subDur = dur / len(pitches);
|
|
30
|
+
forEach(pitches, (p) => note(p, subDur));
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// tremolo - rapid repetition of single note
|
|
34
|
+
export proc tremolo(pitch, dur, rate) {
|
|
35
|
+
const count = floor(rate);
|
|
36
|
+
const subDur = dur / count;
|
|
37
|
+
|
|
38
|
+
for (i in 0..count) {
|
|
39
|
+
note(pitch, subDur);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// turn - ornamental figure going above and below the main note
|
|
44
|
+
export proc turn(pitch, dur) {
|
|
45
|
+
const subDur = dur / 4;
|
|
46
|
+
|
|
47
|
+
note(transpose(pitch, 2), subDur); // upper neighbor
|
|
48
|
+
note(pitch, subDur); // main note
|
|
49
|
+
note(transpose(pitch, -2), subDur); // lower neighbor
|
|
50
|
+
note(pitch, subDur); // main note
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// gruppetto - Italian turn
|
|
54
|
+
export proc gruppetto(pitch, dur) {
|
|
55
|
+
const subDur = dur / 5;
|
|
56
|
+
|
|
57
|
+
note(pitch, subDur);
|
|
58
|
+
note(transpose(pitch, 2), subDur);
|
|
59
|
+
note(pitch, subDur);
|
|
60
|
+
note(transpose(pitch, -2), subDur);
|
|
61
|
+
note(pitch, subDur);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// appoggiatura - grace note that takes time from main note
|
|
65
|
+
export proc appoggiatura(gracePitch, mainPitch, totalDur) {
|
|
66
|
+
const graceDur = totalDur / 4;
|
|
67
|
+
const mainDur = totalDur * 3/4;
|
|
68
|
+
|
|
69
|
+
note(gracePitch, graceDur);
|
|
70
|
+
note(mainPitch, mainDur);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// acciaccatura - very short grace note (crushed note)
|
|
74
|
+
export proc acciaccatura(gracePitch, mainPitch, totalDur) {
|
|
75
|
+
const graceDur = totalDur / 8;
|
|
76
|
+
const mainDur = totalDur * 7/8;
|
|
77
|
+
|
|
78
|
+
note(gracePitch, graceDur);
|
|
79
|
+
note(mainPitch, mainDur);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// glissando - slide between two pitches
|
|
83
|
+
export proc glissando(startPitch, endPitch, dur) {
|
|
84
|
+
const startMidi = pitchMidi(startPitch);
|
|
85
|
+
const endMidi = pitchMidi(endPitch);
|
|
86
|
+
const steps = abs(endMidi - startMidi);
|
|
87
|
+
const subDur = dur / (steps + 1);
|
|
88
|
+
|
|
89
|
+
if (startMidi < endMidi) {
|
|
90
|
+
for (i in 0..=steps) {
|
|
91
|
+
note(midiPitch(startMidi + i), subDur);
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
for (i in 0..=steps) {
|
|
95
|
+
note(midiPitch(startMidi - i), subDur);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
package/lib/patterns.mf
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
// Advanced pattern generation for TakoMusic
|
|
2
|
+
// Algorithmic composition and generative music
|
|
3
|
+
|
|
4
|
+
import { choice, shuffle, clip, wrap, rotate } from "./utils.mf";
|
|
5
|
+
|
|
6
|
+
// Random walk melody generator
|
|
7
|
+
export proc randomWalk(startPitch, steps, maxStep) {
|
|
8
|
+
let melody = [];
|
|
9
|
+
let current = startPitch;
|
|
10
|
+
|
|
11
|
+
for (i in 0..steps) {
|
|
12
|
+
push(melody, current);
|
|
13
|
+
const step = random(-maxStep, maxStep + 1);
|
|
14
|
+
current = transpose(current, step);
|
|
15
|
+
current = transpose(C0, clip(pitchMidi(current), 0, 127));
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return melody;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Pentatonic random walk
|
|
22
|
+
export proc pentatonicWalk(root, steps) {
|
|
23
|
+
const scale = [0, 2, 4, 7, 9, 12];
|
|
24
|
+
let melody = [];
|
|
25
|
+
let idx = 0;
|
|
26
|
+
|
|
27
|
+
for (i in 0..steps) {
|
|
28
|
+
const offset = scale[idx % len(scale)];
|
|
29
|
+
const octave = floor(idx / len(scale));
|
|
30
|
+
push(melody, transpose(root, offset + octave * 12));
|
|
31
|
+
|
|
32
|
+
const step = random(-2, 3);
|
|
33
|
+
idx = clip(idx + step, 0, len(scale) * 3 - 1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return melody;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Fractal melody generator (simple self-similarity)
|
|
40
|
+
export proc fractalMelody(pattern, depth) {
|
|
41
|
+
if (depth == 0) {
|
|
42
|
+
return pattern;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
let result = [];
|
|
46
|
+
for (i in 0..len(pattern)) {
|
|
47
|
+
const pitch = pattern[i];
|
|
48
|
+
push(result, pitch);
|
|
49
|
+
|
|
50
|
+
// Insert transposed version of pattern at smaller scale
|
|
51
|
+
const subPattern = fractalMelody(pattern, depth - 1);
|
|
52
|
+
for (j in 0..len(subPattern)) {
|
|
53
|
+
push(result, transpose(subPattern[j], 7));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Probability-based rhythm pattern
|
|
61
|
+
export proc probabilityRhythm(steps, probability) {
|
|
62
|
+
let pattern = [];
|
|
63
|
+
for (i in 0..steps) {
|
|
64
|
+
push(pattern, random() < probability);
|
|
65
|
+
}
|
|
66
|
+
return pattern;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Density-based rhythm (gradually increase/decrease density)
|
|
70
|
+
export proc densityRhythm(steps, startProb, endProb) {
|
|
71
|
+
let pattern = [];
|
|
72
|
+
for (i in 0..steps) {
|
|
73
|
+
const t = i / (steps - 1);
|
|
74
|
+
const prob = startProb + (endProb - startProb) * t;
|
|
75
|
+
push(pattern, random() < prob);
|
|
76
|
+
}
|
|
77
|
+
return pattern;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Polyrhythmic pattern generator
|
|
81
|
+
export proc polyrhythm(ratio1, ratio2, cycles) {
|
|
82
|
+
const totalSteps = ratio1 * ratio2;
|
|
83
|
+
let pattern1 = [];
|
|
84
|
+
let pattern2 = [];
|
|
85
|
+
|
|
86
|
+
for (i in 0..totalSteps * cycles) {
|
|
87
|
+
push(pattern1, i % ratio1 == 0);
|
|
88
|
+
push(pattern2, i % ratio2 == 0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return [pattern1, pattern2];
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Phasing pattern (Steve Reich style)
|
|
95
|
+
export proc phasePattern(pattern, phaseShift, repetitions) {
|
|
96
|
+
let result = [];
|
|
97
|
+
|
|
98
|
+
for (rep in 0..repetitions) {
|
|
99
|
+
const shift = floor(rep * phaseShift) % len(pattern);
|
|
100
|
+
const rotated = rotate(pattern, shift);
|
|
101
|
+
for (i in 0..len(rotated)) {
|
|
102
|
+
push(result, rotated[i]);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Markov chain melody (simple 2-state)
|
|
110
|
+
export proc markovMelody(notes, transitionProb, length, startIdx) {
|
|
111
|
+
let melody = [];
|
|
112
|
+
let currentIdx = startIdx;
|
|
113
|
+
|
|
114
|
+
for (i in 0..length) {
|
|
115
|
+
push(melody, notes[currentIdx]);
|
|
116
|
+
|
|
117
|
+
// Simple transition: stay or move
|
|
118
|
+
if (random() < transitionProb) {
|
|
119
|
+
currentIdx = (currentIdx + 1) % len(notes);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return melody;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Arpeggiate chord with pattern
|
|
127
|
+
export proc arpeggiate(chord, pattern, dur) {
|
|
128
|
+
for (i in 0..len(pattern)) {
|
|
129
|
+
const idx = pattern[i];
|
|
130
|
+
if (idx >= 0 && idx < len(chord)) {
|
|
131
|
+
note(chord[idx], dur);
|
|
132
|
+
} else {
|
|
133
|
+
rest(dur);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Generate arpeggio pattern (up, down, up-down, random)
|
|
139
|
+
export proc arpeggioPattern(chordSize, style, length) {
|
|
140
|
+
let pattern = [];
|
|
141
|
+
|
|
142
|
+
for (i in 0..length) {
|
|
143
|
+
let idx = 0;
|
|
144
|
+
|
|
145
|
+
if (style == "up") {
|
|
146
|
+
idx = i % chordSize;
|
|
147
|
+
} else {
|
|
148
|
+
if (style == "down") {
|
|
149
|
+
idx = chordSize - 1 - (i % chordSize);
|
|
150
|
+
} else {
|
|
151
|
+
if (style == "updown") {
|
|
152
|
+
const cycle = chordSize * 2 - 2;
|
|
153
|
+
const pos = i % cycle;
|
|
154
|
+
if (pos < chordSize) {
|
|
155
|
+
idx = pos;
|
|
156
|
+
} else {
|
|
157
|
+
idx = chordSize - 2 - (pos - chordSize);
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
// random
|
|
161
|
+
idx = random(chordSize);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
push(pattern, idx);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return pattern;
|
|
170
|
+
}
|