15 Commits

Author SHA1 Message Date
Bartłomiej Pluta
e03c6325f5 Merge branch 'add-setup' 2019-10-11 16:48:06 +02:00
Bartłomiej Pluta
70c7c0963b Fix lack of description and version meta files 2019-10-11 16:42:17 +02:00
Bartłomiej Pluta
56bd6a909a Update readme 2019-10-11 16:01:31 +02:00
Bartłomiej Pluta
25df849c19 Create setup scaffolding 2019-09-24 14:56:32 +02:00
Bartłomiej Pluta
0965ed290e Add bubble_sort.mus example 2019-09-20 23:41:10 +02:00
Bartłomiej Pluta
8e6194071e Add new example: Praeludium C Major - J. S. Bach 2019-09-20 14:56:25 +02:00
Bartłomiej Pluta
fe6c146521 Merge branch 'add-readme' 2019-09-17 23:15:03 +02:00
Bartłomiej Pluta
d720266b87 Add *.mus files 2019-09-17 23:08:37 +02:00
Bartłomiej Pluta
1d01d1c373 Add stdlib documentation 2019-09-17 23:08:37 +02:00
Bartłomiej Pluta
231ce4c4c5 Add README.md 2019-09-17 23:08:35 +02:00
Bartłomiej Pluta
aa38e6b7b6 Merge branch 'add-fft' 2019-09-09 15:32:09 +02:00
Bartłomiej Pluta
f5c72dd8a5 Add fft() function 2019-09-09 15:31:43 +02:00
Bartłomiej Pluta
55adf616c5 Merge branch 'add-possibility-to-tune' 2019-09-09 15:31:32 +02:00
Bartłomiej Pluta
06579e8e78 Enable tuning 2019-09-09 15:29:12 +02:00
Bartłomiej Pluta
2c1f5f7942 Merge branch 'add-cli' 2019-09-09 15:28:56 +02:00
59 changed files with 4561 additions and 99 deletions

1
.gitignore vendored
View File

@@ -2,3 +2,4 @@ __pycache__/
*.mus *.mus
.idea/* .idea/*
venv/ venv/
SMNP.egg-info

34
Pipfile.lock generated
View File

@@ -106,25 +106,25 @@
}, },
"numpy": { "numpy": {
"hashes": [ "hashes": [
"sha256:03f2ebcbffcce2dec8860633b89a93e80c6a239d21a77ae8b241450dc21e8c35", "sha256:05dbfe72684cc14b92568de1bc1f41e5f62b00f714afc9adee42f6311738091f",
"sha256:078c8025da5ab9e8657edc9c2a1e9642e06e953bc7baa2e65c1aa9d9dfb7e98b", "sha256:0d82cb7271a577529d07bbb05cb58675f2deb09772175fab96dc8de025d8ac05",
"sha256:0fbfa98c5d5c3c6489cc1e852ec94395d51f35d9ebe70c6850e47f465038cdf4", "sha256:10132aa1fef99adc85a905d82e8497a580f83739837d7cbd234649f2e9b9dc58",
"sha256:1c841033f4fe6801648180c3033c45b3235a8bbd09bc7249010f99ea27bb6790", "sha256:12322df2e21f033a60c80319c25011194cd2a21294cc66fee0908aeae2c27832",
"sha256:2c0984a01ddd0aeec89f0ce46ef21d64761048cd76c0074d0658c91f9131f154", "sha256:16f19b3aa775dddc9814e02a46b8e6ae6a54ed8cf143962b4e53f0471dbd7b16",
"sha256:4c166dcb0fff7cb3c0bbc682dfb5061852a2547efb6222e043a7932828c08fb5", "sha256:3d0b0989dd2d066db006158de7220802899a1e5c8cf622abe2d0bd158fd01c2c",
"sha256:8c2d98d0623bd63fb883b65256c00454d5f53127a5a7bcdaa8bdc582814e8cb4", "sha256:438a3f0e7b681642898fd7993d38e2bf140a2d1eafaf3e89bb626db7f50db355",
"sha256:8cb4b6ae45aad6d26712a1ce0a3f2556c5e1484867f9649e03496e45d6a5eba4", "sha256:5fd214f482ab53f2cea57414c5fb3e58895b17df6e6f5bca5be6a0bb6aea23bb",
"sha256:93050e73c446c82065b7410221b07682e475ac51887cd9368227a5d944afae80", "sha256:73615d3edc84dd7c4aeb212fa3748fb83217e00d201875a47327f55363cef2df",
"sha256:a3f6b3024f8826d8b1490e6e2a9b99e841cd2c375791b1df62991bd8f4c00b89", "sha256:7bd355ad7496f4ce1d235e9814ec81ee3d28308d591c067ce92e49f745ba2c2f",
"sha256:bede70fd8699695363f39e86c1e869b2c8b74fb5ef135a67b9e1eeebff50322a", "sha256:7d077f2976b8f3de08a0dcf5d72083f4af5411e8fddacd662aae27baa2601196",
"sha256:c304b2221f33489cd15a915237a84cdfe9420d7e4d4828c78a0820f9d990395c", "sha256:a4092682778dc48093e8bda8d26ee8360153e2047826f95a3f5eae09f0ae3abf",
"sha256:f11331530f0eff69a758d62c2461cd98cdc2eae0147279d8fc86e0464eb7e8ca", "sha256:b458de8624c9f6034af492372eb2fee41a8e605f03f4732f43fc099e227858b2",
"sha256:fa5f2a8ef1e07ba258dc07d4dd246de23ef4ab920ae0f3fa2a1cc5e90f0f1888", "sha256:e70fc8ff03a961f13363c2c95ef8285e0cf6a720f8271836f852cc0fa64e97c8",
"sha256:fb6178b0488b0ce6a54bc4accbdf5225e937383586555604155d64773f6beb2b", "sha256:ee8e9d7cad5fe6dde50ede0d2e978d81eafeaa6233fb0b8719f60214cf226578",
"sha256:fd5e830d4dc31658d61a6452cd3e842213594d8c15578cdae6829e36ad9c0930" "sha256:f4a4f6aba148858a5a5d546a99280f71f5ee6ec8182a7d195af1a914195b21a2"
], ],
"index": "pypi", "index": "pypi",
"version": "==1.17.1" "version": "==1.17.2"
}, },
"pycparser": { "pycparser": {
"hashes": [ "hashes": [

2372
README.md Normal file

File diff suppressed because it is too large Load Diff

1084
STDLIB.md Normal file

File diff suppressed because it is too large Load Diff

36
examples/adeste.mus Normal file
View File

@@ -0,0 +1,36 @@
println("Adeste Fideles");
println("John Francis Wade");
s1 = [@g, @g:2, @d, @g, @a:2, @d:2, @h, @a, @h, @c5, @h:2, @a, @g];
s2 = [@g:2, @f#, @e, @f#, @g, @a, @h, @f#:2, @e:4d, @d:8, @d:2d, 4];
s3 = [@d5:2, @c5, @h, @c5:2, @h:2, @a, @h, @g, @a, @f#:4d, @e:8, @d];
s4 = [@g, @g, @f#, @g, @a, @g:2, @d, @h, @h, @a, @h, @c5, @h:2, @a];
s5 = [@h, @c5, @h, @a, @g, @f#:2, @g, @c5, @h:2, @a:4d, @g:8, @g:1];
S = s1 + s2 + s3 + s4 + s5;
a1 = [@d, @d:2, @d, @d, @e:2, @d:2, @d, @d, @d, @e, @d:2, @d, @h3];
a2 = [@h3, @c#, @d, @c#, @d, @d, @d, @d, @d:2, @c#:4d, @d:8, @d:2d, 4];
a3 = [@d:2, @e:8, @f#:8, @g, @g, @f#, @g:2, @d, @d, @e, @e, @d:2, @d];
a4 = [@d, @d:1, @d:2d, @d, @d:1, @d:2d];
a5 = [@g, @f#, @g, @d, @d:8, @c#:8, @d:2, @d, @e, @d:2, @d:4d, @h3:8, @h3:1];
A = a1 + a2 + a3 + a4 + a5;
t1 = [@h3, @h3:2, @h3, @h3, @c:2, @a3:2, @g3, @a3, @g3, @g3, @g3:2, @f#3, @g3];
t2 = [@g3:2, @a3, @a3, @a3, @g3, @f#3, @d3, @a3:2, @g3:4d, @f#3:8, @f#3:2d, 4];
t3 = [@h3:2, @c, @d, @c:2, @d:2, @d, @g3, @h3, @c, @a3:2, @f#3];
t4 = [@h3, @h3, @a3, @h3, @c, @h3:2d, @g3, @g3, @f#3, @g3, @a3, @g3:2, @f#3];
t5 = [@d, @d, @d, @a3, @a3, @a3:2, @g3:2, @g3:2, @f#3:4d, @g3:8, @g3:1];
T = t1 + t2 + t3 + t4 + t5;
b1 = [@g3, @g3:2, @h3, @g3, @g3:2, @f#3:2, @g3, @f#3, @g3, @c3, @d3:2, @d3, @e3];
b2 = [@e3:2, @d3, @a2, @d3, @h2, @f#2, @g2, @a2:2, @a2:4d, @d3:8, @d2:2d, 4];
b3 = [@h3:2, @a3, @g3, @a3:2, @g3:2, @f#3, @g3, @e3, @c3, @d3:2, @d3];
b4 = [4, 1, 1, 1, 2, 4];
b5 = [@g3, @a3, @g3, @f#3, @e3, @d3, @c3, @h2, @c3, @d3:2, @d3:4d, @g2:8, @g2:1];
B = b1 + b2 + b3 + b4 + b5;
synth({ tuning -> 431, attack -> 100, decay -> 1.2, overtones -> [0.7, 0, 0.2, 0.1] }, S, A, T, B);

198
examples/bach_prelude_c.mus Normal file
View File

@@ -0,0 +1,198 @@
println("Praeludium C Major");
println("Acht kleine Praeludien und Fugen");
println("Johann Sebastian Bach");
config = {
overtones -> flat([0.5, 0.3, 5^0.0, 0.1, 3^0.0, 0.05, 0.0, 0.03, 0.0, 0.0, 0.01, 5^0.0, 0.005, 3^0.0, 0.002, 0.0, 0.001]),
decay -> 2,
attack -> 0,
tuning -> 432
};
s1 = [16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @h:16, @c5:16, @e, 4];
s2 = [16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @h:16, @c5:16, @a:16, @f:16, @e:16, @f:16, @c:16, @f:16, @e:16, @f:16];
s3 = [@d:16, @d5:16, @c5:16, @d5:16, @a:16, @d5:16, @c5:16, @d5:16, @h:16, @g:16, @f#:16, @g:16, @d:16, @g:16, @f#:16, @g:16];
s4 = [@e:16, @e5:16, @d5:16, @e5:16, @h:16, @e5:16, @d5:16, @e5:16, @c5:16, @a:16, @g#:16, @a:16, @e:16, @a:16, @g#:16, @a:16];
s5 = flat(2 ^ [@c5, @f#, @e, @f#], 2 ^ [@h, @g, @f#, @g]) as n ^ n.withDuration(16);
s6 = flat(2 ^ [@h, @e, @d, @e], 2 ^ [@a, @f#, @e, @f#]) as n ^ n.withDuration(16);
s7 = flat(2 ^ [@a, @d, @c, @d], 2 ^ [@g, @e, @d, @e]) as n ^ n.withDuration(16);
s8 = flat(2 ^ [@g, @c#, @h3, @c#], 2 ^ [@f#, @d, @c#, @d]) as n ^ n.withDuration(16);
s9 = [@g, @f#, @g, @d, @a, @g, @a, @d, @h, @a, @h, @d, @c5, @h, @c5, @d] as n ^ n.withDuration(16);
s10 = [@d5:4d, @d5:8, @e5:16, @g5:16, @d5:16, @g5:16, @c5:16, @g5:16, @h:16, @g5:16];
s11 = [@a, 8, @h:8, @c5:16, @d5:16, @h:16, @c5:16, @a:8d, @g:16];
s12 = [@g, 4, 2];
S1 = s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12
#
a1 = [2, 16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @h:16, @c5:16];
a2 = [@g, 8, @c5:8, @c5, 4];
a3 = [@a, 8, @d5:8, @d5, 4];
a4 = [@h, 8, @e5:8, @e5, 4];
a5 = 8 ^ @d5:8;
a6 = 8 ^ @c5:8;
a7 = 8 ^ @h:8;
a8 = 8 ^ @a:8;
a9 = [@h, @a, @g, @a];
a10 = [@h:16, @d5:16, @e5:16, @f#5:16, @h5:8, @g5:8, @g5:2];
a11 = [@g5:8, @f#5:16, @e5:16, @f#5:8, @g5:8, @a5:8, @g5:8, @d5];
a12 = [@d5, 4, 2];
A1 = transpose(-12, a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12);
#
t1 = [1];
t2 = [@e, 8, @g:8, @a, 4];
t3 = [@f#, 8, @a:8, @h, 4];
t4 = [@g#, 8, @h:8, @c5, 4];
t5 = (4 ^ @a:8) + (4 ^ @h:8);
t6 = (4 ^ @g:8) + (4 ^ @a:8);
t7 = (4 ^ @f#:8) + (4 ^ @g:8);
t8 = (4 ^ @e:8) + (4 ^ @f#:8);
t9 = [@e, @f#, @g, @f#];
t10 = [@g, @g5:8, @h:8, @c5:8, @h:8, @a:8, @g:8];
t11 = [@d5, 8, @d5:8, @d5:8, @d5:8, @d5];
t12 = [@h, 4, 2];
T1 = transpose(-12, t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8 + t9 + t10 + t11 + t12);
#
b_ = 10 ^ 1;
b11 = [2, 8, @g3, @f#3:8];
b12 = [16, @g3:16, @f#3:16, @g3:16, @d3:16, @g3:16, @f#3:16, @g3:16, @g2, 4];
B1 = b_ + b11 + b12;
#
p1 = [@c:1];
p2 = [@c, 8, @e:8, @f, 4];
p3 = [@f#, 8, @f#:8, @g, 4];
p4 = [@g#, 8, @g#:8, @a, 4];
p5 = (4 ^ @d:8) + (4 ^ @g:8);
p6 = (4 ^ @c:8) + (4 ^ @f#:8);
p7 = (4 ^ @h3:8) + (4 ^ @e:8);
p8 = (4 ^ @a3:8) + (4 ^ @d:8);
p9 = [@d:1];
p10 = [@d, 4, 2];
p11 = [4, 8, @g:8, @f#:8, @g:8, @d];
p12 = [@g3, 4, 16, @g:16, @f:16, @g:16, @e:16, @g:16, @d:16, @g:16];
P1 = transpose(-12, p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11 + p12);
PART1 = wave(config, S1, A1, T1, B1, P1);
#######
s1 = [16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @h:16, @c5:16, @a, 4];
s2 = [16, @h:16, @a:16, @h:16, @f:16, @h:16, @a:16, @h:16, @g#, 4];
s3 = flat([2 ^ [@a, @e, @d, @e], 2 ^ [@g#, @d, @c, @d]]) as n ^ n.withDuration(16);
s4 = flat([2 ^ [@a, @e, @d, @e], 2 ^ [@h, @g#, @f#, @g#]]) as n ^ n.withDuration(16);
s5 = [@c5, @h, @c5, @d5, @h, @a, @h, @c5] as n ^ n.withDuration(8);
s6 = [@a:8, @g#:8, @a:8, @h:8, @g#:8, @e:8, @c5];
s7 = [@h:8, @a:8, @g#:8d, @a:16, @a, 4];
s8 = [16, @e5:16, @d5:16, @e5:16, @h:16, @e5:16, @d5:16, @e5:16, @c5, 4];
s9 = [16, @g5:16, @f5:16, @g5:16, @d5:16, @g5:16, @f5:16, @g5:16, @e5:16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @h:16, @c5:16];
s10 = [@e, 4, 16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @h:16, @c5:16];
s11 = flat(2 ^ [@a:16, @f:16, @e:16, @f:16], [16, @d5:16, @c5:16, @d5:16, @a:16, @d5:16, @c5:16, @d5:16]);
s12 = flat(2 ^ [@h:16, @g:16, @f#:16, @g:16], [16, @e5:16, @d5:16, @e5:16, @h:16, @e5:16, @d5:16, @e5:16]);
s13 = flat(2 ^ [@c5:16, @a:16, @g#:16, @a:16], [16, @g5:16, @f5:16, @g5:16, @d5:16, @g5:16, @f5:16, @g5:16]);
s14 = [@e, @g, @e, @g, @f, @a, @f, @a, @d, @f, @d, @f, @e, @g, @e, @g] as n ^ n.withDuration(16).withOctave(5);
s15 = [@c5:16, @e5:16, @c5:16, @e5:16, @d5:16, @f5:16, @d5:16, @f5:16, @h:16, @g:16, @a:16, @h:16, @c5];
s16a = [@c5, @h, @c5, 4];
s16b = [@c5, @h, @c5:2];
S2 = s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10 + s11 + s12 + s13 + s14 + s15;
#
a1 = [@g, 4, @f5, 4];
a2 = [@f, 4, @e5, 4];
a3 = flat(2 ^ [@c, @c5, @h, @c5], 2 ^ [@e, @e5, @d5, @e5]) as n ^ n.withDuration(16);
a4 = flat(2 ^ [@c, @c5, @h, @c5], 2 ^ [@e, @e5, @d5, @e5]) as n ^ n.withDuration(16);
a5 = [@a, @c5, @g#, @c5, @a, @c5, @f#, @d5, @g, @d5, @f#, @d5, @g, @d5, @e, @e5] as n ^ n.withDuration(16);
a6 = [@f:16, @c5:16, @e:16, @c5:16, @f:16, @c5:16, @d:16, @h:16, @h, 8, @a5:8];
a7 = [@f5, @e, @e, 4];
a8 = (4 ^ @e5:8) + [@e5, 4];
a9 = (4 ^ @d5:8) + [@c5, 4];
a10 = [16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @h:16, @c5:16, @c5, 8, @c5:8];
a11 = (4 ^ @c5:8) + [@d, 8, @d:8];
a12 = (4 ^ @d5:8) + [@e, 8, @e:8];
a13 = (4 ^ @e5:8) + [@g5, 8, @g5:8];
a14 = [@c, @e, @c, @e, @c, @f, @c, @f, @h3, @d, @h3, @d, @h3, @e, @h3, @e] as n ^ n.withDuration(16).withOctave(5);
a15 = [@a:16, @c5:16, @a:16, @c5:16, @a:16, @d5:16, @a:16, @d5:16, @g:2];
a16a = [@g:2, @c, 4];
a16b = [@g:2, @g:2];
A2 = transpose(-12, a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8 + a9 + a10 + a11 + a12 + a13 + a14 + a15);
#
t1 = [@e, 4, 16, @f:16, @e:16, @f:16, @c:16, @f:16, @e:16, @f:16];
t2 = [@d, 4, 16, @e:16, @d:16, @e:16, @h3:16, @e:16, @d:16, @e:16];
t3 = [1];
t4 = [1];
t5 = [1];
t6 = [2, @e, 8, @e5:8];
t7 = [2, 16, @a:16, @g#:16, @a:16, @e:16, @a:16, @g#:16, @a:16];
t8 = (4 ^ @h:8) + [16, @h:16, @g#:16, @a:16, @e:16, @a:16, @g#:16, @a:16];
t9 = (4 ^ @h:8) + [@g, 4];
t10 = [2, @g, 8, @g:8];
t11 = (4 ^ @a:8) + [@a, 8, @a:8];
t12 = (4 ^ @h:8) + [@h, 8, @h:8];
t13 = (4 ^ @c5:8) + [@d5, 8, @d5:8];
t14 = [1];
t15 = [2, @d5, 16, @e5:16, @d5:16, @c5:16];
t16a = [@g5:4d, @f:8, @g ,4];
t16b = [@g5:4d, @f:8, @e:2];
T2 = transpose(-12, t1 + t2 + t3 + t4 + t5 + t6 + t7 + t8 + t9 + t10 + t11 + t12 + t13 + t14 + t15);
#
b_1 = 6 ^ 1;
b7 = [@d5:8, @c5:8, @h, @c5, 4];
b_2 = 8 ^ 1;
b16a = [@d:2, @e, 4];
b16b = [@d:2, @e:2];
B2 = transpose(-12, b_1 + b7 + b_2);
#
p1 = [@c, 4, @f, 4];
p2 = [@h3, 4, @e, 4];
p3 = [@c, 4, @h3, 4];
p4 = [@c, 4, @e, 4];
p5 = [@a, 4, 2];
p6 = [2, 4, 8, @a:8];
p7 = [@d, @e, @a3, 4];
p8 = (4 ^ @g#3:8) + [@a3, 4];
p9 = (4 ^ @h3:8) + [@c, 4];
p10 = [2, @c, 8, @e:8];
p11 = (4 ^ @f:8) + [@f#, 8, @f#:8];
p12 = (4 ^ @g:8) + [@g#, 8, @g#:8];
p13 = (4 ^ @a:8) + [@h, 8, @h:8];
p14 = [@c5, @a, @h, @g];
p15 = [@a, @f, @g:2];
p16a = [@g:2, 16, @c5:16, @h:16, @c5:16, @g:16, @c5:16, @e:16, @g:16];
p16b = [@g:2, @c:2];
P2 = transpose(-12, p1 + p2 + p3 + p4 + p5 + p6 + p7 + p8 + p9 + p10 + p11 + p12 + p13 + p14 + p15);
PART2 = wave(config, S2, A2, T2, B2, P2);
PART2a = PART2 + wave(config, s16a, a16a, t16a, b16a, p16a);
PART2b = PART2 + wave(config, s16b, a16b, t16b, b16b, p16b);
MUSIC = PART1 + PART1 + PART2a + PART2b;
synth(MUSIC);

42
examples/bohemian.mus Normal file
View File

@@ -0,0 +1,42 @@
println("Bohemian Rhapsody :: part");
println("by Queen");
m1 = [@d:8, @d:8, @d:2, 8, @b3:8, @c:8, @d:16, @d:16, @d, 4, 8, @d:16, @d:16];
m2 = [@eb:8, @f:8, @eb:8, @d:8, @c, @c:8, @d:8, @eb:16, @f:8, @eb:8d, @d:8, @c, 4, @d:8, @d:8, @d:2, @d:8, @f:8];
m3 = [@a:8d, @g:16, @g:2, 8, @g:8, @b:8, @b:8, @b:8, @b:8, @b:8d, @g:16, @d:8d, @c:16, @c:2, 2];
M1 = [1, 1] + m1 + m2 + m3;
p_B = [@d:8, @f3:8, @b3:8, @d:8, @g:8, @f3:8, @f:8, @f:8];
p_g = [@d:8, @g3:8, @b3:8, @d:8, @a:8, @g3:8, @g:8, @b3:8];
p_c = [@g:8, @c:8, @eb:8, @g:8, @d5:8, @c:8, @c5:8, @c:8];
p_cF = [@b:8, @c:8, @eb:8, @g:8, @a:8, @eb:8, @f:8, @c:8];
p1 = [@eb:8, @c:8, @eb:8, @g:8, @eb:8, @g:8, @eb:8, @g:8, @eb:8, @a3:8, @eb:8, @g:8, @eb:8, @g:8, @eb:8, @g:8];
P1 = p_B + p_B + p_B + p_g + p_c + p_cF + p_B + p_g + p1;
b1 = [@b3:1, @g3:1, @c3:1, @c3:2, @f3:2];
b2 = [@b3:2d, @a3, @g3:1, @c3:2, @h2, @b2, @a2:2, @ab2, @g2];
B1 = [@b3:1, @b3:1] + b1 + b2;
# Eb
m1 = [@g:16, @g:16, @g:2, 8, @f:8, @g:16, @ab:16, @g:2, 4, 8, @g:16, @g:16, @ab:8d, @g:16, @g:8, @f:16, @f:2, @b3:16];
m2 = [@b3:8, @f:8, @f:8, @g:16, @g:8d, @ab:8, @ab:8, @b:16, @ab:16, @ab:8, @g:8, 8, @f:16, @g:16, @b:4d, @f:16, @g:16];
m3 = [@eb:4d, @b3:16, @b3:16, @h3:8, @db:8, @h3:16, @db:16, @h3:8, @b3:2, 2];
M2 = m1 + m2 + m3;
p_Eb = [@b:8, @eb:8, @eb5:8, @eb:8, @b:8, @eb:8, @f:8, @b:8];
p_f = [@ab:8, @f:8, @ab:8, @ab:8, @ab:8, @eb:8, @ab:8, @d:8];
p_B = [@d, @f, @g, @ab];
p_EbB = [@b:8, @eb:8, @eb5:8, @eb:8, @b:8, @d:8, @b:8, @d:8];
p_cf = [@g:8, @c:8, @g:8, @c:8, @h3:2];
P2 = p_Eb + p_c + p_f + p_B + p_EbB + p_cf;
b1 = [@eb3:2d, @d3, @c3:1, @f3:4d, @e3:8, @eb3, @d3, @b2, @b2, @b2, @b2, @eb3:2, @d3:2];
b2 = [@c2:2, @f2:2, @eb2:2, 2];
B2 = b1 + b2;
M = M1 + M2;
P = P1 + P2;
B = B1 + B2;
synth({ tuning -> 432, bpm -> 72, overtones -> [0.5, 0.3, 0.15, 0.05], decay -> 0.8 }, transpose(12, M), P, B);

45
examples/bubble_sort.mus Normal file
View File

@@ -0,0 +1,45 @@
extend list as array {
function withoutIndex(integer index) {
return array as (i, element) ^ element % i != index;
}
function push(integer index, value) {
return (index as i ^ array.get(i)) + [value] + ((array.size-index) as i ^ array.get(i+index));
}
function replace(integer index, value) {
return array
.withoutIndex(index)
.push(index, value);
}
function swap(integer a, integer b) {
A = array.get(a);
B = array.get(b);
return array
.replace(a, B)
.replace(b, A);
}
}
function bubbleSort(list<integer, float> numbers) {
sorted = numbers;
-(numbers.size as n ^ n) as i ^ {
i as j ^ {
if (sorted.get(j) > sorted.get(j+1)) {
sorted = sorted.swap(j, j+1);
}
}
}
return sorted;
}
min = 0;
max = 100;
size = 30;
randList = size ^ rand(min, max);
println(randList);
println(bubbleSort(randList));

120
examples/cantina.mus Normal file
View File

@@ -0,0 +1,120 @@
println("Star Wars :: Cantina Band");
println("by John Williams");
cb1 = [@a, @d5, @a, @d5] + [@a:8, @d5, @a:8, 8, @g#:8, @a];
cb2 = [@a:8, @g#:8, @a:8, @g:8, 8, @f#:8, @g:8, @gb:8];
cb3 = [@f:4d, @d:2, 8];
cb4 = [@g:8, 8, @g:4d, @f#:8, @g];
cb5 = [@c5:8, @b, @a, @g:4d];
cb6 = [@c5:8, 8, @c5:4d, @a:8, @g];
cb7 = [@f:4d, @d:2, 8];
cb8 = [@d:2, @f:2, @a:2, @c5:2];
cb9 = [@eb5, @d5, @g#:8, @a, @f:8];
CB1 = cb1 + cb2 + cb3 + cb1 + cb4 + cb5 + cb1 + cb6 + cb7 + cb8 + cb9 + [1];
cb11 = 2 ^ [8, @a5, @f5:8, @a5:8, 8, 4];
cb12 = [8, @a5, @f5:8, @g#5:8, @a5, @f5:8];
cb13 = [@f5:4d, @d5:2, 8];
cb14 = [8, @a5, @f5:8, @g#5:8, @a5, @g5:8];
cb15 = [@g5:2, @c5:2];
cb16 = [@b:8, @d5:8, @f5, @h:8, @d5:8, @f5];
cb17 = [@g#:8, @a5, @d5:2, 8];
cb18 = [@d:8, @f:8, @h:8, @d5:8, @g#:8, @a, @f:8];
cb19 = [@f:2d, 4];
CB2 = cb11 + cb12 + cb13 + cb11 + cb14 + cb15 + cb11 + cb12 + cb13 + cb16 + cb17 + cb18 + cb19;
cb20 = [@f, 8, @ab, @f:8, @g];
cb21 = [8, @f:8, @ab:8, @f:8, @g:8, @f:8, @ab:8, @d:8];
cb22 = [@f, 8, @ab, @f:8, @g];
cb23 = [@f:8, @f:8, @ab:8, @f:8, @g:8, @f:8, @ab:8, @f:8];
cb24 = [@g:8, @f:8, @ab:8, @f:8, @g:8, @f:8, @ab:8, @d:8];
cb25 = [@f:8, @f:8, @ab:8, @f:8, @ab:8, @f, @f:8, @f:2d, 4];
CB3 = cb20 + cb21 + cb22 + cb21 + cb22 + cb21 + cb23 + cb24 + cb22 + cb21 + cb22 + cb21 + cb22 + cb21 + cb25;
cb26 = [@c5, 8, @e5:8, 4, @g5];
cb27 = [@g5:8, @g5, @g5:8, @g5, @e5:8, @c5:8];
cb28 = [@f5, @f5:8, @f5:8, @f5:8, @g5, @a5:8, @a5:1];
cb29 = [@e5, @e5, @g5:8, @g5, @c5:8];
cb30 = [@c5:8, @e5, @c5:8, @e5, @g5];
cb31 = [@f5, @f5:8, @f5, @g5, @a5:8, @a5:1];
cb32 = [@b5, @b5, @d6, @b5:8, @db6:8];
cb33 = [@db6:8, @db6:8, @b5, @db6, @b5];
cb34 = [@f5, @f5, @f5:8, @ab5, @d6:8, @d6:1];
cb35 = [8, @b, @d5:8, @g5, @g5];
cb36 = [8, @e5, 8, @e5, @e5];
cb37 = [8, @f5, @f5:8, @f5, @f5:8, @f5:8];
cb38 = [@f5:8, @f5, @f5:8, @f5:8, @f5:8, @f5];
CB4 = cb26 + cb27 + cb28 + cb29 + cb30 + cb31 + cb32 + cb33 + cb34 + cb35 + cb36 + cb37 + cb38;
cb39 = [@ab:8, @gb:8, @ab:8, @gb:8, @ab:8, @gb:8, @ab:8, @gb:8];
cb40 = [@ab:8, @db5, @ab:8, @db5, @ab:8, @db5:8];
cb41 = [8, @ab:8, @b:8, @h:8, @c5:8, @h:8, @b:8, 8];
cb42 = [@ab:8, @db5, @ab:8, @db5, @ab:8, @a:8];
cb43 = [@b:8, @a:8, @b:4d, @a:8, @b:8, @a:8];
cb44 = [@b:8, @a:8, @b:8, @h:8, @c5:8, 8, @gb:8, @g:8];
cb45 = [@b:8, @a:8, @b:4d, @a:8, @b:8, @h:8];
cb46 = [@c5:8, @g:8, @e:8, @c:8, 8, @c:8, @db:8, @c:8];
cb47 = [@db:8, @b3, @db:8, @fb:8, @db, @fb:8];
cb48 = [@f:8, @e:8, @f:8, @gb:8, @g:8, @c, @g:8];
cb49 = [@ab:8, @g:8, @ab:8, @a:8, @b:8, @a:8, @b:8, @h:8];
cb50 = [@c5:8, @c5:8, 4, @c5:8, @c5:8, 4];
cb51 = [@c5, @e5:2, @f5:8, @db5:8];
cb52 = [@ab:8, @f:8, @fb:8, @eb:8, @d:8, 4, @gb:8];
cb53 = [@c5:8, @c5, @gb:8, @c5:8, @c5, @h:8];
cb54 = [@c5:8, @c5, @h:8, @c5:8, @c5, @c5:8];
cb55 = [@db5:8, @fb:8, @db5:4d, @fb:8, @db5:8, @fb:8];
cb56 = [@db5:8, @fb:8, @db5:8, @fb:8, @eb:8, @c5, @c5:8];
cb57 = [@db5:8, @fb:8, @db5:8, @fb:8, @eb:8, @c5, @h3:8];
cb58 = [@b3:8, @db:8, @gb:8, @b:8, @c:8, @e:8, @g:8, @c5:8];
cb59 = [@db5:8, @db, @c:8, @db, 4];
cb60 = [4, @a3, @b3, @a3, @b3, @a3, @gb3:8, @f3:8, @d3:8, 8];
cb61 = [8, @a3, @a3, @a3, @a3, @a3, @a3:8, @a3:8, @a3];
CB5 = cb39 + cb40 + cb41 + cb39 + cb42 + cb43 + cb44 + cb39 + cb42 + cb45 + cb46 + cb47 + cb48 + cb49 + cb50 + cb50 + cb51 + cb52 + cb53 + cb54 + cb55 + cb56 + cb55 + cb56 + cb55 + cb57 + cb58 + cb59 + cb60 + cb60 + cb60;
CB = CB1 + CB2 + CB3 + (2 ^ CB4) + CB5;
b1 = (3 ^ [@d3, 4, @a2, 4]) + [@f3, 4, @c3, 4, @d3, 4, @a2, 4, @d3, 4, @a2, 4, @g2, 4, @g2, 4];
b2 = [@c3, @d3, @d#3, @e3, @d3, 4, @a2, 4, @d3, 4, @a2, 4, @c3, 4, @c3, 4];
b3 = [@f3, 4, @c3, 4, @b2, 4, @b2, 4, @f3, 4, @d3, 4, @g3, 4, @c3, 4, @f3, @e3, @d3, @c3];
B1 = b1 + b2 + b3;
b4 = (3 ^ [@d3, 4, @a2, 4]) + [@d3:4d, @g#2:4d, @a2];
b5 = (3 ^ [@d3, 4, @a2, 4]) + [@eb3:2, @c3, @c3];
b6 = (4 ^ [@d3, 4, @a2, 4]);
b7 = [@b2:8, @b2:8, 4, @h2:8, @h2:8, 4, @c3:4d, @d3:8, 8, @d3:8, @d3, @g2, 4, @c3:4d, @f3:4d, @e3, @d3, @c3];
B2 = b4 + b5 + b6 + b7;
b8 = 3 ^ [@d3, @c3, @b2, @a2, @g2, @f2, @e2, @d2];
b9 = [@d3, 4, 2, 2, 4, @a2];
b10 = [@d3, @b2, @a2, @a2, @d3:8, 8, 4, 2];
B3 = b8 + b9 + b8 + b10;
b11 = [@c3, 4, @g2, 4, @c3, 8, @b2:4d, @g2, @f2, 4, @c3, 4, @f3, 8, @e3:4d, @d3];
b12 = [@c3, 4, @g3, 4, @c3, 8, @b2:4d, @g2, @f2, 4, @c3, 4, @d3, 8, @f#2:4d, @a2];
b13 = [@b2, 4, @b2, 4, @h2, 4, @h2, 4, @c3, 4, @c3, 4, @d3, 8, @d3:4d, @f#2];
b14 = [@g2, 4, @d3, 4, @c3, 8, @c3:4d, @g3, @f3, 4, @db3, 4, @f3, @f3, @e3, @d3];
B4 = b11 + b12 + b13 + b14;
b15 = [@db3, @c3, @b2, @ab2, @gb2, @f2, @eb2, @db2, @db3, @b2, @a2, @ab2];
b16 = [@db3, @c3, @b2, @ab2, @gb2, @f2, @eb2, @db2, @eb2, @e2, @f2, @gb2];
b17 = [@e2, @d2, @h2, @ab2, @h2, @ab2, @f2, @eb2, @db2, @c2, @b1, @ab1];
# ^ or B?
b18 = [@gb2, @gb2, @gb2, @db3, @c3, @c3, @e3, @g3, @gb3, @gb3, @g3, @g3];
b19 = [@ab3, @db3, @c3, @c3, @f3, @c3, @gb3, @gb3, @c3, 4, @c3, 4];
b20 = [@f3, 4, @f3, 4, @c3, @c3, 4, @db3:8, @f3:8, @ab3:8, @a3:8, @b3:8, @h3:8, @c:8, 8, 8, 16, @g3:16];
b21 = [@c3, 4, @c3, 4, @f3, 4, @f3, 4, @gb2, 4, @ab2, 4, @a2, 4, @db3, 4, @gb2, 4, @ab2, 4, @a2, 4, @db3, 4, @d, 4, @eb, 4];
b22 = [@e3, 4, @f3, 4, @gb3, 4, @g3, 4, @db3, 4, @db3, 4];
B5 = b15 + b16 + b17 + b18 + b19 + b20 + b21 + b22;
B = B1 + B2 + B3 + (2 ^ B4) + B5;
synth({ tuning -> 432, bpm -> 270 }, flat(CB), flat(B));

31
examples/les_anges.mus Normal file
View File

@@ -0,0 +1,31 @@
println("Les Anges dans nos campagnes");
s = [@a, @a, @a, @c5, @c5:4d, @b:8, @a:2, @a, @g, @a, @c5, @a:4d, @g:8, @f:2];
sc = [@c5:2, @d5:8, @c5:8, @b:8, @a:8, @b:2, @c5:8, @b:8, @a:8, @g:8, @a:2, @b:8, @a:8, @g:8, @f:8, @g:4d, @c:8, @c:2, @f, @g, @a, @b];
sca = [@a:2, @g, 4];
scb = [@a:2, @g:2, @f:2d, 4];
S = flat(2^s, sc, sca, sc, scb);
a = [@f, @f, @e, @e, @g, @e, @f:2, @f, @e, @f, @f, @f, @e, @f:2];
ac = [@f, @a:8, @g:8, @f:2d, @g:8, @f:8, @e:2d, @f:8, @e:8, @d:2, @c:4d, @c:8, @c:2, @c, @e, @f, @g];
aca = [@f:2, @e, 4];
acb = [@f:2, @e:2, @c:2d, 4];
A = flat(2^a, ac, aca, ac, acb);
t = [@c, @c, @c, @c, @d, @c, @c:2, @c, @c, @c, @c, @c:4d, @b3:8, @a3:2];
tc = [@a3:2, @d:1, @c:1, @b3:2, @g3, @f3, @e3:2, @f3, @c, @c, @d];
tca = [@c:2, @c, 4];
tcb = [@c:2d, @b3, @a3:2d, 4];
T = flat(2^t, tc, tca, tc, tcb);
b = [@f3, @f3, @a3, @a3, @g3, @c3, @f3:2, @f3, @c3, @f3, @a3, @c, @c3, @f3:2];
bc = [@f3:2, @d3, @f3, @g3:2, @c3, @e3, @f3:2, @b2, @d3, @e3, @d3, @c3, @b2, @a2, @c3, @f3, @b2];
bca = [@c3:2, @c3, 4];
bcb = [@c3:1, @f3:2d, 4];
B = flat(2^b, bc, bca, bc, bcb);
synth({ tuning -> 432, overtones -> [0.6, 0.3, 0.07, 0.03], attack -> 200, decay -> 0.6 }, S, A, T, B);

18
examples/per_crucem.mus Normal file
View File

@@ -0,0 +1,18 @@
println("Per Crucem - canon");
d1 = [@d:2, @d:2, @c:2, @f:4d, @f:8, @f, @f, @e, @d, @e:2, @d:2];
d2 = [@d:8, @f:8, @a:8, @d5:8, @b:8, @a:8, @g, @c:8, @e:8, @g:8, @c5:8, @a:8, @g:8, @f, @b3:8, @d:8, @f:8, @b:8, @g:8, @f:8, @e, @a, @e, @f:2];
d3 = [@a:2, @b:2, @c5:2, @a:4d, @a:8, @b, @f, @g, @g, @a, @e, @f:2];
d4 = [@d5:8, @c5:8, @b:8, @a:8, @g:8, @a:8, @b, @c5:8, @b:8, @a:8, @g:8, @f:8, @g:8, @a, @b:8, @a:8, @g:8, @f:8, @e:8, @f:8, @g, @a, @e, @f:2];
d5 = [@d5:2, @d5:2, @c5:2, @c5:2, @d5:8, @c5:8, @b:8, @a:8, @b, @b, @a:2, @a:2];
d6 = [@d:8, @d:8, @d:8, @d:8, @g:8, @g:8, @g, @c:8, @c:8, @c:8, @c:8, @f:8, @f:8, @f, @b3:8, @b3:8, @b3:8, @b3:8, @e:8, @e:8, @e, @a3, @a3, @d:2];
p = [1, 1, 1, 1];
S = d1 + d2 + d3 + d4 + d5 + d6 + d1 + d2 + d3;
A = p + d1 + d2 + d3 + d4 + d5 + d6 + d1 + d2;
T = p + p + d1 + d2 + d3 + d4 + d5 + d6 + d1;
B = p + p + p + d1 + d2 + d3 + d4 + d5 + d6;
wv = wave(S, A, transpose(-12, T), transpose(-12, B));
synth(wv);

View File

@@ -0,0 +1,31 @@
println("Narodził się nam Zbawiciel / Quem pastores laudavere");
println("mel.: XIV w.");
println("sł.: XV - XVI w.");
println("harm.: Bartłomiej Pluta");
s1 = [@f:2, @a, @c5:2, @a, @c5:2, @d5, @c5, @g:2];
s2 = [@a:2, @c5, @b:2, @g, @f:2, @d, @e, @c:2];
s3 = [@a:2, @b, @c5:2, @d5, @c5:2, @g, @a, @f:2];
s4 = [@b:2, @b, @a, @g, @a, @f, @d, @e, @f:2d];
a1 = [@c:2, @f, @g:2, @f, @f, @g, @f, @f, @f, @e];
a2 = [@f, @e, @eb, @d:2, @c, @d:2, @d, @c, @c, @b3];
a3 = [@c:2, @c, @f, @d, @g, @g:2, @e, @e, @d:2];
a4 = [@f:2, @f, @f, @e, @f, @c:2, @c, @c:2d];
t1 = [@a, @b, @c5, @c5, @b, @c5, @a:2, @b, @a, @c5:2];
t2 = [@c5:2, @a, @b:2, @c5, @d5, @c, @b, @g, @g:2];
t3 = [@f, @a, @g, @a:2, @b, @b:2, @g, @g, @a:2];
t4 = [@d5, @db5, @db5, @c5, @b, @a, @g:2, @b, @a:2d];
b1 = [@f:2, @f, @e:2, @f, @f:2, @f, @c, @c:2];
b2 = [@f:2, @f#, @g, @f, @e, @d, @f, @g, @c, @e:2];
b3 = [@f:2, @e, @f, @f#, @g, @e, @d, @c, @c#, @d, @c];
b4 = [@b3:2, @b, @c:2, @c, @c:2, @c, @f:2d];
S = s1 + s2 + s3 + s4;
A = a1 + a2 + a3 + a4;
T = transpose(-12, t1 + t2 + t3 + t4);
B = transpose(-12, b1 + b2 + b3 + b4);
synth({ overtones -> [0.6, 0.25, 0.1] + (2 ^ 0.0) + [0.05], attack -> 50, decay -> 1 }, S, A, T, B);

BIN
img/notes/cd4fga8c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
img/notes/cdef.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

BIN
img/notes/poly1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
img/notes/poly2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

BIN
img/notes/starwars.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
img/notes/twinkle1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
img/notes/twinkle2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

BIN
img/notes/twinkle3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
img/plots/a_127.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
img/plots/a_1overtone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
img/plots/a_2overtones.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

BIN
img/plots/a_3overtones.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
img/plots/a_440.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
img/plots/attack0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
img/plots/attack1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

BIN
img/plots/attack10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
img/plots/attack100.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
img/plots/attack5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

BIN
img/plots/c.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
img/plots/decay0.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
img/plots/decay05.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

BIN
img/plots/decay1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
img/plots/decay10.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
img/plots/decay5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

BIN
img/plots/default.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

BIN
img/plots/spectrum.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
img/schemas/wait_fsm.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

36
setup.py Normal file
View File

@@ -0,0 +1,36 @@
import os
from setuptools import setup, find_packages
def file(file):
return open(os.path.join(os.path.dirname(__file__), file)).read()
setup(
name='SMNP',
version=file('smnp/meta/__version__.txt'),
packages=find_packages(),
description=file('smnp/meta/__description__.txt'),
author='Bartlomiej P. Pluta',
url='https://gitlab.com/bartlomiej.pluta/smnp',
install_requires=[
"cffi>=1.12.3",
"cycler>=0.10.0",
"kiwisolver>=1.1.0",
"matplotlib>=3.1.1",
"numpy>=1.17.2",
"pycparser>=2.19",
"pyparsing>=2.4.2",
"python-dateutil>=2.8.0",
"six>=1.12.0",
"sounddevice>=0.3.13",
"soundfile>=0.10.2"
],
entry_points={
'console_scripts': ['smnp=smnp.main:main']
},
package_data={
'smnp.library.code': ['main.mus'],
'smnp.meta': ['__version__.txt', '__description__.txt']
}
)

View File

@@ -113,11 +113,11 @@ def LoopParser(input):
return Parser.allOf( return Parser.allOf(
ExpressionWithoutLoopParser, ExpressionWithoutLoopParser,
Parser.optional(loopParameters), Parser.optional(loopParameters),
Parser.terminal(TokenType.DASH, createNode=Operator.withValue), Parser.terminal(TokenType.CARET, createNode=Operator.withValue),
StatementParser, StatementParser,
Parser.optional(loopFilter), Parser.optional(loopFilter),
createNode=Loop.loop, createNode=Loop.loop,
name="dash-loop" name="caret-loop"
)(input) )(input)

View File

@@ -1,66 +0,0 @@
from smnp.ast.node.model import Node
from smnp.ast.parser import Parser
from smnp.token.tokenizer import tokenize
from smnp.token.type import TokenType
class Atom(Node):
def __init__(self, value, pos):
super().__init__(pos)
self.children = [value]
@property
def value(self):
return self[0]
class Operation(Node):
def __init__(self, left, op, right, pos):
super().__init__(pos)
self.children = [left, op, right]
@property
def left(self):
return self[0]
@property
def operator(self):
return self[1]
@property
def right(self):
return self[2]
def atom():
return Parser.oneOfTerminals(TokenType.INTEGER, TokenType.NOTE, TokenType.STRING, createNode=lambda val, pos: Atom(val, pos))
def chain():
return Parser.leftAssociativeOperatorParser(atom(), [TokenType.DOT], atom(), lambda left, op, right: Operation(left, op, right, op.pos), name="chain")
def factor():
return Parser.leftAssociativeOperatorParser(chain(), [TokenType.DOUBLE_ASTERISK], chain(), lambda left, op, right: Operation(left, op, right, op.pos), name="factor")
def term():
return Parser.leftAssociativeOperatorParser(factor(), [TokenType.ASTERISK, TokenType.SLASH], factor(), lambda left, op, right: Operation(left, op, right, op.pos), name="term")
def expr():
return Parser.leftAssociativeOperatorParser(term(), [TokenType.PLUS, TokenType.MINUS], term(), lambda left, op, right: Operation(left, op, right, op.pos), name="expr")
#
def evaluate(node):
if type(node) == Atom:
return node.value
lhs = evaluate(node.left)
rhs = evaluate(node.right)
return {
"+": int(lhs) + int(rhs),
"*": int(lhs) * int(rhs),
"-": int(lhs) - int(rhs),
"/": int(lhs) / int(rhs),
"**": int(lhs) ** int(rhs)
}[node.operator.value]
def draft():
tokens = tokenize(['"fesf fe" + "fsefsef" + "fsefs"'])
e = expr()
node = e(tokens).node
node.print()

View File

@@ -1,13 +1,16 @@
import argparse import argparse
VERSION = "0.1" from pkg_resources import resource_string
DESCRIPTION = """
Simple Music Notation Processor is a command line tool enabling you to do some music stuff using custom domain-specific language.
""" def file(file):
return resource_string('smnp.meta', file).decode("utf-8")
class CliParser(object): class CliParser(object):
def __init__(self): def __init__(self):
self.parser = argparse.ArgumentParser(description=DESCRIPTION) self.parser = argparse.ArgumentParser(description=file("__description__.txt"))
self.parser.add_argument('file', nargs='*', help='a file containing SMNP code') self.parser.add_argument('file', nargs='*', help='a file containing SMNP code')
self.parser.add_argument('-c', '--code', action='append', default=[], type=str, help='a string with SMNP code') self.parser.add_argument('-c', '--code', action='append', default=[], type=str, help='a string with SMNP code')
self.parser.add_argument('-m', '--mic', action='store_true', help='test microphone level') self.parser.add_argument('-m', '--mic', action='store_true', help='test microphone level')
@@ -17,7 +20,7 @@ class CliParser(object):
self.parser.add_argument('--tokens', action='store_true', help='print tokens of parsed code') self.parser.add_argument('--tokens', action='store_true', help='print tokens of parsed code')
self.parser.add_argument('--ast', action='store_true', help='print abstract syntax tree of parsed code') self.parser.add_argument('--ast', action='store_true', help='print abstract syntax tree of parsed code')
self.parser.add_argument('--dry-run', action='store_true', help='don\'t execute passed code') self.parser.add_argument('--dry-run', action='store_true', help='don\'t execute passed code')
self.parser.version = VERSION self.parser.version = file("__version__.txt")
def parse(self): def parse(self):
return self.parser.parse_args() return self.parser.parse_args()

492
smnp/library/code/main.mus Normal file
View File

@@ -0,0 +1,492 @@
function flat(list lists...) {
return _flat(lists as l ^ _flat(l, []), []);
}
function _flat(list l, list output) {
l as elem ^ {
if (typeOf(elem) == list) {
output = _flat(elem, output);
} else {
output = output + [elem];
}
}
return output;
}
extend note as n {
function withOctave(integer octave) {
return Note(n.pitch, octave, n.duration, n.dot);
}
function withDuration(integer duration) {
return Note(n.pitch, n.octave, duration, n.dot);
}
function withDot(bool dot) {
return Note(n.pitch, n.octave, n.duration, dot);
}
function toIntRepr() {
return n.octave * 12 + _pitchToNumber(n.pitch);
}
function transpose(integer value) {
return noteFromIntRepr(n.toIntRepr() + value, n.duration, n.dot);
}
}
function noteFromIntRepr(integer intRepr, integer duration, bool dot) {
pitch = _numberToPitch(mod(intRepr, 12));
octave = Integer(intRepr / 12);
return Note(pitch, octave, duration, dot);
}
function mod(integer a, integer b) {
return a - b * Integer(a/b);
}
function _pitchToNumber(string pitch) {
return _keysToIntMapper(
"C",
"CIS",
"D",
"DIS",
"E",
"F",
"FIS",
"G",
"GIS",
"A",
"AIS",
"H"
).get(pitch);
}
function _keysToIntMapper(keys...) {
return Map(keys as (i, key) ^ [key, i]);
}
function _numberToPitch(integer number) {
return ["C", "CIS", "D", "DIS", "E", "F", "FIS", "G", "GIS", "A", "AIS", "H"].get(number);
}
function transpose(integer value, <note, integer, list<note, integer>> notes...) {
if (notes.size == 1) {
first = notes.get(0);
if (typeOf(first) == integer) {
return first;
} else if (typeOf(first) == note) {
return first.transpose(value);
} else if (typeOf(first) == list) {
return _transpose(value, first);
}
}
noteOrInteger = false;
lists = false;
notes as n ^ {
if (typeOf(n) == note or typeOf(n) == integer) {
noteOrInteger = true;
if (lists) {
throw "Mixing notes and integers with lists of them is not supported";
}
} else if (typeOf(n) == list) {
lists = true;
if (noteOrInteger) {
throw "Mixing notes and integers with lists of them is not supported";
}
}
}
output = [];
notes as n ^ {
if (typeOf(n) == integer) {
output = output + [n];
} else if (typeOf(n) == note) {
output = output + [n.transpose(value)];
} else if (typeOf(n) == list) {
output = output + [_transpose(value, n)];
}
}
return output;
}
function _transpose(integer value, list<note, integer> notes) {
output = [];
notes as n ^ {
if (typeOf(n) == integer) {
output = output + [n];
} else if (typeOf(n) == note) {
output = output + [n.transpose(value)];
}
}
return output;
}
function transposeTo(note target, <note, integer, list<note, integer>> notes...) {
if (notes.size == 1) {
first = notes.get(0);
if (typeOf(first) == integer) {
return first;
} else if (typeOf(first) == note) {
return _transposeTo(target, notes).get(0);
} else if (typeOf(first) == list) {
return _transposeTo(target, first);
}
}
noteOrInteger = false;
lists = false;
notes as n ^ {
if (typeOf(n) == note or typeOf(n) == integer) {
noteOrInteger = true;
if (lists) {
throw "Mixing notes and integers with lists of them is not supported";
}
} else if (typeOf(n) == list) {
lists = true;
if (noteOrInteger) {
throw "Mixing notes and integers with lists of them is not supported";
}
}
}
if (noteOrInteger) {
return _transposeTo(target, notes);
}
if (lists) {
return notes as n ^ _transposeTo(target, n);
}
}
function _transposeTo(note target, list<note, integer> notes) {
if (notes.size == 0) {
throw "Provide list with one note at least";
}
firstNote = notes.get(0);
semitones = semitones(firstNote, target);
return transpose(semitones, notes);
}
function tuplet(integer n, integer m, note notes...) {
if (n != notes.size) {
throw "Expected " + n.toString() + " notes exactly, whereas " + notes.size.toString() + " was passed";
}
return notes as x ^ x.withDuration(x.duration * n / m);
}
extend list as l with function contains(expectedValue) {
return (l as value ^ value % value == expectedValue).size > 0;
}
extend map as m {
function containsKey(expectedKey) {
return m.keys.contains(expectedKey);
}
function containsValue(expectedValue) {
return m.values.contains(expectedValue);
}
function contains(key, value) {
if (m.keys.contains(key)) {
return m.get(key) == value;
}
return false;
}
}
function sample(items...) {
if (items.size == 0) {
throw "Provide one item at least";
}
if (items.size == 1 and typeOf(items) == list) {
return items.get(0).get(rand(0, items.get(0).size-1));
}
return items.get(rand(0, items.size-1));
}
extend string as s with function join(list<string> l) {
output = "";
l as (index, item) ^ {
output = output + item;
if (index < l.size - 1) {
output = output + s;
}
}
return output;
}
function random(map<string><> items...) {
accumulator = 0;
items as (index, item) ^ {
if (item.size != 2) {
throw "Expected lists with two items: percent and value";
}
if (not item.containsKey("percent")) {
throw "Item " + (index+1).toString() + " does not have 'percent' key";
}
if (not item.containsKey("value")) {
throw "Item " + (index+1).toString() + " does not have 'value' key";
}
accumulator = accumulator + item.get("percent");
}
if (accumulator != 100) {
throw "Sum of first element of each item must be equal to 100";
}
accumulator = 0;
random = rand(0, 99);
items as item ^ {
accumulator = accumulator + item.get("percent");
if (random < accumulator) {
return item.get("value");
}
}
}
function semitones(<note, integer, list<note, integer>> notes...) {
noteOrInteger = false;
lists = false;
notes as n ^ {
if (typeOf(n) == note or typeOf(n) == integer) {
noteOrInteger = true;
if (lists) {
throw "Mixing notes and integers with lists of them is not supported";
}
} else if (typeOf(n) == list) {
lists = true;
if (noteOrInteger) {
throw "Mixing notes and integers with lists of them is not supported";
}
}
}
if (noteOrInteger) {
return _semitones(notes);
}
if (lists) {
output = [];
notes as n ^ {
output = output + [_semitones(n)];
}
#if (output.size == 1) {
# return output.get(0)
#}
return output;
}
return [];
}
function _semitones(list<note, integer> notes) {
onlyNotes = notes as n ^ n % typeOf(n) == note;
if (onlyNotes.size == 2 and typeOf(onlyNotes.get(0)) == note and typeOf(onlyNotes.get(1)) == note) {
first = onlyNotes.get(0);
second = onlyNotes.get(1);
return second.toIntRepr() - first.toIntRepr();
}
if (onlyNotes.size < 2) {
throw "Provide 2 notes at least to evaluate semitones between them";
}
output = [];
range(1, onlyNotes.size-1) as i ^ {
output = output + [onlyNotes.get(i).toIntRepr() - onlyNotes.get(i-1).toIntRepr()];
}
return output;
}
function stringInterval(integer semitones) {
return [
"1",
"2m",
"2M",
"3m",
"3M",
"4",
"5d/4A",
"5",
"6m",
"6M",
"7m",
"7M"
].get(semitones);
}
function interval(<note, integer, list<note, integer>> notes...) {
noteOrInteger = false;
lists = false;
notes as n ^ {
if (typeOf(n) == note or typeOf(n) == integer) {
noteOrInteger = true;
if (lists) {
throw "Mixing notes and integers with lists of them is not supported";
}
} else if (typeOf(n) == list) {
lists = true;
if (noteOrInteger) {
throw "Mixing notes and integers with lists of them is not supported";
}
}
}
if (noteOrInteger) {
semitones = _semitones(notes);
if (typeOf(semitones) == list) {
return semitones as n ^ stringInterval(n);
} else {
return stringInterval(semitones);
}
}
if (lists) {
output = [];
notes as n ^ {
semitones = _semitones(n);
if (typeOf(semitones) == list) {
output = output + [_semitones(n) as semitone ^ stringInterval(semitone)];
} else {
output = output + [stringInterval(semitones)];
}
}
#if (output.size == 1) {
# return output.get(0);
#}
return output;
}
return [];
}
function noteRange(note a, note b, string filter = "all") {
filters = {
"all" -> [ "C", "CIS", "D", "DIS", "E", "F", "FIS", "G", "GIS", "A", "AIS", "H" ],
"diatonic" -> [ "C", "D", "E", "F", "G", "A", "H" ],
"chromatic" -> [ "CIS", "DIS", "FIS", "GIS", "AIS" ]
};
if (not filters.containsKey(filter)) {
throw "Unknown filter: '" + filter + "'";
}
notes = range(a.toIntRepr(), b.toIntRepr()) as intRepr ^ noteFromIntRepr(intRepr, a.duration, a.dot);
return notes as n ^ n % filters.get(filter).contains(n.pitch);
}
function range(<integer, float> a, <integer, float> b, <integer, float> step = 1) {
if (not (step > 0)) {
throw "Step should be greater than 0";
}
if (a > b) {
throw "Upper range value should be greater than lower or equal to";
}
output = [];
i = a;
i <= b ^ {
output = output + [i];
i = i + step;
}
return output;
}
function alert(<integer, bool> cycles = true, string melody = "beep", list<float, integer> overtones = [0.5, 0.0, 0.0, 0.5]) {
if (not [integer, bool].contains(typeOf(cycles))) {
throw "Provide 'true' or number of cycles as first argument";
}
if (typeOf(cycles) == integer) {
if (cycles < 1) {
throw "Number of cycles cannot be less than 1";
}
}
if (typeOf(cycles) == bool) {
if (not cycles) {
throw "Provide 'true' or number of cycles as first argument";
}
}
notes = {
"beep" -> [@c5:16, 32, @c5:16, 3],
"s1" -> noteRange(@c5:32, @g5:32),
"s2" -> _upDown(noteRange(@c5:32, @g5:32)),
"s3" -> [@a5:16, @d5:16],
"semitone" -> [@c5:16, @db5:16]
};
if (not notes.containsKey(melody)) {
throw "Unknown melody '" + melody + "'. Available: 'beep', 's1', 's2', 's3' and 'semitone'";
}
config = {
bpm -> 120,
decay -> 0.5,
attack -> 200,
overtones -> overtones
};
wave = wave(config, notes.get(melody));
cycles ^ synth(wave);
}
function _upDown(list l) {
return l + -l;
}
function metronome(integer bpm = 120, integer beats = 4, countMeasures = false) {
accent = wave({
overtones -> flat([0.5, 0.1, 10^0, 0.1, 10^0, 0.1, 20^0, 0.1, 25^0, 0.05, 25^0, 0.05]),
attack -> 0,
decay -> 5,
bpm -> bpm
}, @c);
beat = wave({
overtones -> flat([0.5, 10^0, 0.3, 10^0, 0.2]),
attack -> 0,
decay -> 100,
bpm -> bpm
}, @c);
measure = 1;
true ^ {
if (countMeasures) {
println(measure);
measure = measure + 1;
}
synth(accent);
beats - 1 ^ synth(beat);
}
}

View File

@@ -0,0 +1 @@
Simple Music Notation Processor is a command line tool enabling you to do some music stuff using custom domain-specific language.

0
smnp/meta/__init__.py Normal file
View File

View File

@@ -0,0 +1 @@
0.1

View File

@@ -1,4 +1,4 @@
from smnp.module.synth.function import synth, pause, plot, compile from smnp.module.synth.function import synth, pause, plot, compile, fft
functions = [ synth.function, pause.function, plot.function, compile.function ] functions = [ synth.function, pause.function, plot.function, compile.function, fft.function ]
methods = [] methods = []

View File

@@ -0,0 +1,17 @@
import numpy as np
from smnp.function.model import Function
from smnp.function.signature import signature
from smnp.type.model import Type
from smnp.type.signature.matcher.list import listOf
_signature = signature(listOf(Type.FLOAT))
def _function(env, signal):
raw = [ x.value for x in signal.value ]
N = len(raw)
fft = np.fft.fft(raw)/N
fft = fft[range(int(N/2))]
return Type.list([ Type.float(float(abs(x))) for x in fft ])
function = Function(_signature, _function, 'fft')

View File

@@ -10,4 +10,4 @@ def _function(env, wave):
plot(rawWave) plot(rawWave)
function = Function(_signature, _function, 'plotWave') function = Function(_signature, _function, 'plot')

View File

@@ -47,7 +47,7 @@ def getValueAccordingToType(value, type):
raise ValueError() raise ValueError()
raise RuntimeException(f"Type {type.value.name.lower()} is not suuported", None) raise RuntimeException(f"Type {type.value.name.lower()} is not supported", None)
except ValueError: except ValueError:
raise RuntimeException(f"Invalid value '{value}' for type {type.value.name.lower()}", None) raise RuntimeException(f"Invalid value '{value}' for type {type.value.name.lower()}", None)

View File

@@ -51,7 +51,7 @@ class ReturnEvaluator(Evaluator):
# Disclaimer # Disclaimer
# Exception system usage to control program execution flow is really bad idea. # Exception system usage to control program execution flow is really bad idea.
# However because of lack of 'goto' instruction equivalent in Python # However because of lack of 'goto' instruction equivalent in Python
# there is to need to use some mechanism to break function execution on 'return' statement # there is a need to use some mechanism to break function execution on 'return' statement
# and immediately go to Environment's method 'invokeFunction()' or 'invokeMethod()', # and immediately go to Environment's method 'invokeFunction()' or 'invokeMethod()',
# which can handle value that came with exception and return it to code being executed. # which can handle value that came with exception and return it to code being executed.
else: else:

View File

@@ -18,4 +18,4 @@ class PowerEvaluator(Evaluator):
if not right.type in supportedTypes: if not right.type in supportedTypes:
raise RuntimeException(f"Operator '{node.operator.value}' is supported only by {[t.name.lower() for t in supportedTypes]} type", node.right.pos) raise RuntimeException(f"Operator '{node.operator.value}' is supported only by {[t.name.lower() for t in supportedTypes]} type", node.right.pos)
return Type.integer(int(left.value ** right.value)) return Type.float(float(left.value ** right.value))

View File

@@ -36,7 +36,7 @@ tokenizers = (
defaultTokenizer(TokenType.SLASH), defaultTokenizer(TokenType.SLASH),
defaultTokenizer(TokenType.MINUS), defaultTokenizer(TokenType.MINUS),
defaultTokenizer(TokenType.PLUS), defaultTokenizer(TokenType.PLUS),
defaultTokenizer(TokenType.DASH), defaultTokenizer(TokenType.CARET),
defaultTokenizer(TokenType.DOTS), defaultTokenizer(TokenType.DOTS),
defaultTokenizer(TokenType.AMP), defaultTokenizer(TokenType.AMP),
defaultTokenizer(TokenType.DOT), defaultTokenizer(TokenType.DOT),

View File

@@ -21,7 +21,7 @@ class TokenType(Enum):
SLASH = '/' SLASH = '/'
MINUS = '-' MINUS = '-'
PLUS = '+' PLUS = '+'
DASH = '^' CARET = '^'
DOTS = '...' DOTS = '...'
AMP = '&' AMP = '&'
DOT = '.' DOT = '.'